igneum/docs/spec/09-pool-protocol.md
igneum-labs 2fa1c49c96 Spec 09 pool protocol, spec 10 light client, phone-app design
Pool protocol after Stratum V2 job declaration: member-checked or member-built templates, JSON over TLS, shares at target64 << s on the 32-lane unit, one vote key per operator held by the member, votes relayed and carried by the pool with a chain-only drop test. Light client: trust table, checkpoint-mode bytes per day, pinned seed list, the read-only node API, the homepage card's steps. Phone app: wallet, miner monitor, node card, store rules, build plan on journey.json.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 21:43:51 +00:00

31 KiB

Igneum protocol specification, section 9: the pool protocol

Spec version 0.1, 3 October 2026. Status of this section: Designed. Nothing here is implemented. The only miner-to-worker protocol that exists is the devnet worker protocol (igneum-miner --worker, vendor/igneum-node/igneum/miner/src/main.rs; --serve in proto-cuda/host.cu, proto-opencl/host.c, proto-metal/main.swift), which runs between two processes on one machine and is cited here where this section reuses it. The review of 3 October 2026 found that no pool protocol existed and that "shares on a 64-bit lane hash with vardiff are unspecified" (docs/review/round-3-2026-10-03.md, farm operator, attack 3, R3.15). This section is the answer.

Lineage, credited. The shape is Stratum V2's (Braiins and the Stratum V2 working group, stratumprotocol.org), from memory and approximate: a binary, encrypted protocol with a Mining Protocol for shares, a Job Declaration Protocol under which a miner builds its own block template from its own node and declares it to the pool, which may accept it and must then pay shares found on it, and a Template Distribution Protocol between the miner and its node. Igneum keeps the three ideas (encrypted transport, miner-built templates under the pool's payout, pool pays by shares) and changes what the header carries: on Igneum the header names a vote key (section 2.4) and the vote key decides finality (section 3), so this section also fixes whose key a pooled block names and who signs the checkpoint votes. The ledger entries F10 and G6 (pools hold the votes; Stratum V2 job declaration is optional) are the two criticisms this section is written against.

Two words that collide. In this section "pool" means a mining pool: an operator that distributes work to many hashers and pays them by shares. The "proving pool" of sections 2.5 and 5.3 is the 20% emission share paid to provers and is called "the proving share" here whenever it is meant.

9.1 Roles and what each one holds

Role Runs Holds Never holds
Member The operator's miner program (the signer), on a machine the operator controls, driving one or more GPU workers over the worker protocol The operator's vote key (section 3.1 W1, section 8.5 item 4), the operator's payout preference, a verifier: either a full node or the light client of section 10 The pool's keys
Worker A GPU process fed job lines by the member (the --serve protocol) Nothing: no key, no template, no network connection Any key
Pool A server that builds templates, issues jobs, verifies shares, pays members, relays votes and carries them in its templates Its own payout address, its own full node, its members' public keys and share ledger Any member's secret key
Member's verifier A full node or a section 10 light client The chain state the member checks templates and checkpoints against

The signer is one process per vote key (9.6). Hashing rigs that carry no key are workers, and a member MAY drive any number of workers on any number of machines from one signer.

9.2 What the pool cannot do, and how a member would notice

This section exists so that each row of the following table is true for a conforming member against any pool, conforming or not.

The pool tries to Why it fails against a conforming member How it shows
Leave out or reorder transactions the member wanted in its block The member receives the full template (9.4, mode A) or builds its own (mode C) and checks it against its verifier before hashing it; a declared template is paid like any other A pool that refuses declared templates answers with a code (9.5, template_refused) and the member counts refusals; the explorer shows which templates each pool's blocks came from by the template_mode tag in the coinbase extra data
Name its own vote key in the header The pre-PoW hash commits to vote_key_hash (section 2.2, fork point a5), the member checks the field against its own key before hashing and refuses a job that names another A pool whose blocks all name one key is a custodial pool (9.6 item 5); any observer counts keys per payout address from headers and bodies alone
Drop a member's checkpoint votes Votes are signed by the member and reach the chain by three roads (9.7): the pool's template, the member's own template and any node's submitFinalityVote. The member checks that the template it is about to hash carries its outstanding votes Participation per key is public (getFinalityWeights, section 3.10) and computed from votes in blocks (Q2); 9.7 item 6 gives the chain-only test
Make a member sign a wrong checkpoint The member signs only a checkpoint hash its own verifier reports; a member without a verifier does not vote (9.7 item 2) A member that signs two hashes at one index produces equivocation evidence against itself (section 3.6), which is why the rule is "no verifier, no vote"
Withhold a block the member found The member holds the full block and submits it to its own node as well as to the pool (9.5, solution) The block is on the chain whatever the pool did
Underpay shares Share weight is fixed by this section (9.8) and the member keeps its own ledger of accepted shares Not a protocol matter beyond the ledger; the member changes pool

What the pool can still do: choose the transactions in its own templates for members who take them as offered (mode A members who do not check, or mode B members), decline declared templates with a stated code, and concentrate hashrate. Vote weight, however, follows the members' keys (9.6), so pool concentration no longer equals vote concentration as section 3.7 item 3 states; that sentence describes a custodial pool and is narrowed by this section once a conforming pool exists (O-9.1).

9.3 Transport and encoding

Decision: newline-delimited JSON over TLS 1.3, one JSON object per line, UTF-8, binary fields as lowercase hex. Not the node's gRPC.

Why. The pool protocol crosses operators and languages: pools, mining operating systems and rental markets each have their own code base, and the lingua franca of every one of them is a line of JSON on a socket (Stratum V1 made it so). The node's gRPC surface is the node's own interface, it is edited at every fork point (docs/fork-divergence.md, the rpc/grpc rows) and a pool written against it would break at each. Line-oriented text also matches the worker protocol the member already speaks downward, so one miner program has one shape of message in both directions. TLS is required because Stratum V1 in plaintext is hijackable on the wire (the reason Stratum V2 encrypts, approximate), and a hijacked connection could feed a member a checkpoint hash to sign.

Rule Value Label
Transport TLS 1.3, server-authenticated; the pool's certificate chain or a pinned public key the member obtained with the pool's address Designed
Framing One JSON object per line, \n terminated, no object over 4 MiB (a template with its transactions) Designed
Field order Irrelevant; unknown fields MUST be ignored Designed
Integers JSON numbers up to 2^53; anything that can exceed it (nonces, targets, hashes, weights in base units) is a hex string Designed
Identifiers id on every request, echoed on the reply; notifications carry no id Designed
Port 4461 (the mainnet chain id, section 7.4), 4462 testnet, 4463 devnet; a pool MAY use another and say so in its address Designed
Member authentication The authorize message carries the member's BLS public key and a proof of possession (the KeyReveal of section 3.10, 144 bytes), plus a signature over the session's TLS exporter value under the same key, so the key proves it is live and the connection is bound to it Designed

9.4 Templates

Three modes. The pool announces which it supports in welcome; every conforming pool MUST support A and C, and MAY support B.

Mode What the member receives What the member checks For whom
A, full template (default) The complete block: header fields except nonce, the coinbase (payout, the member's key reveal when outstanding, the finality section with the member's votes), every transaction as hex Everything in 9.4.1 A member with a verifier and ordinary bandwidth
B, commitment The header fields, the coinbase, the Merkle path from the coinbase to hash_merkle_root, and the transaction count; not the transactions Header, coinbase and path; it cannot check transaction choice and the protocol marks its blocks template_mode: "B" A member on a metered link that has chosen to trust the pool's transaction choice
C, declared Nothing: the member builds the template from its own node with the pool's payout address and declaration constraints, and declares it; the pool replies with an id and issues jobs on it The pool checks validity and payout; the member checks nothing further because it built it A member that wants its own transaction choice, which is the Stratum V2 job declaration idea

9.4.1 What a member checks before hashing a template (modes A and B)

A conforming member MUST verify, against its verifier, every item below, and MUST refuse the job (job_refused with the code) when one fails:

  1. vote_key_hash equals the hash of the member's own key.
  2. The coinbase miner address is the pool's address announced in welcome (so the pool, not a third party, is paid) and, when the member's key has not yet been revealed on chain, the coinbase extra data carries the member's KeyReveal.
  3. The finality section carries every vote the member sent in this session that is not yet carried by a block in the template's past (the pool reports carriage in votes_carried, and the member's verifier can confirm it).
  4. daa_score, bits, pruning_point, the parents and seed_source agree with what the member's verifier reports for a block built now: parents are known tips or within the merge-depth bound, bits is the target the verifier computes for those parents (section 2.3), the epoch seed in seeds is the one the verifier holds for that DAA score (section 1.12).
  5. Mode A only: hash_merkle_root recomputes from the transactions and the coinbase, no transaction is a state-free fault (design document, execution layer 1.5), and, when the member's verifier is a full node, the node accepts the block as a template (the node's own template validation; the RPC is the forward reference of O-9.4).
  6. Mode B only: the Merkle path from the coinbase proves membership under hash_merkle_root.

Cost. Items 1 to 4 are field comparisons. Item 5 is one Merkle root over the block's transactions and one node call, both well under the 1-s template lifetime at any block size the gas budgets of the design document allow (Designed, not measured; the measurement is O-9.5). The lottery hash is not evaluated at job time at all: the member's CPU evaluates one 32-lane unit per found nonce only (9.8), at 0.441 ms per unit on one M5 Max core (Measured, docs/bench-log.md, igneum-pow entry; section 1.11).

9.4.2 Declared templates (mode C)

  1. The member sends declare_template with the full block (as mode A would carry it) built from its own node, with the pool's payout address as miner, its own vote_key_hash, and the pool's declaration constraints from welcome honoured: at most max_extra_bytes of member extra data after the pool's tag, and the pool's tag (an opaque string the pool uses to attribute the block) placed first in the coinbase extra data.
  2. The pool MUST reply within declare_timeout_ms (Designed 500 ms) with template_ack (an id) or template_refused with one of the codes of 9.5. A pool MUST NOT refuse a declared template on the content of its transactions; it MAY refuse for invalidity against its own node, a wrong payout, a missing tag, oversize, or a rate above max_declarations_per_s.
  3. The pool issues jobs on a declared template as on its own; shares on it are paid identically (9.8).
  4. A pool MAY cap the share of its hashrate on declared templates only by refusing new declarations with code capacity, never by paying them less.

A member that is refused on code other more than refusal_tolerance times in a session SHOULD disconnect and say why in its log; the pool's refusal rate is reported by the member in stats so that a mining operating system can show it.

9.5 Messages

Direction P = pool, M = member. Every message is one object with "t" naming the type.

Type Direction Fields Meaning
hello M to P versions (list), chain_id, client, modes supported Opens the session
welcome P to M version, chain_id, pool_address, modes, vote_mode (member or pool), declaration {tag, max_extra_bytes, max_declarations_per_s, declare_timeout_ms}, share_scheme (pplns or pps with its parameters), min_shift, max_shift The pool's terms; the member shows vote_mode and share_scheme to its operator
authorize M to P pubkey (48 bytes hex), pop (96 bytes hex), binding (signature over the TLS exporter), label Names the member by its vote key
authorized P to M member_id, revealed (true when the key has been revealed on chain, per the pool's node)
seeds P to M epoch_seed, day_seed, seed_source, vdf_proof (516 bytes hex, section 4.4, when the member asks), next_epoch_seed, next_day_seed, next_at_daa Current and next seed pair so the member can prepare its workers ahead (the worker protocol's prepare)
set_target P to M shift s (9.8) Vardiff
template P to M template_id, mode (A or B), header (every field but nonce, hex), coinbase, transactions (A) or merkle_path plus tx_count (B), votes_carried (indices of the member's votes in this template) A new template; supersedes the previous one for new jobs
declare_template M to P header, coinbase, transactions Mode C
template_ack P to M template_id
template_refused P to M code in {invalid, payout, tag, oversize, rate, capacity, other}, detail
job P to M job_id, template_id, prehash (64 hex), target64 (16 hex), share_target64 (16 hex), nonce_start (hex, a multiple of 32), nonce_count (hex, a multiple of 32), clean (bool) Work. clean true means abandon earlier jobs. The member forwards it to its workers as a worker-protocol job line with share_target64 in the target field
job_refused M to P job_id, code in {vote_key, payout, reveal, votes, header, merkle, invalid, seeds}, detail The member will not hash this job and says why
share M to P job_id, nonce (16 hex), hash (16 hex) A lane hash at or below share_target64
share_result P to M job_id, nonce, accepted (bool), code in {ok, stale, duplicate, above_target, wrong_hash, unknown_job}, weight (the share's weight, 9.8)
solution M to P job_id, nonce, hash, block_hash A lane hash at or below target64. The member has already submitted the block to its own node, or does so at once if it has none
checkpoint P to M index, hash, blue_score, daa_score, state The pool's view, for information. A member MUST NOT sign from this message alone (9.7)
vote M to P index, hash, vote (280 bytes hex, section 3.10 C2) The member's signed vote, for relay and carriage
vote_ack P to M index, relayed (bool)
votes_carried P to M list of {index, block_hash} Blocks the pool's node has seen that carry the member's votes
stats both member: hashrate, workers, refusals, shares; pool: members, hashrate, blocks_24h, declared_share For dashboards and the phone app (docs/design/phone-app.md), read-only
ping, pong both id Liveness
bye both reason Close

Sizes. A job line is under 300 bytes; a share under 120; a vote about 600 (hex of 280). A mode A template is the block, which at 1 BPS and the design document's budgets is a few KB to a few hundred KB (Designed, unmeasured; O-9.5); a mode B template is about 1 KB plus the coinbase.

9.6 Identity: one vote key per operator

Rule of 3 October 2026 (ledger F17; section 3.1 W6): keys are free, weight is the only Sybil-resistant quantity, and a rule that counts keys is a rule a splitter wins. This section applies it to pools.

  1. A member's vote key is the operator's key, the one its client created under section 8.5 item 4. A pool MUST NOT create, derive or hold vote keys for its members, and a conforming client defaults to one key per operator. The devnet launcher's MINERS=8 identities per vendor is a devnet convenience and is withdrawn by this rule for any public network (ledger F17, "the client's one-key default" item, closed here as a rule and Open as code, O-9.2).
  2. The header of every block a member finds names the member's key, in every mode. The pool's blocks therefore carry as many keys as it has members, and each member's 30-day weight (W2) is the blocks that member found, under any pool or alone, because weight follows the key and not the payout address. Moving between pools moves nothing.
  3. Many rigs, one key: the key lives in one signer process (9.1) and the rigs are workers. An operator who runs two signers under one key risks equivocation (3.6): BLS signatures are deterministic, so two signers that see the same checkpoint hash produce the same vote, but two signers whose verifiers disagree during a partition sign two hashes at one index and strip the key's weight for 30 days. Two signers under one key is therefore a MUST NOT, and the client enforces it by refusing to start a second signer on the same key file.
  4. Succession (W5) is the operator's: a pool never signs a succession message, because it never holds the key.
  5. A custodial pool (vote_mode: "pool"): a pool MAY name its own key in every header it issues, and a member MAY accept that. The member's client MUST show the mode before the first share and MUST default to refusing it. A custodial pool's blocks all name one key, so its share of vote weight is visible to anyone who counts keys per payout address, and the explorer labels it. Section 3.7 item 3 describes this pool and no other.
  6. Dust (W3) is per key: a member who finds fewer than 100 blocks in 30 days has no vote whichever pool it joins, which at one block a second is about 0.004% of hashrate (section 3.7 item 6). Pooling changes a member's variance of income, not its weight.

9.7 Votes: signed by the member, relayed by the pool

  1. The member's signer reads checkpoints from its own verifier (a full node's getFinalityCheckpoints, or the light client of section 10), signs every checkpoint of the presence window it has not signed (section 3.3 Q2, as the devnet miner does, Voter::tick in main.rs), and sends each vote to the pool as a vote message. Nothing in the vote depends on the pool: the message signed is (chain_id, index, hash(C_i)) (C2), and the pool only sees the signature.
  2. A member whose only source of checkpoints is the pool's checkpoint message MUST NOT vote. A silent key leaves the active denominator after the presence window and loses nothing but its say (Q2); a key that signs what it was told loses 30 days of weight if it was told wrong (3.6). The client enforces this: voting is on only when a verifier is configured, and the light client of section 10 counts as one.
  3. The pool MUST relay every member vote to the network as its own node received it (the p2p vote message of section 3.10, C2) within relay_ms (Designed 1,000 ms, under the certificate grace of Q4, Open O-3.4) and MUST carry it in its next template's finality section unless a block in that template's past already carries it, under the per-block vote bound of O-3.3.
  4. Aggregation in templates. Votes for one (index, checkpoint hash) pair MAY be aggregated inside a block into one signature with a bitmap (Q2). A pool with many members SHOULD aggregate its members' votes per index before carriage: at 10,000 voters and 2,880 checkpoints a day, unaggregated carriage needs 333 votes per block at 280 bytes each (93 KB per block), while an aggregate per index per block is one signature and a bitmap (Designed; the bitmap's size and canonical list are O-3.12). Aggregation needs no secret key, so the pool can do it, and the member's participation is credited either way (Q2 counts a vote carried "as a vote or inside a certificate", and an in-block aggregate is a vote carrier; the spec 03 wording should say "or inside an aggregate", O-9.3).
  5. Three roads. A member's vote reaches the chain through the pool's template (item 3), through the member's own declared templates (mode C, its own finality section), and through submitFinalityVote on any node it can reach, including seed nodes; the signer SHOULD use at least two of the three. A vote carried twice costs block space and nothing else (section 3.10: "votes not already in its past").
  6. Detecting a pool that drops votes, from the chain alone. For member key k with pool payout address A, over a presence window: let V_k be the indices at which k voted (k's own log, or the votes seen on any road), B_A the blocks whose miner is A, and C_A(k) the indices among V_k carried by some block in B_A within 60 blocks of k's vote. A conforming pool's |C_A(k)| / |V_k| is near 1 minus the fraction already carried by other blocks (item 3 lets it skip votes already in the past); a pool that drops votes shows a ratio near 0 while the same votes appear in other producers' blocks or in k's own. The ratio is computable by anyone from headers and bodies (k's key hash is in the header of k's blocks and k's key is revealed in the body; A is in every coinbase), so a pool's carriage ratio is a public statistic the explorer and the phone app show per pool. The threshold below which the client warns is Open (O-9.6).

9.8 Shares

The hash is 64 bits and is defined over an aligned group of 32 nonces (section 1.9), so a share is defined the same way.

  1. A share for job j is a nonce n in the job's range with hash(n) <= share_target64(j), where hash(n) is lane n AND 31 of the group n AND ~31 under the job's prehash, init words I = seed_words_from_bytes("igneum-block/" || prehash || nonce_hi_le32) (section 1.6, header binding, O-1.9) and the job's seed pair.
  2. share_target64 = min(2^64 - 1, target64 << s) for the shift s the pool last sent in set_target, min_shift <= s <= max_shift. The pool MUST choose s so that target64 << s does not saturate; a saturated target makes every hash a share and the pool's verification cost (item 5) unbounded. target64 is the block target of the template's bits under the mapping of section 1.10 (target64 = target256 >> 192, candidate, Open O-2.4).
  3. Weight. A share at shift s counts 2^-s of a block: its expected cost is 2^64 / share_target64 hashes against 2^64 / target64 for a block, and the ratio is 2^-s exactly, so share weights are exact binary fractions and a pool's ledger needs no floating point. A solution (a share at or below target64) counts as a share at its job's shift plus whatever the scheme pays for the block.
  4. Vardiff. The pool SHOULD set s per member so that the member sends about one share per share_interval_s (Designed 10 s): at the worker protocol's 64-bit hash and a card at 229 Mhash/s (the RTX 5090 bench figure quoted in docs/review/round-3-2026-10-03.md, R3.15), ten seconds is 2.3 x 10^9 hashes, which fixes s once target64 is known. The pool adjusts s by one per set_target and never more than once per 30 s (Designed), so the share rate is a smooth estimate of a member's hashrate for the dashboards.
  5. Verification. The pool MUST verify every share by evaluating the 32-lane group on a CPU exactly as a node verifies a block (section 1.11): 0.441 ms per group steady on one M5 Max performance core, 0.87 ms worst cold (Measured, docs/bench-log.md, igneum-pow entry). One such core verifies about 2,270 shares a second, so at one share per 10 s per member one core covers about 22,000 members (derived from the measurement; a server core is the measurement of O-9.5). A pool MAY sample shares at high shifts; it MUST NOT credit a share it did not verify at a shift below sample_shift (Designed 8, so every share worth more than 1/256 of a block is checked).
  6. The member re-checks every found nonce on its own CPU before sending it as a share, as the devnet miner already does for blocks (mine_worker, "cpu re-check ok"); a worker whose found lines fail the re-check is reported as WORKER MISMATCH and the share is not sent.
  7. Rejections. stale: the job's template is superseded and the share is older than stale_grace_ms (Designed 2,000 ms, two block times, so a share found a moment after a new template still pays); duplicate: the nonce was already credited for the job; above_target: the pool's own evaluation exceeds share_target64; wrong_hash: the member's hash field disagrees with the pool's evaluation (a worker fault, reported to the operator).
  8. Payment schemes are the pool's business. The protocol fixes share weight and the share_scheme disclosure; it does not fix PPLNS window lengths or PPS fees. A pool that pays the proving share: a member's blocks pay 80% of emission to the pool's address and 20% to the provers of the block (section 2.5), so a pool receives only the 80%; whether a pool also proves (its node holds the members' keys' sortition eligibility, section 7.2, because eligibility is by key and the key is the member's) is answered by 7.2 item 2: the assignee is the member's key, so a pool cannot prove in its members' name without their shard proofs carrying their keys (R3.13, provers naming in the proof statement). Pools that offer proving to members do so under the external job market's terms, outside this section.

9.9 Seeds and the epoch boundary

The program changes every epoch and the dataset every day (section 1.12), and an ahead-of-time worker needs the next pair before the boundary (the prepare command of the worker protocol, measured across boundaries in docs/bench-log.md, hot-swap entry).

  1. The pool MUST send seeds on connection and whenever the current or next pair changes, with next_at_daa the DAA score of the boundary.
  2. The member MUST check epoch_seed and next_epoch_seed against its verifier (the VDF output for the epoch, section 4.3; on the devnet, the hash of the last selected-chain block below 3,600 e - 600) and refuse jobs on a seed its verifier does not confirm (job_refused, code seeds). A pool that could choose the seed could choose the program, which is the grinding section 4 exists to prevent.
  3. A member whose verifier is the light client of section 10 verifies the VDF proof (516 bytes, 4.5 ms, Measured, section 4.4) that the pool forwards in seeds, against the seed_source its checkpoint chain confirms.

9.10 Parameters in this section

Parameter Value Label
Transport TLS 1.3, newline-delimited JSON Designed
Ports 4461 / 4462 / 4463 Designed
Required modes A (full template) and C (declared); B optional Designed
declare_timeout_ms 500 Designed, Open O-9.5
relay_ms 1,000 Designed, tied to Q4's grace (O-3.4)
share_interval_s 10 Designed, Open O-9.5
Share target target64 << s, never saturated Designed
Share weight 2^-s of a block Designed
sample_shift 8 Designed
stale_grace_ms 2,000 Designed
Vardiff step one shift per 30 s at most Designed
Pool-side verification per share 0.441 ms per 32-lane group, one M5 Max core Measured (section 1.11); server core Open O-9.5
Vote key per member the operator's own; one signer per key; pool holds none Designed (ledger F17)
Custodial mode allowed, disclosed, refused by default, visible on chain Designed
Member without a verifier hashes, does not vote Designed
Vote carriage by the pool every member vote in the next template, aggregated per index when many Designed
Member template checks 9.4.1 items 1 to 6 Designed

9.11 Open items

Id Item What closes it Gate
O-9.1 Section 3.7 item 3 ("pools hold their hashers' votes") describes a custodial pool once this section is implemented; the litepaper's pool sentence (ledger F10, G6, overclaims 44 and 45) should say that a conforming pool's members keep their keys and that custodial pools are visible on chain A reference pool and a reference member run on the phase 4 devnet; the getFinalityWeights listing shows one key per member under the pool's payout address; then the sentence is rewritten and 3.7 narrowed 4
O-9.2 The devnet launcher runs MINERS=8 identities per vendor (ledger F17); the one-key default is a rule here and not code The launcher and the official client start one signer per operator and any number of workers; the signer refuses a second instance on the same key file 4
O-9.3 Q2 counts a vote carried "as a vote or inside a certificate"; an in-block aggregate of votes (9.7 item 4) is a third carrier and the wording should name it; the bitmap and canonical list are O-3.12 Spec 03 wording at the next MINOR step; the per-block vote bound re-run of O-3.3 with pool-aggregated carriage in the model 3
O-9.4 Mode A item 5 needs a node RPC that validates a block as a template without submitting it; none is named Add the RPC to the fork (candidate: validateBlockTemplate), with the cost per call measured at the design document's gas budgets 2
O-9.5 Every timing here is Designed: template size and bandwidth per member at 1 BPS, the member's check cost (9.4.1), declare_timeout_ms, share_interval_s, the pool's verification throughput on a server core A reference pool with 100 members on the phase 4 devnet: record template bytes per second per member, check time per template on a 2019-class laptop core, declared-template acceptance latency, shares verified per second per core on a server CPU; set the four parameters from the distributions 4
O-9.6 The carriage ratio of 9.7 item 6 has no threshold, and its 60-block window is a guess On the same devnet, one pool conforming and one dropping every vote: record both ratios per key over a day; set the warning threshold at the point that separates them with no false warnings on the conforming pool 4
O-9.7 The TLS exporter binding in authorize is named and not specified (which exporter label, which bytes are signed) Write the exact bytes at the first implementation; test that a replayed authorize on a second connection is refused 4
O-9.8 A member with only the light client of section 10 as its verifier checks headers against a checkpoint chain, not against a full node's tip, so item 4 of 9.4.1 (parents are known tips) is weaker for it: it can confirm the parents descend from the last certified checkpoint and no more Decide at gate 4 whether a light-client member may vote (9.7 item 2 says yes) after the eclipse test of O-3.7 is re-run with light-client members in the model 3, with 4
O-9.9 HiveOS and the rental markets need this protocol to list the algorithm (ledger entry on rental, "cannot list an algorithm whose kernel changes hourly without a stratum for it") The reference member runs under HiveOS against the reference pool through 24 epoch changes with in-worker compilation (R3.15's acceptance test: outage under 2 s per change) 4