0.3.18 (app only): the clock sample asks igneum_getExecStatus first and takes no block from a follower without a record (ledger N7)
A node before 0.3.18's exec RPC fix dies on eth_getBlockByNumber when its exec follower holds no record (rpc.rs indexes records[0] on an empty vector; the panic hook exits the process), and this sample ran every 9 s once blocks arrived, so a fresh install's IBD and PC 1's restart crash-looped. The sample now waits for executedTipHash. No node change; the pin stays at 5899f603. Version 0.3.18 on the 0.3.17 app tree. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
a7a9e5c231
commit
0f6b4650b6
7 changed files with 46 additions and 10 deletions
2
app/igneum-app/Cargo.lock
generated
2
app/igneum-app/Cargo.lock
generated
|
|
@ -219,7 +219,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "igneum-app"
|
name = "igneum-app"
|
||||||
version = "0.3.17"
|
version = "0.3.18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "igneum-app"
|
name = "igneum-app"
|
||||||
version = "0.3.17"
|
version = "0.3.18"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Igneum Miner engine: supervises the node, the miner and the GPU workers, and serves the dashboard on 127.0.0.1"
|
description = "Igneum Miner engine: supervises the node, the miner and the GPU workers, and serves the dashboard on 127.0.0.1"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
1 ICON "igneum.ico"
|
1 ICON "igneum.ico"
|
||||||
|
|
||||||
1 VERSIONINFO
|
1 VERSIONINFO
|
||||||
FILEVERSION 0,3,17,0
|
FILEVERSION 0,3,18,0
|
||||||
PRODUCTVERSION 0,3,17,0
|
PRODUCTVERSION 0,3,18,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
FILEFLAGS 0x0L
|
FILEFLAGS 0x0L
|
||||||
FILEOS VOS_NT_WINDOWS32
|
FILEOS VOS_NT_WINDOWS32
|
||||||
|
|
@ -20,12 +20,12 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Igneum"
|
VALUE "CompanyName", "Igneum"
|
||||||
VALUE "FileDescription", "Igneum Miner engine"
|
VALUE "FileDescription", "Igneum Miner engine"
|
||||||
VALUE "FileVersion", "0.3.17"
|
VALUE "FileVersion", "0.3.18"
|
||||||
VALUE "InternalName", "igneum-app"
|
VALUE "InternalName", "igneum-app"
|
||||||
VALUE "LegalCopyright", "Igneum contributors"
|
VALUE "LegalCopyright", "Igneum contributors"
|
||||||
VALUE "OriginalFilename", "igneum-app.exe"
|
VALUE "OriginalFilename", "igneum-app.exe"
|
||||||
VALUE "ProductName", "Igneum Miner"
|
VALUE "ProductName", "Igneum Miner"
|
||||||
VALUE "ProductVersion", "0.3.17"
|
VALUE "ProductVersion", "0.3.18"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,36 @@ fn days_from_civil(y: i64, m: i64, d: i64) -> i64 {
|
||||||
era * 146_097 + doe - 719_468
|
era * 146_097 + doe - 719_468
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// True once the node's exec follower holds a record (igneum_getExecStatus's executedTipHash is set). Any error or an
|
||||||
|
/// unreachable node reads false: the block sample waits rather than asks.
|
||||||
|
fn exec_has_record(evm_port: u16) -> bool {
|
||||||
|
let body = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"igneum_getExecStatus\",\"params\":[]}";
|
||||||
|
let out = crate::detect::run_timeout(
|
||||||
|
Command::new(crate::platform::tool("curl")).args(["-s", "--max-time", "5", "-X", "POST", &format!("http://127.0.0.1:{evm_port}"), "-H", "Content-Type: application/json", "-d", body]),
|
||||||
|
None,
|
||||||
|
Duration::from_secs(7),
|
||||||
|
);
|
||||||
|
out.as_deref().map(exec_status_has_record).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The reading of an igneum_getExecStatus reply: a record is held when executedTipHash is a non-null string.
|
||||||
|
pub fn exec_status_has_record(reply: &str) -> bool {
|
||||||
|
serde_json::from_str::<serde_json::Value>(reply)
|
||||||
|
.ok()
|
||||||
|
.and_then(|v| v.get("result")?.get("executedTipHash")?.as_str().map(|h| !h.is_empty()))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
/// The latest block's timestamp (unix seconds) from the node's Ethereum JSON-RPC (the execution layer mirrors the
|
/// The latest block's timestamp (unix seconds) from the node's Ethereum JSON-RPC (the execution layer mirrors the
|
||||||
/// consensus block times). The first clock source: local time against what the peers produced.
|
/// consensus block times). The first clock source: local time against what the peers produced.
|
||||||
pub fn latest_block_time(evm_port: u16) -> Option<f64> {
|
pub fn latest_block_time(evm_port: u16) -> Option<f64> {
|
||||||
|
// 0.3.18 (ledger N7, 7 October 2026): a node whose exec follower holds no record yet dies on eth_getBlockByNumber
|
||||||
|
// (rpc.rs indexes records[0] on an empty vector and the panic hook exits the process). The nodes before 0.3.18's
|
||||||
|
// fix are live on every machine, and this sample runs every 9 s once blocks arrive, so it asks igneum_getExecStatus
|
||||||
|
// first (it indexes nothing) and takes no block until the follower reports an executed tip.
|
||||||
|
if !exec_has_record(evm_port) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let body = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}";
|
let body = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}";
|
||||||
let out = crate::detect::run_timeout(
|
let out = crate::detect::run_timeout(
|
||||||
Command::new(crate::platform::tool("curl")).args(["-s", "--max-time", "5", "-X", "POST", &format!("http://127.0.0.1:{evm_port}"), "-H", "Content-Type: application/json", "-d", body]),
|
Command::new(crate::platform::tool("curl")).args(["-s", "--max-time", "5", "-X", "POST", &format!("http://127.0.0.1:{evm_port}"), "-H", "Content-Type: application/json", "-d", body]),
|
||||||
|
|
@ -56,6 +83,15 @@ pub fn latest_block_time(evm_port: u16) -> Option<f64> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
/// Ledger N7: the clock sample must not ask eth_getBlockByNumber of a follower with no record
|
||||||
|
#[test]
|
||||||
|
fn exec_status_gate() {
|
||||||
|
assert!(super::exec_status_has_record(r#"{"jsonrpc":"2.0","id":1,"result":{"executedTip":"0x38a5","executedTipHash":"0xa3ae37ec31b9227c3855a1b25ba50ee9f6815bf00b0befcc8836b430baf04343"}}"#));
|
||||||
|
assert!(!super::exec_status_has_record(r#"{"jsonrpc":"2.0","id":1,"result":{"executedTip":"0x0","executedTipHash":null}}"#));
|
||||||
|
assert!(!super::exec_status_has_record(r#"{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"method not found"}}"#));
|
||||||
|
assert!(!super::exec_status_has_record(""));
|
||||||
|
assert!(!super::exec_status_has_record("not json"));
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn http_date() {
|
fn http_date() {
|
||||||
assert_eq!(super::parse_http_date("Sun, 04 Oct 2026 11:17:47 GMT"), Some(1_791_112_667.0));
|
assert_eq!(super::parse_http_date("Sun, 04 Oct 2026 11:17:47 GMT"), Some(1_791_112_667.0));
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,6 @@
|
||||||
// packaging/windows/Igneum-Miner.iss when the app version moves. Include guards, not #pragma once: rc.exe reads it too.
|
// packaging/windows/Igneum-Miner.iss when the app version moves. Include guards, not #pragma once: rc.exe reads it too.
|
||||||
#ifndef IGNEUM_HOST_VERSION_H
|
#ifndef IGNEUM_HOST_VERSION_H
|
||||||
#define IGNEUM_HOST_VERSION_H
|
#define IGNEUM_HOST_VERSION_H
|
||||||
#define IGNEUM_HOST_VERSION_STR "0.3.17"
|
#define IGNEUM_HOST_VERSION_STR "0.3.18"
|
||||||
#define IGNEUM_HOST_VERSION_RC 0,3,17,0
|
#define IGNEUM_HOST_VERSION_RC 0,3,18,0
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>VERSION_STAMP</string>
|
<string>VERSION_STAMP</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.3.17</string>
|
<string>0.3.18</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
#define ArtDir "..\..\brand\icons"
|
#define ArtDir "..\..\brand\icons"
|
||||||
#endif
|
#endif
|
||||||
#ifndef AppVersion
|
#ifndef AppVersion
|
||||||
#define AppVersion "0.3.17"
|
#define AppVersion "0.3.18"
|
||||||
#endif
|
#endif
|
||||||
#define AppName "Igneum Miner"
|
#define AppName "Igneum Miner"
|
||||||
#define Publisher "Igneum"
|
#define Publisher "Igneum"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue