Upgrade Iroh native backend foundation

This commit is contained in:
Eric Wendland 2026-05-22 15:28:52 +02:00
commit 9d46dd4d0d
11 changed files with 1588 additions and 712 deletions

View file

@ -2,7 +2,6 @@ use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::net::{SocketAddrV4, SocketAddrV6};
use std::path::{Path, PathBuf};
use std::time::Duration;
pub const ALPN_CONTROL: &[u8] = b"/geth/control/1";
pub const ALPN_KV: &[u8] = b"/geth/kv/1";
@ -13,6 +12,11 @@ pub const ALPN_DB: &[u8] = b"/geth/db/1";
pub const ALPN_DOCUMENT: &[u8] = b"/geth/document/1";
pub const ALPN_SSH_PROXY: &[u8] = b"/geth/ssh-proxy/1";
pub const IROH_VERSION: &str = "0.95.1";
pub const IROH_BLOBS_VERSION: &str = "0.97.0";
pub const IROH_DOCS_VERSION: &str = "0.95.0";
pub const IROH_GOSSIP_VERSION: &str = "0.95.0";
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct GethIrohConfig {
pub secret_key_path: PathBuf,
@ -157,6 +161,38 @@ pub fn default_protocol_descriptors() -> Vec<ProtocolDescriptor> {
]
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct NativeIrohLibrary {
pub module: String,
pub crate_name: String,
pub crate_version: String,
pub alpn: String,
}
#[must_use]
pub fn native_iroh_libraries() -> Vec<NativeIrohLibrary> {
vec![
NativeIrohLibrary {
module: "cas".to_owned(),
crate_name: "iroh-blobs".to_owned(),
crate_version: IROH_BLOBS_VERSION.to_owned(),
alpn: display_alpn(iroh_blobs::ALPN),
},
NativeIrohLibrary {
module: "kv".to_owned(),
crate_name: "iroh-docs".to_owned(),
crate_version: IROH_DOCS_VERSION.to_owned(),
alpn: display_alpn(iroh_docs::ALPN),
},
NativeIrohLibrary {
module: "pubsub".to_owned(),
crate_name: "iroh-gossip".to_owned(),
crate_version: IROH_GOSSIP_VERSION.to_owned(),
alpn: display_alpn(iroh_gossip::ALPN),
},
]
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GethRelayMode {
@ -218,7 +254,7 @@ impl GethIrohEndpoint {
#[must_use]
pub fn node_id(&self) -> String {
self.endpoint.node_id().to_string()
self.endpoint.id().to_string()
}
#[must_use]
@ -227,19 +263,12 @@ impl GethIrohEndpoint {
}
pub async fn node_addr_snapshot(&self) -> Result<GethNodeAddr, IrohError> {
use n0_watcher::Watcher;
let mut watcher = self.endpoint.node_addr();
let node_addr = tokio::time::timeout(Duration::from_secs(2), watcher.initialized())
.await
.map_err(|_| IrohError::NodeAddrTimeout)?
.map_err(|error| IrohError::NodeAddrUnavailable(error.to_string()))?;
let endpoint_addr = self.endpoint.addr();
Ok(GethNodeAddr {
endpoint_id: node_addr.node_id.to_string(),
relay_url: node_addr.relay_url.map(|url| url.to_string()),
direct_addresses: node_addr
.direct_addresses
.into_iter()
endpoint_id: endpoint_addr.id.to_string(),
relay_url: endpoint_addr.relay_urls().next().map(ToString::to_string),
direct_addresses: endpoint_addr
.ip_addrs()
.map(|addr| addr.to_string())
.collect(),
})
@ -265,7 +294,7 @@ pub async fn start_endpoint(config: &GethIrohConfig) -> Result<GethIrohEndpoint,
.alpns(config.alpns.clone());
if config.local_discovery {
builder = builder.discovery_local_network();
builder = builder.discovery(iroh::discovery::mdns::MdnsDiscovery::builder());
}
if let Some(bind_ipv4) = config.bind_ipv4 {
@ -278,12 +307,17 @@ pub async fn start_endpoint(config: &GethIrohConfig) -> Result<GethIrohEndpoint,
let endpoint = builder.bind().await.map_err(IrohError::from)?;
let status = EndpointStatus {
enabled: true,
endpoint_id: Some(endpoint.node_id().to_string()),
endpoint_id: Some(endpoint.id().to_string()),
relay_mode: config.relay_mode.label(),
local_discovery: config.local_discovery,
note: format!(
"Iroh endpoint started with iroh 0.90.0; relay mode: {:?}; local discovery: {}",
config.relay_mode, config.local_discovery
"Iroh endpoint started with iroh {}; relay mode: {:?}; local discovery: {}; native libraries: iroh-blobs {}, iroh-docs {}, iroh-gossip {}",
IROH_VERSION,
config.relay_mode,
config.local_discovery,
IROH_BLOBS_VERSION,
IROH_DOCS_VERSION,
IROH_GOSSIP_VERSION
),
};
Ok(GethIrohEndpoint { endpoint, status })
@ -297,7 +331,7 @@ pub fn load_or_create_secret_key(path: &Path) -> Result<iroh::SecretKey, IrohErr
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let secret_key = iroh::SecretKey::generate(rand_core::OsRng);
let secret_key = iroh::SecretKey::generate(&mut rand::rng());
let tmp = path.with_extension("tmp");
std::fs::write(&tmp, hex::encode(secret_key.to_bytes()))?;
std::fs::rename(tmp, path)?;
@ -389,6 +423,30 @@ mod tests {
assert_eq!(alpns.len(), 8);
}
#[test]
fn native_iroh_libraries_are_pinned_and_expose_alpns() {
let libraries = native_iroh_libraries();
assert_eq!(libraries.len(), 3);
assert!(libraries.iter().any(|library| {
library.module == "cas"
&& library.crate_name == "iroh-blobs"
&& library.crate_version == IROH_BLOBS_VERSION
&& library.alpn == "/iroh-bytes/4"
}));
assert!(libraries.iter().any(|library| {
library.module == "kv"
&& library.crate_name == "iroh-docs"
&& library.crate_version == IROH_DOCS_VERSION
&& library.alpn == "/iroh-sync/1"
}));
assert!(libraries.iter().any(|library| {
library.module == "pubsub"
&& library.crate_name == "iroh-gossip"
&& library.crate_version == IROH_GOSSIP_VERSION
&& library.alpn == "/iroh-gossip/1"
}));
}
#[test]
fn default_router_registers_all_protocols() {
let router = default_protocol_router();