Skip to main content

pot_o_validator/
config.rs

1//! Validator configuration: TOML file and environment overrides.
2
3use serde::Deserialize;
4
5/// Runtime configuration for the PoT-O validator (HTTP server, consensus, extensions).
6#[derive(Debug, Clone, Deserialize)]
7pub struct ValidatorConfig {
8    /// Unique node identifier (default: random UUID).
9    #[serde(default = "default_node_id")]
10    pub node_id: String,
11    /// Bind address for the HTTP server (default: 0.0.0.0).
12    #[serde(default = "default_listen_addr")]
13    pub listen_addr: String,
14    /// HTTP port (default: 8900).
15    #[serde(default = "default_port")]
16    pub port: u16,
17    /// Solana RPC URL for chain and program calls.
18    #[serde(default = "default_solana_rpc_url")]
19    pub solana_rpc_url: String,
20    /// PoT-O program ID (optional; empty uses default).
21    #[serde(default)]
22    pub pot_program_id: String,
23    /// Mining difficulty (target path count).
24    #[serde(default = "default_difficulty")]
25    pub difficulty: u64,
26    /// Maximum tensor dimension for challenges.
27    #[serde(default = "default_max_tensor_dim")]
28    pub max_tensor_dim: usize,
29    /// Max iterations per mining attempt.
30    #[serde(default = "default_max_mine_iterations")]
31    #[allow(dead_code)]
32    pub max_mine_iterations: u64,
33    /// Peer network mode (e.g. local_only).
34    #[serde(default = "default_peer_network_mode")]
35    pub peer_network_mode: String,
36    /// Pool strategy (e.g. solo).
37    #[serde(default = "default_pool_strategy")]
38    pub pool_strategy: String,
39    /// Chain bridge identifier (e.g. solana).
40    #[serde(default = "default_chain_bridge")]
41    pub chain_bridge: String,
42    /// Device protocol (e.g. native).
43    #[serde(default = "default_device_protocol")]
44    pub device_protocol: String,
45    /// Path to relayer keypair for on-chain miner registration.
46    #[serde(default = "default_relayer_keypair_path")]
47    pub relayer_keypair_path: String,
48    /// Whether to auto-register miners on device registration when not yet on-chain.
49    #[serde(default = "default_auto_register_miners")]
50    pub auto_register_miners: bool,
51}
52
53fn default_node_id() -> String {
54    uuid::Uuid::new_v4().to_string()
55}
56fn default_listen_addr() -> String {
57    "0.0.0.0".into()
58}
59fn default_port() -> u16 {
60    8900
61}
62fn default_solana_rpc_url() -> String {
63    "http://testnet-solana-rpc-gateway:8899".into()
64}
65fn default_difficulty() -> u64 {
66    2
67}
68fn default_max_tensor_dim() -> usize {
69    64
70}
71fn default_max_mine_iterations() -> u64 {
72    10_000
73}
74fn default_peer_network_mode() -> String {
75    "local_only".into()
76}
77fn default_pool_strategy() -> String {
78    "solo".into()
79}
80fn default_chain_bridge() -> String {
81    "solana".into()
82}
83fn default_device_protocol() -> String {
84    "native".into()
85}
86fn default_relayer_keypair_path() -> String {
87    let home = std::env::var("HOME").unwrap_or_else(|_| "/root".into());
88    format!("{}/.config/solana/id.json", home)
89}
90fn default_auto_register_miners() -> bool {
91    true
92}
93
94impl ValidatorConfig {
95    /// Load config from TOML file, then override with env vars.
96    pub fn load() -> Self {
97        let mut cfg: Self = std::fs::read_to_string("/config/default.toml")
98            .ok()
99            .and_then(|s| toml::from_str(&s).ok())
100            .or_else(|| {
101                std::fs::read_to_string("config/default.toml")
102                    .ok()
103                    .and_then(|s| toml::from_str(&s).ok())
104            })
105            .unwrap_or_else(Self::defaults);
106
107        // Env overrides
108        if let Ok(v) = std::env::var("SOLANA_RPC_URL") {
109            cfg.solana_rpc_url = v;
110        }
111        if let Ok(v) = std::env::var("POT_PROGRAM_ID") {
112            cfg.pot_program_id = v;
113        }
114        if let Ok(v) = std::env::var("POT_O_DIFFICULTY") {
115            if let Ok(d) = v.parse() {
116                cfg.difficulty = d;
117            }
118        }
119        if let Ok(v) = std::env::var("PORT") {
120            if let Ok(p) = v.parse() {
121                cfg.port = p;
122            }
123        }
124        if let Ok(v) = std::env::var("PEER_NETWORK_MODE") {
125            cfg.peer_network_mode = v;
126        }
127        if let Ok(v) = std::env::var("POOL_STRATEGY") {
128            cfg.pool_strategy = v;
129        }
130        if let Ok(v) = std::env::var("CHAIN_BRIDGE") {
131            cfg.chain_bridge = v;
132        }
133        if let Ok(v) = std::env::var("DEVICE_PROTOCOL") {
134            cfg.device_protocol = v;
135        }
136        if let Ok(v) = std::env::var("RELAYER_KEYPAIR_PATH") {
137            cfg.relayer_keypair_path = v;
138        }
139        if let Ok(v) = std::env::var("AUTO_REGISTER_MINERS") {
140            cfg.auto_register_miners = v != "0" && v.to_lowercase() != "false";
141        }
142
143        cfg
144    }
145
146    fn defaults() -> Self {
147        Self {
148            node_id: default_node_id(),
149            listen_addr: default_listen_addr(),
150            port: default_port(),
151            solana_rpc_url: default_solana_rpc_url(),
152            pot_program_id: String::new(),
153            difficulty: default_difficulty(),
154            max_tensor_dim: default_max_tensor_dim(),
155            max_mine_iterations: default_max_mine_iterations(),
156            peer_network_mode: default_peer_network_mode(),
157            pool_strategy: default_pool_strategy(),
158            chain_bridge: default_chain_bridge(),
159            device_protocol: default_device_protocol(),
160            relayer_keypair_path: default_relayer_keypair_path(),
161            auto_register_miners: default_auto_register_miners(),
162        }
163    }
164}