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:
parent
700312688a
commit
f3b43179de
1 changed files with 15 additions and 9 deletions
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue