diff --git a/crates/sentrix-core/src/blockchain.rs b/crates/sentrix-core/src/blockchain.rs index 6d6eaa20..e3c47a06 100644 --- a/crates/sentrix-core/src/blockchain.rs +++ b/crates/sentrix-core/src/blockchain.rs @@ -458,6 +458,14 @@ pub struct Blockchain { pub mempool_sender_count: std::collections::HashMap, pub total_minted: u64, pub chain_id: u64, // kept pub — read-only constant used by external clients + /// Display name of this network (eg "Sentrix Chain", "Sentrix Testnet"). + /// Sourced from the loaded genesis `[chain].name` so testnet binaries + /// don't lie about being mainnet on the `/` self-describe endpoint. + /// Default exists only because pre-genesis ctors (tests) skip the + /// genesis path; real boot always overwrites this in + /// `new_with_genesis`. + #[serde(default = "Blockchain::default_chain_name")] + pub chain_name: String, /// Binary Sparse Merkle Tree for account state. /// None until init_trie() is called; not persisted in MDBX state blob. #[serde(skip)] @@ -624,6 +632,13 @@ fn default_block_source() -> crate::block_executor::BlockSource { } impl Blockchain { + /// Default for the `chain_name` serde-skip field — only matters for + /// pre-genesis state-blob deserialisations that predate the field. + /// Real boot always overwrites via `new_with_genesis`. + fn default_chain_name() -> String { + "Sentrix Chain".to_string() + } + /// Construct a blockchain initialised from the embedded canonical mainnet /// genesis. Thin wrapper over [`Blockchain::new_with_genesis`]. /// @@ -658,6 +673,7 @@ impl Blockchain { .ok() .and_then(|v| v.parse().ok()) .unwrap_or(genesis.chain.chain_id), + chain_name: genesis.chain.name.clone(), state_trie: None, mdbx_storage: None, stake_registry: sentrix_staking::staking::StakeRegistry::new(), diff --git a/crates/sentrix-core/src/storage.rs b/crates/sentrix-core/src/storage.rs index 84f5933e..d1186dd1 100644 --- a/crates/sentrix-core/src/storage.rs +++ b/crates/sentrix-core/src/storage.rs @@ -57,6 +57,29 @@ impl Storage { } }; + // Upgrade-path fix-up for chain_name. The field gets a serde + // default of "Sentrix Chain" so old state blobs deserialise + // cleanly, but on testnet that means the loaded value silently + // takes mainnet's name. Override from the canonical chain_id + // mapping so the self-describe endpoint reflects the network + // this binary is actually running. The very first save_blockchain + // after this fix-up persists the corrected name so subsequent + // boots find it already right. + let canonical = match bc.chain_id { + 7119 => Some("Sentrix Chain"), + 7120 => Some("Sentrix Testnet"), + _ => None, + }; + if let Some(name) = canonical + && bc.chain_name != name + { + tracing::info!( + "chain_name fix-up on load: chain_id={} blob={:?} → {:?}", + bc.chain_id, bc.chain_name, name, + ); + bc.chain_name = name.to_string(); + } + // Load only the sliding window (last CHAIN_WINDOW_SIZE blocks) into RAM. let height = self .chain diff --git a/crates/sentrix-rpc/src/routes/ops.rs b/crates/sentrix-rpc/src/routes/ops.rs index 4da00073..d20d9190 100644 --- a/crates/sentrix-rpc/src/routes/ops.rs +++ b/crates/sentrix-rpc/src/routes/ops.rs @@ -29,10 +29,16 @@ pub(super) async fn root(State(state): State) -> Json