Say which pool a miner is actually looking at - #41
Merged
Conversation
The dashboard header read "simplepool · stratum stats" on every page. That is true of every simplepool ever deployed, and it left four things a miner has no other way to learn unstated: which Bitcoin network the coinbase is being built for, whether the pool pays solo or pps-classic, the coinbase tag, and the addresses the money goes to. A stratum port looks identical on mainnet and on regtest. The header chip now carries network and mode, and a strip under it names the tag, the operator fee address and — under pps-classic — the pool wallet, in full. Truncated addresses verify nothing, and verifying where the money goes is the point. The facts come from pool_meta, which the proxy now writes at startup, not from the dashboard's environment. Same rule the PPS rate already follows, for the same reason: a second copy of the config is a copy that can disagree with the pool it claims to describe. The practical consequence is that an un-restarted proxy leaves the strip reading "unknown" — deliberate, since a banner asserting the wrong network is worse than one admitting it does not know. The identity columns are read by their own guarded SELECT so a dashboard deployed ahead of the proxy keeps its rate figures. Determining the network needed care. getblockchaininfo is authoritative but is not always available: the CUSF enforcer serves exactly getblocktemplate and submitblock, and that enforcer is precisely the backend a drivechain pool must point at. So ask the node first, fall back to the network encoded in operator_address, and record which answered — an address cannot tell testnet from signet, and "inferred" says so rather than guessing. Comparing the two also catches a live footgun for free: a mainnet operator address on a test chain, or the reverse, pays the fee to a script nobody on that chain controls. Valid block, plausible coinbase, money gone. It now gets a warning in the journal at startup. /api/status returns the same five fields, so a monitor does not have to scrape HTML to notice a pool restarted onto a different network.
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.
The problem
The dashboard header says the same thing on every simplepool ever deployed:
Four things a miner has no other way to learn are left unstated:
What it looks like now
Addresses are shown in full. A truncated address verifies nothing, and
verifying where the money goes is the entire point. A non-mainnet pool gets a
warn-coloured rule — "why has my payout not arrived" and "this pool is mining
signet" are frequently the same question.
The strip renders on the admin nav too.
Where the facts come from
pool_meta, which the proxy now writes at startup — not the dashboard'senvironment. That is the rule the PPS rate already follows, for the reason
already written into
schema.sql: a second copy of the config is a copy thatcan disagree with the pool it claims to describe.
The practical consequence is that a proxy that has not restarted leaves the
strip reading
unknown. That is deliberate. A banner asserting the wrongnetwork is worse than one admitting it does not know.
The identity columns are read by their own guarded SELECT, so a dashboard
deployed ahead of the proxy — the upgrade order that actually happens — keeps
its rate figures instead of losing
poolMetaentirely to add a banner. Thereis a test pinning exactly that.
Determining the network
getblockchaininfois authoritative but is not always available: the CUSFenforcer serves exactly
getblocktemplateandsubmitblock, and thatenforcer is precisely the backend a drivechain pool must point at. So:
network_source = nodeoperator_address—network_source = inferred, and the strip labels it, because an address cannot tell testnet from signetunknownA footgun caught for free
Comparing the two answers catches something worth catching: a mainnet
operator address on a test chain, or the reverse, pays the fee to a script
nobody on that chain controls. Valid block, plausible-looking coinbase, money
gone. That now gets a warning in the journal at startup:
Also
/api/statusreturns the same five fields underpool, so a monitor does nothave to scrape HTML to notice a pool restarted onto a different network.
Changes
src/bitcoind.[ch]bitcoind_get_chain()—getblockchaininfo→chainsrc/coinbase.[ch]coinbase_address_network(),coinbase_network_is_mainnet()src/main.cresolve_network(), mismatch warning, identity written at startupschema.sql,src/store.[ch]pool_metacolumns + migrations,store_record_pool_identity()dashboard/partial/pool-identity.ejs, both navs,stats.poolIdentity(),/api/status, CSS, READMEstore_record_pool_identity()touches only its own columns, so it cannotcollide with the per-template
store_record_pool_meta()write in eitherorder — including the write-once
credited_fromstamp. It deliberately doesnot touch
updated_at, which means "when the rate was last refreshed"; astalled template path must not look alive because the process restarted.
Solo mode stores
pool_btc_addressas NULL rather than"", so "notapplicable in this mode" reads differently from "configured blank".
Testing
make test— all suites pass, including newtest_pool_identity(store) andaddress -> network(coinbase). Builds clean under-Werror.npm testindashboard/— 84 tests, 82 pass / 2 pre-existing/procskips, including 6 new ones covering full-address rendering, solo mode hiding the pool wallet,inferredlabelling, the non-mainnet flag, a pre-migration DB, and a nullpool_meta.Not in this PR
The user picked the dashboard header as the surface to fix. The same identity
gap exists in
simplepoolctl status, the proxy's startup log (partly closedhere — it now logs one
pool identity:line), and the hardcoded "About thenumbers on this page" card on
/, which still claims "PPS-classic build"and "1 000 sats × share difficulty" regardless of the actual mode and
rate. That card is wrong on a solo pool today and is worth a follow-up.