Ember /api/live: each block and miner row carries "miner", the lane id = the first 8 hex of the vote key hash, the same 8 a card's ids carry (the UI marks "you" by it); test

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-06 19:52:16 +00:00
parent 700312688a
commit f3b43179de

View file

@ -74,24 +74,26 @@ pub fn shape_from_blocks(blocks: &[RecentBlock], now_ms: u64, window_s: u64) ->
let rows: Vec<Value> = blocks
.iter()
.filter(|b| b.timestamp_ms >= win)
.map(|b| json!({ "hash": short(&b.hash), "blue_score": b.blue_score, "daa": b.daa_score, "timestamp_ms": b.timestamp_ms, "is_chain_block": b.is_chain_block, "color": if b.color.is_empty() { "pending" } else { b.color.as_str() }, "vote_key_hash": short(&b.vote_key_hash), "timestamp_source": if b.timestamp_source.is_empty() { "header" } else { b.timestamp_source.as_str() } }))
.map(|b| json!({ "hash": short(&b.hash), "blue_score": b.blue_score, "daa": b.daa_score, "timestamp_ms": b.timestamp_ms, "is_chain_block": b.is_chain_block, "color": if b.color.is_empty() { "pending" } else { b.color.as_str() }, "vote_key_hash": short(&b.vote_key_hash), "miner": lane(&b.vote_key_hash), "timestamp_source": if b.timestamp_source.is_empty() { "header" } else { b.timestamp_source.as_str() } }))
.collect();
json!({
"miners_10m": miners.len(),
"blocks_10m": recent.len(),
"blocks_per_minute": per_min,
"blocks": rows,
"miners": miners.iter().map(|(k, n)| json!({ "vote_key_hash": short(k), "blocks_10m": n })).collect::<Vec<_>>(),
"miners": miners.iter().map(|(k, n)| json!({ "id": lane(k), "vote_key_hash": short(k), "blocks_10m": n })).collect::<Vec<_>>(),
})
}
/// The lane id the UI matches against a card's `ids`: the first 8 hex of the vote key hash (engine.rs gives a card
/// its ids the same way, `h.chars().take(8)`); "" when the block carries no key.
pub fn lane(vote_key_hash: &str) -> String {
vote_key_hash.trim_start_matches("0x").chars().take(8).collect()
}
/// The site's `short`: the first 16 hex (site/api/live.mjs), so a hash reads the same from either source.
fn short(h: &str) -> String {
let h = h.trim_start_matches("0x");
if h.len() > 12 {
format!("{}..{}", &h[..6], &h[h.len() - 6..])
} else {
h.to_string()
}
h.trim_start_matches("0x").chars().take(16).collect()
}
/// The reply for GET /api/live: cached when fresh, else a refresh is started and the last body (or `pending`)
@ -212,6 +214,10 @@ mod tests {
assert_eq!(v["blocks"][0]["color"], "blue");
assert_eq!(v["blocks"][0]["timestamp_source"], "header");
assert_eq!(v["miners"].as_array().unwrap().len(), 3);
assert_eq!(v["blocks"][0]["miner"], "aa", "the lane id is the first 8 hex of the vote key hash, as a card's ids");
assert_eq!(v["miners"][0]["id"], "aa", "the miners rows carry id, as the site's");
assert_eq!(lane("0x0123456789abcdef"), "01234567");
assert_eq!(lane(""), "");
}
#[test]
@ -222,6 +228,6 @@ mod tests {
assert_eq!((p[1].color.as_str(), p[1].timestamp_source.as_str()), ("red", "merging_block"));
assert_eq!((p[0].blue_score, p[0].is_chain_block, p[0].color.as_str()), (5, true, "blue"));
assert!(parse_recent(&json!(null)).is_empty());
assert_eq!(short("0x1234567890abcdef"), "123456..abcdef");
assert_eq!(short("0x1234567890abcdef00"), "1234567890abcdef", "the site's 16-hex short");
}
}