diff --git a/docs/plans/pool.md b/docs/plans/pool.md index d3eadd78..e39e3843 100644 --- a/docs/plans/pool.md +++ b/docs/plans/pool.md @@ -461,6 +461,20 @@ Consequences by tier, from these numbers (the standing rule of 5 October): | A pool user without a node | cannot join the open pool; pool-0 as before | the page says so | | The network | the open pool's stale rate was 9.6 percent at 2 shares a second with ten daemons on one host; a public chain at the same rate across the internet loses more to forks, which is the uncles row (10.6); every block's coinbase grew by 48 bytes per payee, at most 256 payees, under the devnet's 16,384-byte cap | the uncles row stays open; the public chain's rate is O-9.10 | +### 10.5a The ten-member window on pool-1 (the fleet lane, 7 October 2026, 12:37Z to 13:30Z) + +Ten rented RTX 3070 members (`mine none`, no node of their own) on the fixed pair, daemon 03457d96 and miner 9829bdf7, +pool-1's node 5899f603, plain TCP. Result: 10 of 10 authorized, 0 shares, 0 blocks, 0 payouts, every member's vardiff +easing from shift 10 to 27 with nothing to measure (bundle `~/igneum-fleet/pool-run-1328/` on the fleet lane's side). Two +faults stacked, each its own row: + +| Fault | Side | What the logs show | Fix | +|---|---|---|---| +| The daemon got no template after 12:54Z | daemon (this lane) | 1,891 "template for member N: RPC request timeout" lines, STATUS "NODE NOT ANSWERING: last template 2,072 s ago" at 13:28Z, while the node read synced with 3 to 4 peers and answered its own miner's 578 template requests | ten parallel `getBlockTemplate` calls on one gRPC connection against a node that builds a template in 1.6 to 1.8 s queued past the client's own request timeout; `--template-parallel` (default 2) bounds the fetches in flight, the rest take the next tick | +| The members' NVRTC prepare never completed across the epoch boundary 78 to 79 | the member's worker path | every member printed `prepare started ... (NVRTC sm_86 in the background)` and never `prepared` or `prepare-failed`; the worker sat at 0 percent on the old pack; a solo miner on a standing box crossed the same boundary through its exit-42-and-re-export path, which the member path lacks | the register's row (docs/plans/miner-faults.md, the reliability lane's number): a member that hears nothing for 120 s after a prepare treats it as failed, re-exports, re-sends once, then restarts its worker with the reason shown; the pool flags a member with 0 accepted across an epoch roll | + +So the window holds no pool-0 share numbers; its rerun waits for both fixes on the 0.3.21 pair. + ### 10.6 Open after this round | Item | Why it is open | What closes it | diff --git a/pool/README.md b/pool/README.md index 387048bf..ecee8872 100644 --- a/pool/README.md +++ b/pool/README.md @@ -54,6 +54,7 @@ igneum-pool --node grpc://127.0.0.1:26610 --evm-rpc http://127.0.0.1:26790 \ | `--stale-grace-ms` | `2000` | a share on a superseded job inside the grace still pays | | `--orphan-after-daa` | `120` | a pending block this far behind the virtual and not blue is an orphan | | `--verify-threads` | `2` | share checks running at once on the CPU | +| `--template-parallel` | `2` | template fetches in flight against the node (one gRPC connection is one request stream; a burst of one fetch per member against a node that builds a template in over a second queued past the client's request timeout on pool-1, 7 October 2026) | | `--tls-cert`, `--tls-key` | none | TLS 1.3 on the member port (spec 9.3) from a PEM chain and key | | `--tls-self-signed` | off | TLS 1.3 from a self-signed pair made under the data dir on first start; the pool prints the certificate's pin, members pass it as `--pool-pin` | | `--allow-plain` | off | plain TCP members on testnet or mainnet (the devnet allows plain by default; the public networks refuse to start in the clear without this) | diff --git a/pool/src/config.rs b/pool/src/config.rs index 730a6864..c2b4e249 100644 --- a/pool/src/config.rs +++ b/pool/src/config.rs @@ -39,6 +39,11 @@ pub struct Config { /// its own miner plus four members, the fixed 5 s gave up on the parallel fetches, no job was issued for 7 minutes, /// every block the stale templates found was an orphan, and vardiff could not act (a new target rides with a job) pub template_timeout_s: u64, + /// Template fetches in flight at once against the node (7 October 2026, the ten-member window on pool-1: ten + /// parallel getBlockTemplate calls on one gRPC connection against a node that builds a template in 1.6 to 1.8 s + /// queued past the client's own request timeout, "RPC request timeout" on every member template from 12:54Z for + /// 36 minutes, no job issued, no share); the rest of the members take the next tick's template + pub template_parallel: usize, /// TLS 1.3 on the member port (spec 9.3, `tls.rs`): a PEM chain and key, or a self-signed pair under the data dir pub tls_cert: Option, pub tls_key: Option, @@ -68,7 +73,7 @@ pub struct Config { impl Config { pub fn usage() -> ! { eprintln!( - "usage: igneum-pool [--node grpc://127.0.0.1:26610]... [--evm-rpc http://127.0.0.1:26790] [--listen 0.0.0.0:4463] [--node-wait-secs 60] [--template-timeout-s 20]\n\ + "usage: igneum-pool [--node grpc://127.0.0.1:26610]... [--evm-rpc http://127.0.0.1:26790] [--listen 0.0.0.0:4463] [--node-wait-secs 60] [--template-timeout-s 20] [--template-parallel 2]\n\ \x20 [--http 127.0.0.1:4480] [--data-dir ./data] [--payout-key ] [--fee-percent 1] [--min-payout 1.0]\n\ \x20 [--pplns-window 2.0] [--payout-interval-s 60] [--dry-run] [--network devnet|testnet|mainnet]\n\ \x20 [--share-interval-s 10] [--min-shift 0] [--max-shift 60] [--stale-grace-ms 2000] [--orphan-after-daa 120]\n\ @@ -105,6 +110,7 @@ impl Config { snapshot_interval_s: 15, node_wait_secs: 60, template_timeout_s: 20, + template_parallel: 2, tls_cert: None, tls_key: None, tls_self_signed: false, @@ -151,6 +157,7 @@ impl Config { "--snapshot-interval-s" => c.snapshot_interval_s = val().parse().unwrap_or_else(|_| Config::usage()), "--node-wait-secs" => c.node_wait_secs = val().parse().unwrap_or_else(|_| Config::usage()), "--template-timeout-s" => c.template_timeout_s = val().parse::().unwrap_or_else(|_| Config::usage()).max(1), + "--template-parallel" => c.template_parallel = val().parse::().unwrap_or_else(|_| Config::usage()).max(1), "--tls-cert" => c.tls_cert = Some(PathBuf::from(val())), "--tls-key" => c.tls_key = Some(PathBuf::from(val())), "--tls-self-signed" => c.tls_self_signed = true, diff --git a/pool/src/main.rs b/pool/src/main.rs index 4538d2b9..54614eef 100644 --- a/pool/src/main.rs +++ b/pool/src/main.rs @@ -179,6 +179,7 @@ async fn main() { net: Mutex::new(NetInfo::default()), want_templates: tokio::sync::Notify::new(), verify_permits: tokio::sync::Semaphore::new(cfg.verify_threads), + template_permits: tokio::sync::Semaphore::new(cfg.template_parallel), started: Instant::now(), cfg: cfg.clone(), template_failures: AtomicU64::new(0), diff --git a/pool/src/node.rs b/pool/src/node.rs index 807342e3..91381899 100644 --- a/pool/src/node.rs +++ b/pool/src/node.rs @@ -68,6 +68,10 @@ pub async fn fetch_job(pool: &Arc, member: &Arc) -> Result<(), Str Some(o) => o.base_extra_data(member), None => extra_data(member, &pool.pool_address), }; + // at most `--template-parallel` fetches in flight: the gRPC client is one request stream per connection and a + // node under load builds a template in over a second, so a burst of one fetch per member queued past the client's + // request timeout (pool-1, 7 October 2026, 12:54Z to 13:30Z: 1,891 "RPC request timeout" lines, no job issued) + let _permit = pool.template_permits.acquire().await.map_err(|e| e.to_string())?; let tmpl = match tokio::time::timeout(Duration::from_secs(pool.cfg.template_timeout_s), pool.node.get_block_template(pool.pay_address.clone(), base_extra)).await { Ok(Ok(t)) => t, Ok(Err(e)) => { diff --git a/pool/src/pool.rs b/pool/src/pool.rs index 6ea6df44..63c86520 100644 --- a/pool/src/pool.rs +++ b/pool/src/pool.rs @@ -123,6 +123,8 @@ pub struct Pool { pub net: Mutex, pub want_templates: tokio::sync::Notify, pub verify_permits: tokio::sync::Semaphore, + /// Template fetches in flight against the node (`--template-parallel`) + pub template_permits: tokio::sync::Semaphore, pub started: Instant, /// Template fetches that failed or timed out since start, and the unix ms of the last one that succeeded (0 = /// never): a daemon whose node answers no template issues no job, and the STATUS line in the log says so