245 lines
26 KiB
Markdown
245 lines
26 KiB
Markdown
# Pool vote-key commitment: the member's key stays with the member, at protocol level
|
|
|
|
Design document, Igneum 2.0, "Pools, software and participation", first bullet. Written 8 October 2026 (evening, UK)
|
|
by the adversarial seat, from the code and the specification as they stand on the box mirror's master (d6bee526) and
|
|
the pool lane's branches (`pool-finish-22` bee1f5f2, the fork's `pool-tags-node` 7455b8d5). Design only: no consensus
|
|
code changes here, and the pool lane's 0.3.20 branches are not touched. Status labels follow the specification's:
|
|
Implemented (in code on a named branch), Designed (written, not run), Measured (a number with its log).
|
|
|
|
The pin this document serves, in one sentence: a miner's finality vote key is committed into every share and every
|
|
block the miner's hardware produces, whichever pool distributes the work and collects the pay, so a pool's share of
|
|
hashrate never becomes a pool's share of votes unless the miner hands over the key on purpose, and that hand-over is
|
|
visible on chain.
|
|
|
|
## 1. The current state, from the code
|
|
|
|
### 1.1 Where the vote key is bound today
|
|
|
|
| Binding | Where | What it says | Status |
|
|
|---|---|---|---|
|
|
| The header carries the key | `vendor/igneum-node/consensus/core/src/header.rs:174`, `pub vote_key_hash: Hash` | 32 bytes, BLAKE2b under the domain `IgneumVoteKeyHash` of the 48-byte compressed G1 BLS key (spec 03 W1, table row W1). Zero only in genesis; any other header without it is `RuleError::MissingVoteKeyHash` | Implemented |
|
|
| Proof of work commits the key | `consensus/core/src/hashing/header.rs:28`, `.update(header.vote_key_hash)` in the header hash | The pre-PoW hash (the `prehash` every job carries) is a hash over every header field but the nonce, `vote_key_hash` among them (spec 02 fork point a5). A nonce that solves one prehash solves no other, so a share or a block is work on exactly one key | Implemented |
|
|
| The key is revealed once | `consensus/core/src/finality.rs:31` (`IGNK`), `:259` (`KeyReveal`, W1) | The first block under a key carries `IGNK || pubkey (48) || pop (96)` in the coinbase extra data; the node checks the proof of possession and that its hash equals the header's `vote_key_hash` | Implemented |
|
|
| Weight reads the header | spec 03 W2 to W4; the node's finality module (`docs/fork-divergence.md`, "Finality v2") | A key's 30-day weight is the blue blocks whose header names it. Nothing in weight reads the coinbase beyond the reveal | Implemented |
|
|
| The miner sets it | `vendor/igneum-node/igneum/miner/src/main.rs:480`, `raw.header.vote_key_hash = id.key_hash`; `:74`, the reveal into extra data | The solo miner writes its own identity into every template it hashes | Implemented |
|
|
| A placeholder survives | `header.rs:257`, `placeholder_vote_key_hash(payout_script)` | Devnet v0's stand-in, a hash of the payout script; any non-zero value was accepted "until the finality layer lands". The finality layer landed; the function remains callable | Implemented, to retire (5.3) |
|
|
|
|
### 1.2 Where the pay is bound today
|
|
|
|
| Binding | Where | What it says | Status |
|
|
|---|---|---|---|
|
|
| The coinbase names the payee | `consensus/core/src/evm.rs`, `miner_address_extra_data` (`IGNA` + 20 bytes) | The execution layer credits 80 percent of a blue block's subsidy to the coinbase's `IGNA` address (`pool/src/payout.rs:1`), the other 20 percent to the proving pool escrow | Implemented |
|
|
| The pool pays the pool | `pool/src/node.rs:32`, `extra_data(member, pool_address)`: the member's reveal plus the pool's `IGNA`; `:42`, `get_block_template(pool.pay_address, ...)`; `:47`, `raw.header.vote_key_hash = member.key_hash` | Pool v0 builds one template per member: the member's key in the header, the pool's address in the coinbase. The chain pays the pool; the pool's ledger (`pool/src/state.rs`, `pplns.rs`) splits it by PPLNS and pays balances at or above `min_payout` in rounds of at most 16 transfers (`payout.rs:198`) from the pool's own key (`payout-key.json`, `payout.rs:20`) | Implemented (pool-0, pool v0) |
|
|
| The open pool pays by a split in the block | fork `pool-tags-node` 7455b8d5: `evm.rs` `IGNH` (the share chain's parent) and `IGNW` (the window's split, `count x (address 20 bytes, weight 4 bytes)`), `split_producer`, the switch `pool_split_activation_daa` (never by default); `pool/src/sidechain.rs`, `open.rs`, `p2p.rs` | A share is a real template at the share chain's target with the member's own key and the member's own `IGNA`; a block pays the PPLNS window (2,160 shares) by `IGNW`, computed by every node from the block alone; nobody holds a balance or an operator key (pool.md 10.4) | Implemented on the branch, gated on Devnet 3 (pool.md 10.5: 100 members on 10 daemons, 90 of 90 honest members paid, 0 of 864 honest blocks paying a withheld address, drop proof by `verify-share`); the switch never set on any live chain |
|
|
|
|
### 1.3 Where the pool's identity is bound today, and the member's defences
|
|
|
|
| Item | Where | Status |
|
|
|---|---|---|
|
|
| The member names itself by its key | `pool/src/protocol.rs:42`, `authorize {pubkey, pop, label, payout, binding}`; spec 9.3, the `binding` over the TLS exporter (O-9.7, closed on `pool-finish-22` 10.2) | Implemented |
|
|
| The member refuses a template that names another key | spec 9.4.1 item 1; `job_refused` code `vote_key` (`protocol.rs`, pool.md section 2 "Member checks") | Implemented on the member side of the fork (`igneum/miner/src/pool.rs`) |
|
|
| The member refuses a coinbase that pays a third party or lacks its reveal | spec 9.4.1 item 2; codes `payout`, `reveal` | Implemented |
|
|
| The pool holds no key | spec 9.6 item 1; pool.md section 5 "Votes": every member voted through its own node, the pool held no key, 3 keys under one payout address on chain | Implemented, Measured on the devnet |
|
|
| Custodial mode exists and is disclosed | spec 9.6 item 5, `welcome.vote_mode` in {`member`, `pool`}; a client defaults to refusing `pool` | Designed; pool v0 does not offer it (pool.md section 3) |
|
|
| The litepaper says the opposite | `site/litepaper.html:702`, Governance: "Pools can decline, and vote keys stay with the pool"; ledger G6 (conceded 5 October 2026), O-9.1 | A stated line about the custodial case, written before pool v0 ran with member keys. Under 2.0 it flips (5.2) |
|
|
|
|
So the first half of the pin is already true in code: the header commits the key, proof of work commits the header,
|
|
and the only pool that exists names its members' keys. What 2.0 adds is the second half (payment aggregation separate
|
|
and verifiable by any node, the pool unable to substitute without the member's share failing even against a member who
|
|
does not check), and the public words.
|
|
|
|
## 2. The design
|
|
|
|
### 2.1 Where the commitment lives: the header, not the coinbase
|
|
|
|
The member's vote key is committed in the header field `vote_key_hash`, as today, and nowhere else is required. Why
|
|
the header and not a coinbase commitment:
|
|
|
|
1. Proof of work is over the header. A share is a nonce whose lane hash under the job's prehash is at or below the
|
|
share target (spec 9.8 item 1), and the prehash is the header hash with the key in it. A coinbase commitment is
|
|
also under proof of work, through `hash_merkle_root`, but only transitively: to check it the member needs the
|
|
coinbase bytes and a Merkle path (mode B) or the whole body (mode A), while the header field is one 32-byte
|
|
comparison on bytes the member hashes anyway. The cheapest check is the one every client will run.
|
|
2. Consensus already enforces the field (non-zero, revealed once, equal to the reveal's hash) and weight already reads
|
|
it. A coinbase commitment would be a second place to keep in step with the first.
|
|
3. The key is per block, the coinbase is per body. Mode C (declared templates) and the open pool build the body
|
|
themselves; the header field is the same in every mode, so the binding does not depend on which side built the
|
|
body.
|
|
|
|
The coinbase keeps what is not needed per share: the one-time reveal (`IGNK`), the finality section (`IGNF`, the votes
|
|
carried), the payee (`IGNA`), and on the open pool the share chain's parent (`IGNH`) and the window's split (`IGNW`).
|
|
|
|
### 2.2 The share is the commitment, and the pool cannot forge it
|
|
|
|
A share the pool accepts is work on a prehash. The prehash commits to `vote_key_hash`. So for a pool to credit a
|
|
member's work while naming any other key in the block, the pool would need a nonce that solves a prehash the member
|
|
never hashed, which is a fresh block's worth of work per block. There is nothing to add here for a conforming member.
|
|
|
|
The gap is the non-conforming member: a client that hashes whatever prehash it is given. Against it the pool can put
|
|
its own key in the header and the member's work becomes the pool's weight. The design closes this at the protocol's
|
|
own level rather than the client's:
|
|
|
|
1. The share carries the key. The `share` message gains `vote_key_hash` (32 bytes hex) beside `job_id`, `nonce`,
|
|
`hash`, and the pool MUST verify the share against a prehash whose header carries that key: the pool rebuilds the
|
|
prehash from the template it issued, and a template whose `vote_key_hash` is not the member's authorised key is a
|
|
template the pool cannot issue a job on at all (`job` MUST carry `vote_key_hash`, and a conforming member checks
|
|
it before any other field). Designed. Cost: 32 bytes on a line that is under 120 bytes today, one comparison.
|
|
2. The authorised key is the only key. A session is one key (`authorize`); every job and every share of the session
|
|
names it; a pool that issues a job under another key to that session is non-conforming on its face, and the
|
|
member's log says so with the code `vote_key`. Designed (spec 9.4.1 item 1 already; the job field makes it
|
|
checkable without the template).
|
|
3. On the open pool there is no pool to forge: every share is a full template the member built on its own node with
|
|
its own key and its own `IGNA`; the daemons check structure, seeds and proof of work (`open.rs`), and a share whose
|
|
header names a key other than the one that signed the daemon session is refused before it enters the chain.
|
|
Implemented on `pool-finish-22`; the session-key check is to confirm there (5.3).
|
|
|
|
### 2.3 Payment aggregation stays at the pool, separate and verifiable
|
|
|
|
Two shapes, both kept:
|
|
|
|
- The operated pool (pool-0, pool v0): the chain pays the pool's `IGNA`; the pool pays members by PPLNS from its own
|
|
balance. The key is the member's, the money is the pool's until it pays. This is the Bitcoin pool shape; it is
|
|
allowed and it stays, because a member without a node can join nothing else (pool.md 10.5, "A pool user without a
|
|
node cannot join the open pool"). What makes it verifiable: every block on chain carries `(vote_key_hash k, IGNA A)`,
|
|
so any node computes, per pool address A, the set of keys that found its blocks and each key's count, which is
|
|
exactly each member's share of the pool's income under PPLNS at the block level. A pool that underpays a member by
|
|
blocks is caught from the chain; a pool that underpays by shares is caught only by the member's own share ledger
|
|
(spec 9.2, "Underpay shares"), which is the operated pool's known limit and the open pool's reason to exist.
|
|
- The open pool (no operator): the block's coinbase carries the window's split (`IGNW`) and the chain pays the split
|
|
directly to every member's own `IGNA` from `pool_split_activation_daa` on. Aggregation is the split; verification is
|
|
every node's execution of the block; no balance exists anywhere. Implemented and gated on Devnet 3; the switch is
|
|
never set until the P2 mechanism or the override sets it, as the fee switch was.
|
|
|
|
In both shapes the vote key and the payee are different fields written by different parties on purpose: the key is
|
|
the member's and only the member's client writes it into a template it will hash; the payee is the pool's (operated)
|
|
or the member's own (open). A pool that writes a member's key into its own hashers' templates gains nothing (the
|
|
member's weight rises, not the pool's) and loses the blocks' weight for itself, which is why no pool does it.
|
|
|
|
### 2.4 The share sidechain's role
|
|
|
|
The share sidechain (pool.md 10.4; spec 09 section 9.12 on the branch) is the open pool: shares at a 10-second target,
|
|
one parent each, heaviest work wins, a PPLNS window of 2,160 shares, the window's split stamped into every coinbase so
|
|
a found block pays the window. Its role for this pin is twofold:
|
|
|
|
1. It is the only shape in which payment is verifiable from the chain alone at the share level: a member can prove
|
|
a dropped share with `verify-share` (pool.md 10.5, "Drop proof"), and a block's split is computed by every node.
|
|
2. It removes the custodian of money as well as of keys, so a home miner's whole relationship with pooling is its own
|
|
node, its own key, its own address and a gossip socket.
|
|
|
|
What it is not: it is not required for the vote-key pin. The operated pool satisfies the pin with 2.2 alone. The
|
|
sidechain is the stronger payment story, with a measured cost: every block's coinbase grew by 48 bytes per window
|
|
entry (pool.md 10.5, "The network"), the stale rate was 9.6 percent at 2 shares a second with ten daemons on one host,
|
|
and a public chain across the internet loses more to forks (the uncles row, 10.6, open).
|
|
|
|
### 2.5 What Stratum V2 job declaration supplies and what it does not
|
|
|
|
Stratum V2's Job Declaration Protocol (Braiins and the Stratum V2 working group; the lineage line of spec 09) lets a
|
|
hasher build its own block template, declare it to the pool, and be paid for shares on it, so the pool no longer
|
|
chooses the transactions. That is Igneum's mode C (spec 9.4.2) and it is in pool v0 as a required mode.
|
|
|
|
It supplies: transaction choice, and with it the hasher's own coinbase extra data (so on Igneum a declared template
|
|
carries the member's reveal and votes by construction).
|
|
|
|
It does not supply: an identity in the header. Stratum V2 has no header field for a voter, because Bitcoin has no
|
|
voter; the pool still sets the payout and, in the standard mining protocol without declaration, the whole template.
|
|
Job declaration is optional for pools, pools can decline (ledger G6 is right about that), and a pool that declines
|
|
puts the hasher back on the pool's template. On Igneum that template still carries the hasher's key in the header
|
|
(2.2), so declining job declaration changes transaction choice and nothing about votes. The sentence for the site is
|
|
in 5.2.
|
|
|
|
## 3. The attack list, as the adversarial seat tried it
|
|
|
|
Each row: the attack, what stops it in the design above, how it shows, and whether it survives.
|
|
|
|
| # | Attack | What stops it | How it shows | Survives? |
|
|
|---|---|---|---|---|
|
|
| A1 | Pool substitution: the pool names its own key in the member's header | The prehash commits the key; a conforming member refuses the job (`vote_key`); under 2.2 the job and the share name the key and a share on another key is unverifiable against the issued template | Every block under the pool's `IGNA` names one key; the explorer's concentration page (ledger X14) shows one key with the pool's whole hashrate | No, against a conforming member. Yes, against a non-conforming client by the client's consent: see A5 |
|
|
| A2 | Key reuse across members: one key authorised by many sessions, so one voter holds many members' weight | Authorisation needs the proof of possession and the TLS-exporter binding, so only the secret's holder opens a session; several sessions under one secret are one operator's rigs (spec 9.6 item 3), which is the design. A pool cannot reuse a member's key without the secret | Nothing wrong on chain: one key, its own blocks | Not an attack: weight follows the secret's holder, as intended |
|
|
| A3 | Split identities: an operator or a pool spreads its hashrate over many keys | W6: keys are free and weight is blocks, so splitting moves no weight; dust (W3, 100 blocks in 30 days) silences the small keys. A pool splitting its own rigs over many keys to look like many members fools a member count, not a weight table | Many keys with the same `IGNA` and the same uptime pattern; cosmetic | Not an attack on votes; a presentation issue for pool pages |
|
|
| A4 | Withheld votes: the pool drops a member's votes from relay and carriage | Three roads (spec 9.7 item 5): the member's own node, `submitFinalityVote` on any node, and the pool's template; a member with a verifier signs from it, not from the pool's `checkpoint`; a member without a verifier does not vote at all | The carriage ratio per key against the pool's blocks (9.7 item 6, O-9.6, threshold open) | Survives only for a member whose only road is the pool, which the specification forbids from voting in the first place |
|
|
| A5 | Custody by terms of service: a pool whose terms require the member's key, or a modified client that accepts `vote_mode: pool` | Nothing at protocol level stops a holder giving a key away, and the specification allows the disclosed custodial mode (9.6 item 5). What the protocol does: the custodial pool's blocks all name the pool's key, so its vote share equals its hash share and both are public; the official client refuses the mode by default and shows it before the first share | One key under the pool's `IGNA` with the pool's whole hashrate; the ledger's "pools hold their hashers' votes" (spec 03 3.7 item 3) is then true of that pool | YES. This is the cheapest surviving attack: it costs the pool a terms line and a client fork, and it is bounded only by members' willingness and by the public reading of it |
|
|
| A6 | Block withholding by the pool: the pool drops a block a member found | The member holds the full block (mode A or C) and submits it to its own node before or beside `solution` (spec 9.5) | The block is on the chain whatever the pool did | Survives for a member with no node (mode A, no verifier): that member loses the block's weight and the pool loses the income, so the pool has no motive beyond harming the member |
|
|
| A7 | Pay-to-third-party: the pool's template names an `IGNA` that is not the pool's announced address | Spec 9.4.1 item 2, code `payout` | A refusal in the member's log | No |
|
|
| A8 | Induced equivocation: the pool feeds two checkpoint hashes at one index | The member signs only a hash its own verifier reports (9.7 item 2); a verifier-less member does not sign | None | No |
|
|
| A9 | Session replay: a captured `authorize` replayed to open a session under a member's key | The `binding` over the TLS exporter (O-9.7, closed on `pool-finish-22` 10.2); a replayed `authorize` on another connection is refused | A refusal in the pool's log | No, since TLS landed; the test that a replay is refused is the one to keep green (5.3) |
|
|
| A10 | Share theft between members: a member submits another member's share under its own session | The share names the key and the pool verifies it against the job it issued to that session; a nonce on another member's prehash hashes to a different value (`verify.rs`, "the same nonce on another template hashes differently") | `wrong_hash` | No |
|
|
| A11 | The pool mines its own rigs under a member's key to inflate that member | The pool gives weight away and keeps no income advantage; the member's `IGNA` is not paid (the pool's is), so the member sees blocks under its key paid to the pool, which is the normal case | Nothing abnormal | Not an attack: a gift of weight |
|
|
| A12 | Open pool: a daemon stamps a share chain parent or a split that favours itself | Every member checks the coinbase before hashing (`IGNH` the chain's tip, `IGNW` the window the member computes itself); a block with a wrong split is a block the honest members never hashed | The withholder's branch on Devnet 3: 0 of 864 honest blocks paid it | No |
|
|
|
|
The cheapest one that survives is A5, custody by consent. It is not defeated by cryptography because it is not a
|
|
forgery; it is defeated by defaults (the client refuses), by visibility (one key per pool address on the explorer's
|
|
concentration page), and by the pool market (a non-custodial pool offers the same income). The design makes custody a
|
|
public, deliberate choice rather than the silent default it is on every chain with pooled voting; that is the whole of
|
|
what "at protocol level" can mean for a key its owner may give away.
|
|
|
|
A note on what was not found: no path by which a pool gains weight from a member's work without that member's client
|
|
consenting, before or after 2.2. The weight table reads headers, headers are under proof of work, and proof of work is
|
|
per key.
|
|
|
|
## 4. The cost on the honest side
|
|
|
|
| Cost | Value | Status |
|
|
|---|---|---|
|
|
| Header bytes | 0 new: `vote_key_hash` is 32 bytes in the header today | Implemented |
|
|
| Coinbase bytes | the reveal 148 bytes once per key (`IGNK` 4 + 48 + 96); `IGNA` 24 bytes per block; the finality section per block as today; on the open pool `IGNH` 36 bytes and `IGNW` 4 + 24 per window entry (48 bytes per entry measured on Devnet 3 with the hex framing) | Implemented, Measured for the open pool |
|
|
| Share and job bytes (2.2) | 32 bytes hex (64 characters) on each, so a `share` of under 120 bytes becomes under 190 and a `job` of under 300 under 370 | Designed |
|
|
| Verification per block | one 32-byte comparison on every block (W1), one BLS proof-of-possession check on a reveal block (once per key); weight accounting as today | Implemented |
|
|
| Verification per share, pool side | one 32-lane group evaluation, 0.441 ms per group on one M5 Max core (spec 9.8 item 5, Measured), 1.35 ms in isolation and 2.1 ms under load on a rented 2 vCPU box (pool.md section 5); 2.2 adds a comparison | Measured |
|
|
| The home miner's bandwidth, operated pool | one `share` per 10 s and one `job` per template: under 0.1 kbit/s for shares; the template is the cost, a few KB to a few hundred KB per second at 1 block per second in mode A (spec 9.5 sizes, Designed, O-9.5); mode B carries the header, the coinbase and a Merkle path; mode C carries nothing down and one template up per declaration | Designed, unmeasured at a public pool |
|
|
| The home miner's bandwidth, open pool | one share per 10 s per member gossiped to every daemon it peers with: at 100 members, 10 shares a second of about one template each; the Devnet 3 gate ran 100 members on 10 daemons on one host, so the internet cost is unmeasured (10.6) | Measured on one host only |
|
|
| The accepted-work penalty of home internet against a datacentre link | the second bullet of the 2.0 Pools section; unmeasured here; it is the stale rate's dependence on round-trip time at `stale_grace_ms` 2,000 ms and two block times, to be measured with a member behind a home connection against one beside the pool | Open (6) |
|
|
|
|
## 5. Migration note for the pool lane's branches
|
|
|
|
### 5.1 Rebase first
|
|
|
|
The pool lane's branches on the box mirror against `release-2.0.0` (b891444f, the version bump, 16:29 BST today):
|
|
|
|
| Branch | Ahead | Behind | Carries |
|
|
|---|---|---|---|
|
|
| `pool-finish-22` | 1 | 112 | the open pool's Devnet 3 hour and the daemon's reconnect |
|
|
| `pool-mf-row-2` | 3 | 102 | the pool page rows |
|
|
| `pool-finish` | 11 | 572 | pool-0, TLS, the share sidechain |
|
|
| `pool-v0-rebase` | 4 | 925 | the pool-mode miner on the fork (the three commits the shipper needed for 0.3.20) |
|
|
| `pool-v0` | 3 | 1,691 | the original v0 |
|
|
| `release-0.3.20` | 0 | 539 | the release line the pool lane landed on |
|
|
|
|
The fork side: `pool-tags-node` 7455b8d5 (`IGNH`, `IGNW`, `split_producer`, the switch) and `pool-finish-node`'s own
|
|
commits (the binding in `finality.rs`, the params field, the executor's split, the miner's TLS and rung). Every one of
|
|
these is rebased onto `release-2.0.0` (and the fork's 2.0 line) before any of this document's items is applied; the
|
|
version bump is rule 15's and a branch that carries 0.3.x strings is not landed on 2.0.
|
|
|
|
### 5.2 The words
|
|
|
|
- `site/litepaper.html` Governance, "Pools can decline, and vote keys stay with the pool" becomes: "Pools can decline
|
|
job declaration; the vote key stays with the miner in every mode, named in the header of every block its hardware
|
|
finds, and a pool that asks for custody says so and is shown as one key." Closes O-9.1 and the G6 cross-reference in
|
|
the ledger.
|
|
- spec 03, 3.7 item 3 ("Pools hold their hashers' votes") is rewritten as the custodial case only, with 9.6 item 5
|
|
named.
|
|
- spec 09, 9.5: `job` and `share` gain `vote_key_hash`; 9.4.1 item 1 reads "the job's `vote_key_hash` and the
|
|
template's are the member's own key"; 9.8 item 5 adds the comparison.
|
|
|
|
### 5.3 The code, in order
|
|
|
|
1. The pool daemon: `vote_key_hash` on `job` and `share` (`pool/src/protocol.rs`), checked in `verify::check`
|
|
against the job's template; the member side (`igneum/miner/src/pool.rs`) checks the job field before the template.
|
|
A test with a known-pass (the member's key) and a known-fail (another key on the job) per the standing rule.
|
|
2. The open pool: confirm the daemon refuses a share whose header key is not the session's key (`open.rs`), with the
|
|
same pair of tests.
|
|
3. Retire `placeholder_vote_key_hash` from the fork's template path once no caller remains (today the miner writes the
|
|
real hash over it); keep the consensus rule that a zero hash is a `MissingVoteKeyHash`.
|
|
4. The explorer's concentration page: keys per pool `IGNA` and the share of blocks each holds, so A5 is visible as the
|
|
design intends (ledger X14).
|
|
5. The replay test of A9 and the drop proof of A12 stay in the pool crate's tests on 2.0.
|
|
|
|
## 6. Open questions, named for main
|
|
|
|
| Id | Question | What closes it |
|
|
|---|---|---|
|
|
| Q1 | Does the share carry `vote_key_hash` (2.2 item 1, 64 more characters per share) or does the job alone (item 2) suffice, the share being bound through `job_id`? The share form lets a pool's log stand on its own as evidence; the job form is cheaper | A decision; the adversarial seat's preference is the share, for the evidence |
|
|
| Q2 | The accepted-work penalty for home internet against a datacentre connection (the 2.0 bullet) has no measurement: the stale rate at 2,000 ms grace against round-trip time | One rented member behind a home-class link (a residential proxy or a PC on home broadband) against one beside the pool, an hour each, the stale rates per member |
|
|
| Q3 | Mode A template bandwidth per member at 1 block per second on a public pool (O-9.5) | The same hour's bytes on the member's socket |
|
|
| Q4 | The open pool across the internet: stale rate and uncles (pool.md 10.6) | The Devnet 3 gate re-run with daemons on three regions |
|
|
| Q5 | Whether the custodial mode (`vote_mode: pool`) remains allowed at all under 2.0, or is removed from the specification so that A5 requires a non-conforming pool as well as a non-conforming client | A ruling; removing it does not stop A5 (a fork of the pool is as cheap as a fork of the client) but changes who is non-conforming |
|
|
| Q6 | Minimum payouts on the operated pool: `min_payout_ign` is the pool's parameter; the 2.0 bullet asks for "practical" ones, which needs the fee-per-transfer at 2.0's fee level | The execution lane's fee number, then a floor in `share_scheme` |
|