Skip to content

Every node is a disk provider, listed on d1sks by signed heartbeat; v0.2.95 - #199

Merged
ralyodio merged 1 commit into
masterfrom
feat/disk-provider-default
Nov 9, 2026
Merged

ralyodio merged 1 commit into
masterfrom
feat/disk-provider-default

Conversation

@ralyodio

@ralyodio ralyodio commented Nov 9, 2026

Copy link
Copy Markdown
Collaborator

Why

Anthony: "all nodes should be disk providers too by default. can be disabled". Until now a node whose config.toml listed roles = [...] lost storage/hosting if they were missing from the list, and a disk was only listed on d1sks when gateway.announce was a public https origin, so d1sks listed exactly 1 disk (dev2).

What

Disk provider by default (config.rs, worker start)

  • storage and hosting join every node's roles, even when roles / --roles lists others (Config::apply_disk_provider_defaults, applied on load and after CLI flags).
  • Opt-outs: [storage] enabled = false / --no-storage / C0MPUTE_STORAGE=0; [hosting] enabled = false / --no-hosting / C0MPUTE_HOSTING=0. Turning one off also removes it from an explicit list.
  • Private mode adds nothing (a private node keeps exactly the roles it asked for) and never lists.
  • [storage] root now has a default, so [storage]\nenabled = false parses.
  • The installer's closing notes and worker start say the node is a disk provider and how to opt out.

Signed d1sks listing, NAT or not (opendisk.rs, supervisor.rs)

  • Every storage node (gateway or not) POSTs {payload, signature} to <d1sks>/api/v1/disks/announce 20 s after start and every 5 min (plus jitter). Payload c0mpute.disk.announce/1: marketplace host, peer id, ed25519: key, ts, expires_in 1200, optional https origin, and the OpenDisk descriptor with c0mpute.addrs (up to 8, public first) and c0mpute.reachable (https, direct, c0mpute). Signed with the worker's libp2p identity (checked to match the running peer id).
  • Replaces the origin-only register + daily re-submit. Opt out: [storage] list_on_d1sks = false or C0MPUTE_D1SKS=0. Optional [storage] country / C0MPUTE_COUNTRY.

Picking hosts (hosting/market.rs, hosting/mod.rs, CLI)

  • HostDisk carries reachable, heartbeat_age_secs (from d1sks heartbeat_age_s) and live. Ranking tier: live on the hosting gossip, then fresh and reachable (or origin-polled), then fresh behind NAT, then stale (heartbeat older than 15 min); then price, standing, space, peer id.
  • hosting publish --disks ... starts the hosting service first and listens to the gossip (up to 70 s) to mark live hosts before choosing.
  • hosting disks prints REACH and SEEN columns; --live also joins the gossip and marks which listed disks are announcing right now.

d1sks side (verification, rate limits, expiry, NAT display): profullstack/d1sks.com#6, merged and deployed.

Tests

  • config: explicit list still provides disk; enabled = false opts out even from an explicit list; private mode adds nothing and never lists; list_on_d1sks = false alone.
  • opendisk: signed listing verifies with the peer key and carries marketplace/ts/key/reachable/addrs; reachability (origin, public v4/v6, CGNAT, ULA, documentation ranges).
  • market: live and fresh reachable disks rank first, stale last.
  • Cross-language: a listing signed by opendisk::signed_listing is a fixture in d1sks test/announce.test.js and verifies there.
  • cargo test -p c0mpute-core --lib: 384 pass (two libp2p timing tests, registry_observes_advertised_capabilities and end_to_end_sealed_paid_delivery, failed once under box load and pass on rerun; untouched here).

🤖 Generated with Claude Code

…heartbeat; v0.2.95

Storage and hosting are on for every node unless turned off: an explicit
roles list (config.toml or --roles) no longer drops them. Opt-outs:
[storage] enabled = false / --no-storage / C0MPUTE_STORAGE=0,
[hosting] enabled = false / --no-hosting / C0MPUTE_HOSTING=0. Private mode
adds nothing. [storage] root now defaults, so a partial [storage] section
parses.

Every storage node lists its disk on d1sks, NAT'd or not: a payload
(c0mpute.disk.announce/1: marketplace host, peer id, key, ts, expires_in,
origin, OpenDisk descriptor with c0mpute.addrs and reachable) signed with the
node's libp2p ed25519 identity, POSTed to /api/v1/disks/announce 20 s after
start and every 5 min, expiring 20 min after the last one. Replaces the
origin-only listing (which needed a public https gateway.announce). Opt out
with [storage] list_on_d1sks = false or C0MPUTE_D1SKS=0; private mode never
lists. Optional [storage] country / C0MPUTE_COUNTRY.

hosting publish --disks auto joins the hosting gossip first and ranks d1sks
disks live on gossip first, then fresh reachable, fresh NAT'd, stale; then
price, standing, space. hosting disks shows reach, last heartbeat and, with
--live, gossip liveness.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

13 finding(s)

HIGH/CRITICAL: 1 | MEDIUM: 8 | LOW: 4

Severity Rule Location
HIGH js-ssrf-outbound-request apps/web/public/sw.js:24
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:53
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:89
MEDIUM sh-remote-script-execution scripts/dev-setup.sh:25
MEDIUM sh-eval-expansion scripts/dev-setup.sh:35
MEDIUM sh-remote-script-execution scripts/install.sh:181
MEDIUM sh-remote-script-execution scripts/install.sh:206
MEDIUM sh-remote-script-execution scripts/install.sh:399
MEDIUM sh-remote-script-execution scripts/install.sh:441
LOW py-ssrf-outbound-request examples/business-strategist-agent/chat.py:37
LOW py-ssrf-outbound-request examples/business-strategist-agent/train.py:54
LOW secret-generic-credential node/crates/c0mpute-core/src/webhook.rs:1165
LOW py-path-traversal node/crates/c0mpute-core/tests/fixtures/fake-infernet-text:29

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit c50b877 into master Nov 9, 2026
11 checks passed
ralyodio added a commit that referenced this pull request Nov 9, 2026
…#205)

Every node hosts by default since #199, including busy production boxes, and
the only guard was the 5 GiB hosting budget: dev2 runs ~6 c0mpute processes
that now all host, on a 1.8 TiB disk with 20 GiB free. replicate() now refuses
a copy unless max(10 GiB, 5% of the disk, capped at 50 GiB) stays free.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant