/ node / network / src / lib.rs
lib.rs
  1  // Copyright (c) 2025 ADnet Contributors
  2  // This file is part of the AlphaOS library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  #![forbid(unsafe_code)]
 17  
 18  pub mod node_type;
 19  pub use node_type::*;
 20  
 21  pub mod peer;
 22  pub use peer::*;
 23  
 24  pub mod peering;
 25  pub use peering::*;
 26  
 27  pub mod resolver;
 28  pub use resolver::*;
 29  
 30  use alphavm::prelude::Network;
 31  
 32  use std::{net::SocketAddr, str::FromStr};
 33  use tracing::*;
 34  
 35  // Include the generated build information.
 36  pub mod built_info {
 37      include!(concat!(env!("OUT_DIR"), "/built.rs"));
 38  }
 39  
 40  /// Returns the list of bootstrap peers for the ALPHA network.
 41  ///
 42  /// Bootstrap peers can also be configured via environment variables:
 43  /// - ALPHA_BOOTSTRAP_PEERS: Comma-separated list of peer addresses (e.g., "1.2.3.4:4130,5.6.7.8:4130")
 44  #[allow(clippy::if_same_then_else)]
 45  pub fn bootstrap_peers<N: Network>(is_dev: bool) -> Vec<SocketAddr> {
 46      if cfg!(feature = "test") || is_dev {
 47          // Development testing contains optional bootstrap peers loaded from the environment.
 48          match std::env::var("TEST_BOOTSTRAP_PEERS") {
 49              Ok(peers) => peers.split(',').map(|peer| SocketAddr::from_str(peer).unwrap()).collect(),
 50              Err(err) => {
 51                  warn!("Failed to load bootstrap peers from environment: {err}");
 52                  vec![]
 53              }
 54          }
 55      } else if let Ok(peers) = std::env::var("ALPHA_BOOTSTRAP_PEERS") {
 56          // Allow runtime configuration of bootstrap peers via environment variable.
 57          peers.split(',').filter_map(|peer| SocketAddr::from_str(peer.trim()).ok()).collect()
 58      } else if N::ID == alphavm::console::network::MainnetV0::ID {
 59          // ALPHA Mainnet bootstrap peers (ADnet infrastructure).
 60          // TODO: Replace with actual ADnet mainnet bootstrap node IPs when deployed.
 61          vec![
 62              // Placeholder: ADnet mainnet bootstrap nodes
 63              // SocketAddr::from_str("alpha-boot-1.adnet.io:4130").unwrap(),
 64              // SocketAddr::from_str("alpha-boot-2.adnet.io:4130").unwrap(),
 65          ]
 66      } else if N::ID == alphavm::console::network::TestnetV0::ID {
 67          // ALPHA Testnet bootstrap peers (ADnet infrastructure).
 68          // TODO: Replace with actual ADnet testnet bootstrap node IPs when deployed.
 69          vec![
 70              // Placeholder: ADnet testnet bootstrap nodes
 71              // SocketAddr::from_str("alpha-test-1.adnet.io:4130").unwrap(),
 72              // SocketAddr::from_str("alpha-test-2.adnet.io:4130").unwrap(),
 73          ]
 74      } else if N::ID == alphavm::console::network::CanaryV0::ID {
 75          // ALPHA Canary bootstrap peers (ADnet infrastructure).
 76          // TODO: Replace with actual ADnet canary bootstrap node IPs when deployed.
 77          vec![
 78              // Placeholder: ADnet canary bootstrap nodes
 79              // SocketAddr::from_str("alpha-canary-1.adnet.io:4130").unwrap(),
 80              // SocketAddr::from_str("alpha-canary-2.adnet.io:4130").unwrap(),
 81          ]
 82      } else {
 83          // Unrecognized networks contain no bootstrap peers.
 84          vec![]
 85      }
 86  }
 87  
 88  /// Get our SHA from the build information (or None if it is not set or does not 40 bytes long).
 89  pub fn get_repo_commit_hash() -> Option<[u8; 40]> {
 90      built_info::GIT_COMMIT_HASH.and_then(|sha| sha.as_bytes().try_into().ok())
 91  }
 92  
 93  /// Logs the peer's AlphaOS repo SHA and how it compares to ours.
 94  pub fn log_repo_sha_comparison(peer_addr: SocketAddr, peer_sha: &Option<[u8; 40]>, ctx: &str) {
 95      let our_sha = get_repo_commit_hash();
 96  
 97      // Generate a string representation for the peers hash.
 98      let peer_sha_str: Option<&str> = peer_sha.as_ref().and_then(|h| str::from_utf8(h).ok());
 99  
100      let sha_cmp = match (&our_sha, peer_sha, peer_sha_str) {
101          // They sent no hash, or an invalid string.
102          (_, _, None) | (_, None, _) => " with an unknown repo SHA".to_owned(),
103          // Our hash cannot be retrieved.
104          (None, _, Some(theirs_str)) => format!("@{theirs_str} (potentially different than us)"),
105          // Both hashes are valid. Compare.
106          (Some(ours), Some(theirs), Some(theirs_str)) => {
107              if ours == theirs {
108                  format!("@{theirs_str} (same as us)")
109              } else {
110                  format!("@{theirs_str} (different than us)")
111              }
112          }
113      };
114  
115      debug!("{ctx} Peer '{peer_addr}' uses AlphaOS{sha_cmp}");
116  }