Upgrade Iroh integration to 1.0
This commit is contained in:
parent
b0768999db
commit
32580749d6
9 changed files with 912 additions and 930 deletions
1672
Cargo.lock
generated
1672
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
16
Cargo.toml
16
Cargo.toml
|
|
@ -32,7 +32,7 @@ resolver = "3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://example.invalid/local/geth"
|
repository = "https://example.invalid/local/geth"
|
||||||
rust-version = "1.85"
|
rust-version = "1.91"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
|
@ -44,24 +44,22 @@ bytes = "1"
|
||||||
clap = { version = "4", features = ["derive", "env"] }
|
clap = { version = "4", features = ["derive", "env"] }
|
||||||
clap_complete = "4"
|
clap_complete = "4"
|
||||||
directories = "5"
|
directories = "5"
|
||||||
# Compatibility pins for iroh 0.95's ed25519-dalek prerelease dependency.
|
|
||||||
ed25519 = "=3.0.0-rc.1"
|
|
||||||
ed25519-dalek = { version = "2", features = ["rand_core"] }
|
ed25519-dalek = { version = "2", features = ["rand_core"] }
|
||||||
pkcs8 = "=0.11.0-rc.11"
|
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
hexane = "=0.1.5"
|
hexane = "=0.1.5"
|
||||||
iroh = { version = "0.95.1", features = ["discovery-local-network"] }
|
iroh = "1.0.0"
|
||||||
iroh-blobs = "0.97.0"
|
iroh-blobs = "0.103.0"
|
||||||
iroh-docs = "0.95.0"
|
iroh-docs = "0.101.0"
|
||||||
iroh-gossip = "0.95.0"
|
iroh-gossip = "0.101.0"
|
||||||
|
iroh-mdns-address-lookup = "0.4.0"
|
||||||
postcard = { version = "1", features = ["alloc"] }
|
postcard = { version = "1", features = ["alloc"] }
|
||||||
rand = "0.9"
|
rand = "0.9"
|
||||||
rand_core = { version = "0.6", features = ["getrandom"] }
|
rand_core = { version = "0.6", features = ["getrandom"] }
|
||||||
rusqlite = { version = "0.32", features = ["bundled"] }
|
rusqlite = { version = "0.32", features = ["bundled"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
swarm-discovery = "0.4.1"
|
swarm-discovery = "0.6.0"
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
time = { version = "0.3", features = ["formatting", "serde"] }
|
time = { version = "0.3", features = ["formatting", "serde"] }
|
||||||
|
|
|
||||||
|
|
@ -231,8 +231,8 @@ card against the observed Iroh EndpointID and requires `cas.fetch` on
|
||||||
blob payload over native `iroh-blobs` (`/iroh-bytes/4`) on the same daemon-owned
|
blob payload over native `iroh-blobs` (`/iroh-bytes/4`) on the same daemon-owned
|
||||||
Iroh endpoint, verifies the BLAKE3 hash, stores it in local CAS, and records the
|
Iroh endpoint, verifies the BLAKE3 hash, stores it in local CAS, and records the
|
||||||
serving peer as a provider visible with `geth cas providers <hash>`.
|
serving peer as a provider visible with `geth cas providers <hash>`.
|
||||||
`geth-iroh` is pinned to `iroh 0.95.1` and compiles the native backend
|
`geth-iroh` is pinned to `iroh 1.0.0` and compiles the native backend
|
||||||
libraries `iroh-blobs 0.97.0`, `iroh-docs 0.95.0`, and `iroh-gossip 0.95.0`
|
libraries `iroh-blobs 0.103.0`, `iroh-docs 0.101.0`, and `iroh-gossip 0.101.0`
|
||||||
against the same daemon-owned endpoint generation. KV stores are mirrored into
|
against the same daemon-owned endpoint generation. KV stores are mirrored into
|
||||||
native `iroh-docs` namespaces and peers receive read-only document tickets only
|
native `iroh-docs` namespaces and peers receive read-only document tickets only
|
||||||
after geth authorization succeeds. Pubsub joins native `iroh-gossip` topics
|
after geth authorization succeeds. Pubsub joins native `iroh-gossip` topics
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,11 @@ license.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
ed25519.workspace = true
|
|
||||||
pkcs8.workspace = true
|
|
||||||
iroh.workspace = true
|
iroh.workspace = true
|
||||||
iroh-blobs.workspace = true
|
iroh-blobs.workspace = true
|
||||||
iroh-docs.workspace = true
|
iroh-docs.workspace = true
|
||||||
iroh-gossip.workspace = true
|
iroh-gossip.workspace = true
|
||||||
rand.workspace = true
|
iroh-mdns-address-lookup.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ pub const ALPN_DOCUMENT: &[u8] = b"/geth/document/1";
|
||||||
pub const ALPN_SSH_PROXY: &[u8] = b"/geth/ssh-proxy/1";
|
pub const ALPN_SSH_PROXY: &[u8] = b"/geth/ssh-proxy/1";
|
||||||
pub const ALPN_OVERLAY: &[u8] = b"/geth/overlay/1";
|
pub const ALPN_OVERLAY: &[u8] = b"/geth/overlay/1";
|
||||||
|
|
||||||
pub const IROH_VERSION: &str = "0.95.1";
|
pub const IROH_VERSION: &str = "1.0.0";
|
||||||
pub const IROH_BLOBS_VERSION: &str = "0.97.0";
|
pub const IROH_BLOBS_VERSION: &str = "0.103.0";
|
||||||
pub const IROH_DOCS_VERSION: &str = "0.95.0";
|
pub const IROH_DOCS_VERSION: &str = "0.101.0";
|
||||||
pub const IROH_GOSSIP_VERSION: &str = "0.95.0";
|
pub const IROH_GOSSIP_VERSION: &str = "0.101.0";
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct GethIrohConfig {
|
pub struct GethIrohConfig {
|
||||||
|
|
@ -348,20 +348,20 @@ fn is_loopback_socket_addr(addr: &str) -> bool {
|
||||||
|
|
||||||
pub async fn start_endpoint(config: &GethIrohConfig) -> Result<GethIrohEndpoint, IrohError> {
|
pub async fn start_endpoint(config: &GethIrohConfig) -> Result<GethIrohEndpoint, IrohError> {
|
||||||
let secret_key = load_or_create_secret_key(&config.secret_key_path)?;
|
let secret_key = load_or_create_secret_key(&config.secret_key_path)?;
|
||||||
let mut builder = iroh::Endpoint::builder()
|
let mut builder = iroh::Endpoint::builder(iroh::endpoint::presets::N0)
|
||||||
.secret_key(secret_key)
|
.secret_key(secret_key)
|
||||||
.relay_mode(config.relay_mode.to_iroh()?)
|
.relay_mode(config.relay_mode.to_iroh()?)
|
||||||
.alpns(config.alpns.clone());
|
.alpns(config.alpns.clone());
|
||||||
|
|
||||||
if config.local_discovery {
|
if config.local_discovery {
|
||||||
builder = builder.discovery(iroh::discovery::mdns::MdnsDiscovery::builder());
|
builder = builder.address_lookup(iroh_mdns_address_lookup::MdnsAddressLookup::builder());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(bind_ipv4) = config.bind_ipv4 {
|
if let Some(bind_ipv4) = config.bind_ipv4 {
|
||||||
builder = builder.bind_addr_v4(bind_ipv4);
|
builder = builder.bind_addr(bind_ipv4)?;
|
||||||
}
|
}
|
||||||
if let Some(bind_ipv6) = config.bind_ipv6 {
|
if let Some(bind_ipv6) = config.bind_ipv6 {
|
||||||
builder = builder.bind_addr_v6(bind_ipv6);
|
builder = builder.bind_addr(bind_ipv6)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let endpoint = builder.bind().await.map_err(IrohError::from)?;
|
let endpoint = builder.bind().await.map_err(IrohError::from)?;
|
||||||
|
|
@ -391,7 +391,7 @@ pub fn load_or_create_secret_key(path: &Path) -> Result<iroh::SecretKey, IrohErr
|
||||||
if let Some(parent) = path.parent() {
|
if let Some(parent) = path.parent() {
|
||||||
std::fs::create_dir_all(parent)?;
|
std::fs::create_dir_all(parent)?;
|
||||||
}
|
}
|
||||||
let secret_key = iroh::SecretKey::generate(&mut rand::rng());
|
let secret_key = iroh::SecretKey::generate();
|
||||||
let tmp = path.with_extension("tmp");
|
let tmp = path.with_extension("tmp");
|
||||||
std::fs::write(&tmp, hex::encode(secret_key.to_bytes()))?;
|
std::fs::write(&tmp, hex::encode(secret_key.to_bytes()))?;
|
||||||
std::fs::rename(tmp, path)?;
|
std::fs::rename(tmp, path)?;
|
||||||
|
|
@ -444,6 +444,8 @@ pub enum IrohError {
|
||||||
InvalidSecretKeyLength,
|
InvalidSecretKeyLength,
|
||||||
#[error("invalid iroh relay URL `{url}`: {message}")]
|
#[error("invalid iroh relay URL `{url}`: {message}")]
|
||||||
InvalidRelayUrl { url: String, message: String },
|
InvalidRelayUrl { url: String, message: String },
|
||||||
|
#[error("invalid iroh bind address: {0}")]
|
||||||
|
InvalidBindAddr(iroh::endpoint::InvalidSocketAddr),
|
||||||
#[error("failed to bind iroh endpoint: {0}")]
|
#[error("failed to bind iroh endpoint: {0}")]
|
||||||
Bind(Box<iroh::endpoint::BindError>),
|
Bind(Box<iroh::endpoint::BindError>),
|
||||||
#[error("timed out waiting for iroh node address")]
|
#[error("timed out waiting for iroh node address")]
|
||||||
|
|
@ -460,6 +462,12 @@ pub enum RouterError {
|
||||||
UnknownAlpn { alpn: String },
|
UnknownAlpn { alpn: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<iroh::endpoint::InvalidSocketAddr> for IrohError {
|
||||||
|
fn from(error: iroh::endpoint::InvalidSocketAddr) -> Self {
|
||||||
|
Self::InvalidBindAddr(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<iroh::endpoint::BindError> for IrohError {
|
impl From<iroh::endpoint::BindError> for IrohError {
|
||||||
fn from(error: iroh::endpoint::BindError) -> Self {
|
fn from(error: iroh::endpoint::BindError) -> Self {
|
||||||
Self::Bind(Box::new(error))
|
Self::Bind(Box::new(error))
|
||||||
|
|
|
||||||
|
|
@ -238,15 +238,13 @@ fn geth_status_against_running_daemon() {
|
||||||
assert!(stdout.contains("iroh relay: disabled"));
|
assert!(stdout.contains("iroh relay: disabled"));
|
||||||
assert!(stdout.contains("iroh discovery: local-network disabled"));
|
assert!(stdout.contains("iroh discovery: local-network disabled"));
|
||||||
assert!(stdout.contains(
|
assert!(stdout.contains(
|
||||||
"native backend cas: shared-iroh-endpoint-ready target iroh-blobs 0.97.0 (wired)"
|
"native backend cas: shared-iroh-endpoint-ready target iroh-blobs 0.103.0 (wired)"
|
||||||
));
|
));
|
||||||
assert!(
|
|
||||||
stdout.contains(
|
|
||||||
"native backend kv: shared-iroh-endpoint-ready target iroh-docs 0.95.0 (wired)"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert!(stdout.contains(
|
assert!(stdout.contains(
|
||||||
"native backend pubsub: shared-iroh-endpoint-ready target iroh-gossip 0.95.0 (wired)"
|
"native backend kv: shared-iroh-endpoint-ready target iroh-docs 0.101.0 (wired)"
|
||||||
|
));
|
||||||
|
assert!(stdout.contains(
|
||||||
|
"native backend pubsub: shared-iroh-endpoint-ready target iroh-gossip 0.101.0 (wired)"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@ prefix-scoped capabilities.
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
The prototype keeps SQLite as the durable local KV index and mirrors each named
|
The prototype keeps SQLite as the durable local KV index and mirrors each named
|
||||||
KV store into an Iroh Documents namespace on the daemon-owned `iroh 0.95.1`
|
KV store into an Iroh Documents namespace on the daemon-owned `iroh 1.0.0`
|
||||||
endpoint. Remote `geth kv sync` still uses geth control as the authorization
|
endpoint. Remote `geth kv sync` still uses geth control as the authorization
|
||||||
preflight. If the caller has `kv.read` on the remote `resource:kv:<name>`, the
|
preflight. If the caller has `kv.read` on the remote `resource:kv:<name>`, the
|
||||||
remote daemon returns a read-only Iroh Documents ticket and the requester imports
|
remote daemon returns a read-only Iroh Documents ticket and the requester imports
|
||||||
entries through `iroh-docs 0.95.0`.
|
entries through `iroh-docs 0.101.0`.
|
||||||
|
|
||||||
The daemon must not hand out Iroh Documents write capabilities as a substitute
|
The daemon must not hand out Iroh Documents write capabilities as a substitute
|
||||||
for geth authorization. Write authority remains modeled through geth resource
|
for geth authorization. Write authority remains modeled through geth resource
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,11 @@ shared Iroh endpoint and register module protocols on ALPNs such as
|
||||||
`/geth/cas/1`, `/geth/kv/1`, `/geth/pipe/1`, `/geth/ssh-proxy/1`, and
|
`/geth/cas/1`, `/geth/kv/1`, `/geth/pipe/1`, `/geth/ssh-proxy/1`, and
|
||||||
`/geth/overlay/1`.
|
`/geth/overlay/1`.
|
||||||
|
|
||||||
The pinned Iroh integration uses `iroh = 0.95.1`. `geth-iroh` wraps
|
The pinned Iroh integration uses `iroh = 1.0.0`. `geth-iroh` wraps
|
||||||
`iroh::Endpoint::builder()`, configures geth ALPNs with `Builder::alpns`, uses
|
`iroh::Endpoint::builder(iroh::endpoint::presets::N0)`, configures geth
|
||||||
`Builder::relay_mode`, persists an `iroh::SecretKey` as hex-encoded 32-byte key
|
ALPNs with `Builder::alpns`, uses `Builder::relay_mode`, adds
|
||||||
|
`iroh-mdns-address-lookup` when local discovery is enabled, persists an
|
||||||
|
`iroh::SecretKey` as hex-encoded 32-byte key
|
||||||
material, and shuts down through `Endpoint::close().await`. The default config
|
material, and shuts down through `Endpoint::close().await`. The default config
|
||||||
uses Iroh's default relay policy; local-only/offline development can set
|
uses Iroh's default relay policy; local-only/offline development can set
|
||||||
`[iroh].relay_mode = "disabled"`. Named custom relay maps are configured under
|
`[iroh].relay_mode = "disabled"`. Named custom relay maps are configured under
|
||||||
|
|
@ -31,7 +33,7 @@ uses Iroh's default relay policy; local-only/offline development can set
|
||||||
|
|
||||||
The native module-backend crates for the intended CAS, KV, and pubsub
|
The native module-backend crates for the intended CAS, KV, and pubsub
|
||||||
replacements now compile against the same endpoint generation:
|
replacements now compile against the same endpoint generation:
|
||||||
`iroh-blobs 0.97.0`, `iroh-docs 0.95.0`, and `iroh-gossip 0.95.0`. `geth-iroh`
|
`iroh-blobs 0.103.0`, `iroh-docs 0.101.0`, and `iroh-gossip 0.101.0`. `geth-iroh`
|
||||||
exposes their native ALPNs without creating a second daemon endpoint. CAS now
|
exposes their native ALPNs without creating a second daemon endpoint. CAS now
|
||||||
registers an `iroh-blobs` provider handler on `/iroh-bytes/4`; local CAS writes
|
registers an `iroh-blobs` provider handler on `/iroh-bytes/4`; local CAS writes
|
||||||
are mirrored into the native blob store, and remote `geth cas fetch` performs a
|
are mirrored into the native blob store, and remote `geth cas fetch` performs a
|
||||||
|
|
|
||||||
|
|
@ -191,9 +191,9 @@ Implementation order:
|
||||||
equivalent.
|
equivalent.
|
||||||
- `[x]` Fallback/stub behavior remains clearly marked where APIs are not yet
|
- `[x]` Fallback/stub behavior remains clearly marked where APIs are not yet
|
||||||
pinned.
|
pinned.
|
||||||
- `[x]` Upgrade `geth-iroh` from `iroh 0.90.0` to an endpoint version
|
- `[x]` Upgrade `geth-iroh` to stable `iroh 1.0.0` with matching `iroh-blobs 0.103.0`,
|
||||||
compatible with `iroh-blobs`, `iroh-docs`, and `iroh-gossip` without
|
`iroh-docs 0.101.0`, and `iroh-gossip 0.101.0` without introducing a
|
||||||
introducing a second daemon endpoint.
|
second daemon endpoint.
|
||||||
|
|
||||||
- `[x]` File sync reconciliation polish.
|
- `[x]` File sync reconciliation polish.
|
||||||
Acceptance criteria:
|
Acceptance criteria:
|
||||||
|
|
@ -620,8 +620,8 @@ authorization and durable-state boundaries clear.
|
||||||
- `[x]` `geth cas providers <hash>` lists locally known providers.
|
- `[x]` `geth cas providers <hash>` lists locally known providers.
|
||||||
- `[x]` Tests cover local provider metadata storage.
|
- `[x]` Tests cover local provider metadata storage.
|
||||||
- `[x]` Replace the bootstrap control-ALPN byte transfer with `iroh-blobs`
|
- `[x]` Replace the bootstrap control-ALPN byte transfer with `iroh-blobs`
|
||||||
provider/fetch behavior using the daemon-owned `iroh 0.95.1` endpoint and
|
provider/fetch behavior using the daemon-owned `iroh 1.0.0` endpoint and
|
||||||
pinned `iroh-blobs 0.97.0`.
|
pinned `iroh-blobs 0.103.0`.
|
||||||
- `[x]` CAS fetch keeps the geth control-ALPN authorization preflight before
|
- `[x]` CAS fetch keeps the geth control-ALPN authorization preflight before
|
||||||
opening the native `iroh-blobs` payload transfer.
|
opening the native `iroh-blobs` payload transfer.
|
||||||
- `[x]` Local CAS adds and daemon startup mirror available blobs into the
|
- `[x]` Local CAS adds and daemon startup mirror available blobs into the
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue