Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ members = [
]

[workspace.package]
version = "0.2.94"
version = "0.2.95"
edition = "2024"
license = "MIT"
repository = "https://github.com/profullstack/c0mpute"
Expand Down
2 changes: 1 addition & 1 deletion apps/tui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@c0mpute/tui",
"version": "0.2.94",
"version": "0.2.95",
"private": true,
"type": "module",
"bin": {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "c0mpute",
"version": "0.2.94",
"version": "0.2.95",
"private": true,
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/releases/latest.json/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const dynamic = "force-dynamic";
* this in sync with the workspace version in `Cargo.toml` on each release so a
* freshly built CLI reports "already latest" rather than a phantom upgrade.
*/
const FALLBACK_VERSION = "0.2.94";
const FALLBACK_VERSION = "0.2.95";
const FALLBACK_MIN_REQUIRED = "0.0.1";

type Channel = "stable" | "beta" | "nightly";
Expand Down
57 changes: 46 additions & 11 deletions docs/storage-opendisk.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Storage on every node, listed on OpenDisk

Storage is a default role. Every node that runs it (that is every node unless
`--roles` leaves it out) serves two things on its gateway, `0.0.0.0:7777`:
Every node is a disk provider by default: `storage` and `hosting` are on even when
`roles` in config.toml (or `--roles`) lists other roles, until the operator turns them
off (below). A node with the gateway role serves two things on `0.0.0.0:7777`:

| Path | What |
|---|---|
Expand All @@ -14,28 +15,62 @@ A node with the `hosting` role also says so: `accepts.hosting: true`, `c0mpute.r

## Listing on d1sks

A node lists itself; nothing central does it for the node. When the gateway announces a
public **https** origin, the node submits that origin to the OpenDisk marketplace
(`storage.d1sks_url`, default `https://d1sks.pwa.pit.world`) a few seconds after
start and again every 24 hours. d1sks then reads the descriptor itself, every hour,
and dedupes on the node's key.
A node lists itself; nothing central does it for the node. Every storage node, NAT'd or
not, pushes a **signed listing** to the OpenDisk marketplace (`storage.d1sks_url`,
default `https://d1sks.pwa.pit.world`) 20 seconds after start and then every 5 minutes:

```
POST /api/v1/disks/announce
{ "payload": "<JSON text>", "signature": "<hex ed25519 signature over the text>" }
```

The payload is `{ type: "c0mpute.disk.announce/1", marketplace, peer_id, key, ts,
expires_in, origin, descriptor }`. It is signed with the node's libp2p identity, so d1sks
checks that `key` is the key inside `peer_id` and that the signature holds; no origin
fetch is needed. `marketplace` (the d1sks host) and `ts` stop replays. The descriptor is the
same OpenDisk document the gateway serves, plus `c0mpute.addrs` (up to 8 multiaddrs, public
first) and `c0mpute.reachable`:

| `reachable` | Meaning |
|---|---|
| `https` | the gateway announces a public https origin (`gateway.announce`); d1sks shows its URL |
| `direct` | a public IP multiaddr; dialable over libp2p |
| `c0mpute` | behind NAT; reached through c0mpute over connections the node opens. Still a full holder: storage and hosting move over libp2p |

A listing expires 20 minutes after the last heartbeat, so a node that goes quiet drops off
by itself. `c0mpute hosting publish --disks auto` ranks disks seen live on the hosting
gossip first, then fresh publicly reachable ones, then fresh NAT'd ones, then stale ones
(price, standing and free space break ties); `c0mpute hosting disks --live` shows the same.

Origin-based listings still work for any OpenDisk server: `POST /api/v1/disks {"url": ...}`
and d1sks fetches `/.well-known/opendisk.json` hourly.

```toml
# ~/.config/c0mpute/config.toml
[gateway]
bind = "0.0.0.0:7777"
announce = "https://disk.example.net" # TLS in front of :7777
announce = "https://disk.example.net" # optional: TLS in front of :7777

[storage]
enabled = true # false: not a disk provider at all
list_on_d1sks = true # false: store for the network, stay off d1sks
country = "DE" # optional, shown and filterable on d1sks
cap_bytes = 500_000_000_000 # offer 500 GB, not the whole disk
price_usd_per_gib_month = 0.004 # the default
trusted_writers = [] # extra ed25519 keys (64 hex) allowed to write
opendisk = true # false: no descriptor, no listing

[hosting]
enabled = true # false: hold no sites for the network
```

A node without a public https origin (most home nodes, behind NAT) still serves its
descriptor locally and still stores shards for the network; it is simply not on the
marketplace until it has an origin d1sks can reach.
| Opt-out | Config | CLI | Environment |
|---|---|---|---|
| no storage, not listed | `[storage] enabled = false` | `worker start --no-storage` | `C0MPUTE_STORAGE=0` |
| no hosting | `[hosting] enabled = false` | `worker start --no-hosting` | `C0MPUTE_HOSTING=0` |
| store, but stay off d1sks | `[storage] list_on_d1sks = false` | | `C0MPUTE_D1SKS=0` |

Private mode never lists and never adds roles the node did not ask for.

## On the node board

Expand Down
Loading
Loading