From 0676b9b79650a4121ddf72665a923ec0c04b4f38 Mon Sep 17 00:00:00 2001 From: evalir Date: Wed, 10 Sep 2025 15:49:38 -0400 Subject: [PATCH 1/3] feat(calc): manual `FromEnv` impl Implements `FromEnv` manuall for the calculator. It now has the following behavior: - First, the `CHAIN_NAME` environment variable is checked. If it's present, instantiation from the chain name is attempted. - If the `CHAIN_NAME` environment variable is not present, the individual environment variables used to configure the calculator are looked up, and the calculator is instantiated. Any of these missing results in a hard error. --- src/utils/calc.rs | 60 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/utils/calc.rs b/src/utils/calc.rs index 2285e45..a37f607 100644 --- a/src/utils/calc.rs +++ b/src/utils/calc.rs @@ -1,6 +1,6 @@ -use crate::utils::from_env::FromEnv; +use crate::utils::from_env::{EnvItemInfo, FromEnv, FromEnvErr, FromEnvVar}; use signet_constants::KnownChains; -use std::str::FromStr; +use std::{num::ParseIntError, str::FromStr}; /// A slot calculator, which can calculate slot numbers, windows, and offsets /// for a given chain. @@ -51,16 +51,11 @@ use std::str::FromStr; /// The `+ 1` is added because the first slot is the slot at `slot_offset`, /// which ENDS at `start_timestamp`. I.e. a timestamp at `start_timestamp` is /// in slot `slot_offset + 1`. -#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Deserialize, FromEnv)] -#[from_env(crate)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Deserialize)] pub struct SlotCalculator { /// The start timestamp. This is the timestamp of the header to start the /// PoS chain. That header occupies a specific slot (the `slot_offset`). The /// `start_timestamp` is the END of that slot. - #[from_env( - var = "START_TIMESTAMP", - desc = "The start timestamp of the chain in seconds" - )] start_timestamp: u64, /// This is the number of the slot containing the block which contains the @@ -69,17 +64,9 @@ pub struct SlotCalculator { /// This is needed for chains that contain a merge (like Ethereum Mainnet), /// or for chains with missed slots at the start of the chain (like /// Holesky). - #[from_env( - var = "SLOT_OFFSET", - desc = "The number of the slot containing the start timestamp" - )] slot_offset: usize, /// The slot duration (in seconds). - #[from_env( - var = "SLOT_DURATION", - desc = "The slot duration of the chain in seconds" - )] slot_duration: u64, } @@ -275,6 +262,47 @@ impl SlotCalculator { } } +impl FromEnv for SlotCalculator { + type Error = FromEnvErr; + + fn inventory() -> Vec<&'static EnvItemInfo> { + vec![ + &EnvItemInfo { + var: "START_TIMESTAMP", + description: "The start timestamp of the chain in seconds", + optional: false, + }, + &EnvItemInfo { + var: "SLOT_OFFSET", + description: "The number of the slot containing the start timestamp", + optional: false, + }, + &EnvItemInfo { + var: "SLOT_DURATION", + description: "The slot duration of the chain in seconds", + optional: false, + }, + ] + } + + fn from_env() -> Result> { + if let Ok(slot_calculator) = SlotCalculator::from_env_var("CHAIN_NAME") { + return Ok(slot_calculator); + } + + // Else, look for the individual chain constants + let start_timestamp = FromEnvVar::from_env_var("START_TIMESTAMP")?; + let slot_offset = FromEnvVar::from_env_var("SLOT_OFFSET")?; + let slot_duration = FromEnvVar::from_env_var("SLOT_DURATION")?; + + Ok(Self { + start_timestamp, + slot_offset, + slot_duration, + }) + } +} + impl From for SlotCalculator { fn from(value: KnownChains) -> Self { match value { From 25122fbedb75b9bb930bf0eb3eb7ddef9fa87e4f Mon Sep 17 00:00:00 2001 From: evalir Date: Wed, 10 Sep 2025 15:55:47 -0400 Subject: [PATCH 2/3] chore: remove superfluous comment --- src/utils/calc.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/calc.rs b/src/utils/calc.rs index a37f607..116ca09 100644 --- a/src/utils/calc.rs +++ b/src/utils/calc.rs @@ -290,7 +290,6 @@ impl FromEnv for SlotCalculator { return Ok(slot_calculator); } - // Else, look for the individual chain constants let start_timestamp = FromEnvVar::from_env_var("START_TIMESTAMP")?; let slot_offset = FromEnvVar::from_env_var("SLOT_OFFSET")?; let slot_duration = FromEnvVar::from_env_var("SLOT_DURATION")?; From 7ccb9881012ece0e0ae3cefeaae4155e7396e9eb Mon Sep 17 00:00:00 2001 From: evalir Date: Wed, 10 Sep 2025 15:58:31 -0400 Subject: [PATCH 3/3] chore: add CHAIN_NAME to inventory --- Cargo.toml | 2 +- src/utils/calc.rs | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b205177..b5ac8bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "init4-bin-base" description = "Internal utilities for binaries produced by the init4 team" keywords = ["init4", "bin", "base"] -version = "0.12.2" +version = "0.12.3" edition = "2021" rust-version = "1.81" authors = ["init4", "James Prestwich", "evalir"] diff --git a/src/utils/calc.rs b/src/utils/calc.rs index 116ca09..733e947 100644 --- a/src/utils/calc.rs +++ b/src/utils/calc.rs @@ -267,20 +267,25 @@ impl FromEnv for SlotCalculator { fn inventory() -> Vec<&'static EnvItemInfo> { vec![ + &EnvItemInfo { + var: "CHAIN_NAME", + description: "The name of the chain. If set, the other environment variables are ignored.", + optional: true, + }, &EnvItemInfo { var: "START_TIMESTAMP", - description: "The start timestamp of the chain in seconds", - optional: false, + description: "The start timestamp of the chain in seconds. Required if CHAIN_NAME is not set.", + optional: true, }, &EnvItemInfo { var: "SLOT_OFFSET", - description: "The number of the slot containing the start timestamp", - optional: false, + description: "The number of the slot containing the start timestamp. Required if CHAIN_NAME is not set.", + optional: true, }, &EnvItemInfo { var: "SLOT_DURATION", - description: "The slot duration of the chain in seconds", - optional: false, + description: "The slot duration of the chain in seconds. Required if CHAIN_NAME is not set.", + optional: true, }, ] }