core: pluggable address decoder hook + standalone-coin authorize work-resend (BCH G3b served-coinbase) - #585
Merged
Merged
Conversation
…dalone-coin payout
Two core seams behind the BCH G3b served-coinbase result; both required so a
miner CashAddr username resolves to a real payout output instead of a
value-0 OP_RETURN coinbase (which BCHN rejects as bad-txns / BIP30).
Seam (a) -- coin-registered address decoders (src/core/address_utils):
address_to_script() consults coin-registered fallback decoders AFTER its
built-in bech32/base58 formats fail. Core stays format-agnostic and holds
NO coin-specific address knowledge: a decoder is an opaque functor
string -> scriptPubKey, {} meaning "not my format, try the next". Additive
and inert until a coin calls register_address_decoder(). BCH supplies its
CashAddr decoder (src/impl/bch/coin/cashaddr.hpp, header-only); the stratum
serve-path call-site lands with the BCH M5 pool-serve work.
Seam (b) -- authorize work-resend gate (src/core/stratum_server.cpp):
the post-authorize work-resend was gated on !merged_addresses_.empty().
Standalone parent coins (BCH/BTC: no merged chains) never populate
merged_addresses_, so they kept mining the pre-authorize job whose empty
username_ produced an empty payout_script -> degenerate coinbase. Gate now
fires when the now-known username_ OR merged addrs can change the coinbase.
Single guard, single send_notify_work(true): for merged coins (LTC/DOGE)
merged_addresses_ is populated on authorize so the disjunction holds for the
same reason as before -> fires exactly once, identical coinbase. The only
new-firing case is the standalone-parent path, which cannot affect merged
coins.
Outstanding (tracked, not in this PR): BCH stratum serve-path decoder
registration (M5 pool-serve), and the live won-block-lands-on-BCHN leg
(bitaxe rig allocation).
…e-fire matrix The post-authorize work-resend gate (PR #585 seam b) widened from merged-only to (username non-empty OR merged non-empty). The prior rationale understated the new-firing scope as standalone-parent only. A P2WSH/P2TR primary carries a 32-byte witness program that cannot reduce to a 20-byte hash160, so merged_addresses_ is never auto-derived even on a merged coin (LTC/DOGE) whose username_ IS set. Under the old merged-only gate these miners got no resend and kept mining the pre-authorize degenerate value-0 coinbase; the widened gate now resends once (force_clean) so the coinbase carries the real witness-script payout. This is a latent-bug fix for taproot/segwit-script LTC/DOGE miners, not a no-op. - stratum_server.cpp: corrected gate comment to record BOTH new-firing classes (standalone-parent AND P2WSH/P2TR-primary LTC/DOGE). - test/test_address_resolution.cpp: Suite 8 ResendGate single-fire matrix mirroring handle_authorize across the full username set incl. P2WSH/P2TR LTC primaries; asserts exactly-one-fire, merged-empty for the non-convertible path, real 34-byte witness payout, and that the old merged-only gate would have stayed silent (regression witness).
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.
Summary
Two src/core seams behind the BCH G3b served-coinbase result. Both are required so a miner CashAddr username resolves to a real payout output instead of a value-0 OP_RETURN coinbase (which BCHN rejects as
bad-txns/ BIP30). Bundled because both are needed for the same served-coinbase outcome; each seam has its own justification below.This is an exceptional core/shared change (touches
src/core/address_utils+src/core/stratum_server.cpp, the shared stratum path for every coin). NOT eligible for self-merge or auto-merge — surfaced to integrator for operator tap. Not requesting merge until the gates below are green.Seam (a) — coin-registered address decoders (
src/core/address_utils.{hpp,cpp})address_to_script()now consults coin-registered fallback decoders after its built-in bech32/base58 formats fail. Core stays format-agnostic and holds no coin-specific address knowledge: a decoder is an opaque functorstring -> scriptPubKey, returning{}to mean "not my format, try the next one". Thread-safe registry, additive, and inert until a coin callsregister_address_decoder().BCH supplies its CashAddr decoder in
src/impl/bch/coin/cashaddr.hpp(header-only, included here). Pre/post evidence on the BCH harness:address_to_script("bchtest:q...")returned{}before the decoder was registered and the correct P2PKHscriptPubKeyafter — proving the fallback is clean and built-ins are untouched.Seam (b) — authorize work-resend gate (
src/core/stratum_server.cpp)The post-authorize work-resend was gated on
!merged_addresses_.empty(). Standalone parent coins (BCH/BTC — no merged chains) never populatemerged_addresses_, so they kept mining the pre-authorize job, whose emptyusername_produced an empty payout_script -> degenerate coinbase. The gate now fires when the now-knownusername_or merged addrs can change the coinbase.Single-fire (all coins): the change is a single guard around a single
send_notify_work(true)— no second send added. The resend fires exactly once in every case.Corrected new-firing scope (the prior "standalone-parent only" claim was incomplete — there are TWO new-firing classes):
username_set,merged_addresses_empty.merged_addresses_is not auto-derived even thoughusername_is set. Under the OLD merged-only gate these miners got no post-authorize resend and kept mining the pre-authorize degenerate value-0 coinbase. The widened gate now resends once (force_clean) so their coinbase carries the real payout —address_to_script()returns00 20 <32B>(P2WSH) /51 20 <32B>(P2TR). This is a latent-bug fix for taproot/segwit-script LTC/DOGE miners: a genuine, correct LTC/DOGE behavior change, not a no-op.For a P2PKH/P2WPKH/P2SH merged primary,
merged_addresses_is populated on authorize, so the new disjunction is true for the same reason the old condition was — identical coinbase, behavior unchanged. ltc-doge-production-steward verified single-fire / no double-notify against the live serve path (handle_authorize, singlesend_notify_work(true), same coinbase build). Deterministic matrix coverage including P2WSH/P2TR LTC primaries lands intest/test_address_resolution.cppSuite 8 (ResendGate.*, 7/7): asserts exactly-one-fire, merged-empty on the non-convertible path, the real 34-byte witness payout, and that the old merged-only gate would have stayed silent (regression witness).Gates (pending — do not merge until green)
test/test_address_resolution.cppSuite 8ResendGate.*, 7/7 PASS) + ltc-doge live serve-path sign-off (no double-notify, identical coinbase build)Outstanding (tracked, NOT in this PR)
work_source.cppcall-site is not on master)