From 059d791d8bf48f2b8b63b539e59e866b90d0c77e Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Sun, 4 Oct 2026 15:02:24 +0000 Subject: [PATCH] Prover service: with nothing assigned, an open shard (past its exclusive window, spec 7.2 item 4) is proven; the tile says open Co-Authored-By: Claude Fable 5.1 --- app/igneum-app/src/prover.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/app/igneum-app/src/prover.rs b/app/igneum-app/src/prover.rs index 1320de4ad..d85268646 100644 --- a/app/igneum-app/src/prover.rs +++ b/app/igneum-app/src/prover.rs @@ -34,6 +34,8 @@ pub struct Work { pub pgas: u64, pub tx_count: u64, pub assigned: bool, + /// Past the exclusive window: anyone may prove it (spec 7.2 item 4). + pub open: bool, pub paid: bool, pub in_pool: bool, pub shard_wei: u128, @@ -54,6 +56,7 @@ pub fn parse_work(v: &Value) -> Vec { pgas: hexu(&w["pgas"]) as u64, tx_count: w["txCount"].as_u64().unwrap_or(0), assigned: w["assigned"].as_bool().unwrap_or(false), + open: w["open"].as_bool().unwrap_or(false), paid: !w["paid"].is_null(), in_pool: w["pool"].as_array().map(|p| !p.is_empty()).unwrap_or(false), shard_wei: hexu(&w["shardWei"]), @@ -66,10 +69,15 @@ pub fn parse_work(v: &Value) -> Vec { /// The shard to prove next: assigned to one of our keys, unpaid, not already in the pool from us, not attempted /// in this session; the newest first (its exclusive window is the one still open), the smallest among equals. +/// With nothing assigned, an open shard (spec 7.2 item 4: past its exclusive window, unpaid, anyone may prove it), +/// so a machine with no weight in the window still earns on what the assignees left. pub fn choose(work: &[Work], attempted: &HashSet<(String, u32)>) -> Option { - let mut c: Vec<&Work> = work.iter().filter(|w| w.assigned && !w.paid && !w.in_pool && !attempted.contains(&(w.hash.clone(), w.shard))).collect(); - c.sort_by(|a, b| b.number.cmp(&a.number).then(a.pgas.cmp(&b.pgas))); - c.first().map(|w| (*w).clone()) + let pick = |want_assigned: bool| { + let mut c: Vec<&Work> = work.iter().filter(|w| (if want_assigned { w.assigned } else { w.open }) && !w.paid && !w.in_pool && !attempted.contains(&(w.hash.clone(), w.shard))).collect(); + c.sort_by(|a, b| b.number.cmp(&a.number).then(a.pgas.cmp(&b.pgas))); + c.first().map(|w| (*w).clone()) + }; + pick(true).or_else(|| pick(false)) } /// A Windows path as WSL sees it: `C:\Users\x\f` -> `/mnt/c/Users/x/f`. @@ -354,7 +362,7 @@ fn loop_forever(shared: Arc, bin_dir: PathBuf) { let Some(w) = choose(&work, &attempted) else { set(&shared, |p| { p.status = if submitted.is_empty() { "idle".into() } else { "submitted".into() }; - p.message = if assigned == 0 { "no shard assigned to this machine in the last 60 blocks".into() } else { "every assigned shard is proven or paid".into() }; + p.message = if assigned == 0 { "no shard assigned to this machine and none open in the last 60 blocks".into() } else { "every assigned and open shard is proven or paid".into() }; }); continue; }; @@ -371,7 +379,7 @@ fn loop_forever(shared: Arc, bin_dir: PathBuf) { let started = Instant::now(); set(&shared, |p| { p.status = "proving".into(); - p.current = format!("block {} shard {} ({} txs, {} pgas)", w.number, w.shard, w.tx_count, w.pgas); + p.current = format!("block {} shard {} ({} txs, {} pgas{})", w.number, w.shard, w.tx_count, w.pgas, if w.assigned { "" } else { ", open" }); p.started_at = crate::platform::unix_now_f(); p.message = "exporting the chain and cutting the shard".into(); }); @@ -469,7 +477,7 @@ mod tests { #[test] fn chooses_the_newest_unpaid_assigned_shard_not_yet_attempted() { let v: Value = serde_json::from_str(r#"[ - {"number":"0x20","hash":"0xa","shard":0,"pgas":"0x640","txCount":1,"assigned":true,"assignedKeys":["0xk1"],"paid":null,"pool":[],"shardWei":"0x10"}, + {"number":"0x20","hash":"0xa","shard":0,"pgas":"0x640","txCount":1,"assigned":true,"open":false,"assignedKeys":["0xk1"],"paid":null,"pool":[],"shardWei":"0x10"}, {"number":"0x1f","hash":"0xb","shard":1,"pgas":"0x10","txCount":0,"assigned":true,"assignedKeys":["0xk1"],"paid":null,"pool":[{"keyHash":"0xk1"}],"shardWei":"0x10"}, {"number":"0x1e","hash":"0xc","shard":0,"pgas":"0x10","txCount":0,"assigned":true,"assignedKeys":["0xk2"],"paid":{"wei":"0x1"},"pool":[],"shardWei":"0x10"}, {"number":"0x1d","hash":"0xd","shard":0,"pgas":"0x10","txCount":0,"assigned":false,"assignedKeys":[],"paid":null,"pool":[],"shardWei":"0x10"},