Skip to content

Latest commit

 

History

1,245 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

deCDN

CI Security License: MIT OR Apache-2.0 MSRV

Decentralized CDN where nodes cache and serve content-addressed blobs over iroh QUIC, and clients pay per-MB via off-chain USDC vouchers backed by a shared on-chain payment pool. Rust implementation. The initial network deployment targets tens of nodes on Arbitrum Sepolia, while the on-chain surface ships at full production shape with governance-tunable economics from day one (ADR 016).

Status

Pre-launch. The workspace version is 0.0.0, there is no release tag, and nothing is published to crates.io or a container registry yet. Eleven crates and two binaries are implemented; no crate is a stub.

Until the first public deployment, wire, ABI, config, and storage formats change without compatibility shims — there are no live peers to keep in step.

How It Works

  • Nodes bond TOKEN proportional to declared bandwidth capacity, cache content, and serve BLAKE3-addressed blobs over QUIC
  • Clients take candidate nodes from their peer store or the on-chain registry, pick the RTT-nearest — from their RTT map, or by probing (ADR 037) — stream content, and pay via off-chain USDC vouchers
  • On a cache miss, nodes pull from peers (paid), cache locally, and stream to the client simultaneously
  • All byte transfers are paid — client-to-node and node-to-node
  ┌────────────┐ ┌────────────┐ ┌────────────┐
  │    Node    │◄┤    Node    │◄┤    Node    │
  │  (cached)  ├►│  (origin)  ├►│  (cached)  │
  └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
        │              │              │
     pays per-MB    pays per-MB    pays per-MB
       (USDC)         (USDC)         (USDC)
        │              │              │
  ┌─────▼──────┐ ┌─────▼──────┐ ┌─────▼──────┐
  │   Client   │ │   Client   │ │   Client   │
  └────────────┘ └────────────┘ └────────────┘

Wire Protocols (Core CDN)

ALPN Purpose
cdn/probe/v1 Latency + availability probing
cdn/client/v1 All paid delivery (client→node and node→node)
cdn/dht/v1 Content discovery via Kademlia DHT (see ADR 022)

Peer discovery is on-chain, not broadcast: the node set is the CapacityBond active staker set, read directly from the contract (ADR 001).

Binaries

Binary Role
decdn-node Daemon — runs the cache node service. Single subcommand: decdn-node run [--config <path>].
decdn User CLI — every command a human types. See the table below.

The container image ships decdn-node only. Publishers grab the decdn-${VERSION}-${TARGET}.tar.gz release archive; operators grab both. See adr/appendix-binaries.md for the dockerd-style split rationale.

CLI Surface

Command group Purpose
key-gen, whoami Generate, then inspect, the Ed25519 node key and Ethereum keystore
config {init,validate} Render a config file and check one before the daemon reads it
setup Guided operator onboarding over key-gen / node bond / node register (ADR 019)
node {…} Operator admin against a running daemon over the loopback surface, plus the on-chain lifecycle (bond, register, deregister, rotate-key) and read-only diagnostics (doctor, lookup, slashes)
probe, fetch Probe a node over cdn/probe/v1; paid single-blob fetch over cdn/client/v1
pool {…} Client payment-pool lifecycle: list/status, open, top-up, close, reclaim, assign (delegated spend)
publish {…} Publisher control plane: create namespaces, seat and unseat authorized origins
origin {import} Seed a cache origin store from local content, offline and config-free
bundle {pull} Fetch directory bundles by manifest
appeal {slash} File a slash appeal and post the appeal bond (ADR 028)

Run decdn --help for the full subcommand tree.

Install

From the first tagged release — nothing is published yet, see Status above:

cargo install decdn-cli          # the `decdn` CLI
cargo install decdn-node         # the daemon
docker pull decdn/decdn-node     # or ghcr.io/decdn/decdn-node

Signed release archives are attached to each GitHub release; they are the channel a maintainer's signature covers, so prefer them if you verify signatures — see SECURITY.md. Operator terms accepted at registration live in crates/cli/TERMS.md, embedded verbatim in the CLI.

Quickstart

Run a node. setup performs the pre-flight checks, bonds TOKEN against the on-chain bondRequired(mbps) curve, and registers the node, then prints a go/no-go summary.

decdn config init
decdn setup --mbps 100 --region US --multiaddr /ip4/203.0.113.10/udp/4433/quic-v1
decdn-node run --config ~/.decdn/node.toml
decdn node health          # then `node status`, `node lanes`, `node pools`, `node top`

Fetch content. A pool is a single deposit that fans out to every provider paid from it, so there is no per-provider open.

decdn pool open --deposit-micro-usdc 5000000
decdn fetch --hash <blake3-hash> --output ./blob.bin

Publishers additionally create a namespace and seat the origins authorized to serve it:

decdn publish namespace create
decdn publish assign <namespace-id> <0xOPERATOR>

Chain endpoints and contract addresses come from the config file, or from explicit --rpc-url and --*-address flags on each command.

Architecture

Crate Structure

crates/
  node/         — daemon binary `decdn-node`: runtime bring-up, handlers, admin RPC server, dispatch limiter
  cli/          — user CLI binary `decdn`: every command a human types (see the CLI Surface table above)
  common/       — shared types: config schema + resolver, identity loading, AdminRpc trait + DTOs, and the clap definitions for both binaries
  protocol/     — shared types, wire format, ALPN message definitions (leaf crate, minimal deps)
  config-types/ — config-vocabulary value types shared by cache + common (leaf crate)
  bao-range/    — iroh-blobs-free bao verified-range helpers: chunk-group alignment, range encode/verify, origin-store layout (leaf crate, ADR 038)
  cache/        — cache engine wrapping iroh-blobs + origin pull-through
  client/       — reusable `cdn/client/v1` paid-pull requester and buyer-side channel open, shared by node and cli
  incentive/    — shared payment pools, staking, vouchers (alloy for Ethereum)
  reputation/   — local per-peer reputation scoring (ADR 008)
  e2e/          — test-only cross-layer Rust↔contract fixtures (anvil + the production deploy script)
contracts/      — Solidity contracts + Foundry (repo root, excluded from workspace)

The daemon is itself a paying client on its upstream cache-miss leg, which is why node depends on client like any other consumer. Three leaf crates — protocol, config-types, and bao-range — keep the publisher CLI free of any blob store or AWS SDK; .github/scripts/check_crate_edges.py enforces that boundary in CI.

Key Design Decisions

Architecture decision records live in adr/. adr/README.md is the entry point with reading order; adr/architecture.md is the living overview. Highlights:

  • Content addressing: BLAKE3 hashes; clients verify on receipt (ADR 002)
  • Encryption-agnostic protocol: publishers may encrypt content before upload; the CDN content-addresses and delivers the resulting bytes, while key distribution stays outside the protocol (ADR 002)
  • Dual currency: USDC for payments, TOKEN for staking and governance; per-bucket economics are governance-tunable from day one (ADR 026, ADR 016)
  • No exposed origins: origin backends (S3/R2/B2) are opaque per-node config
  • Settlement: provider-only redemption — no party submits a value on another's behalf, so an owner's closePool cannot understate a node's earnings; the node's periodic redeem sweep runs inside the close grace window to collect earned vouchers before the owner can reclaim (ADR 003)
  • Discovery: cdn/dht/v1 Kademlia DHT over the on-chain active set, with the on-chain origin directory as the deterministic last-resort fallback (ADR 022)
  • Verified ranges: the BLAKE3 content hash already is a Merkle root, and the outboard supplies the interior nodes, so any byte range verifies on its own — this is what makes resume and parallel fetch safe (ADR 038)
  • Multi-source fetch: a client saturates its downlink from the cheapest adequate set of holders, reassigning ranges as sources finish or stall (ADR 039)
  • Cache policy: admission and eviction are node-local and pluggable, never a wire concern (ADR 040)
  • Regional locality: latency-driven proxy warming closes the gap between keyspace-routed discovery and geographic demand (ADR 037)
  • Refuse to serve: a node declines a cache miss whose upstream price leaves no margin after the fee split, rather than serving at a loss (ADR 041)
  • Reputation: local per-peer EWMA over observed outcomes, with no cross-node aggregation (ADR 008)
  • Slashing appeals: slashed TOKEN sits in escrow and the operator has a bounded 30-day appeal backed by an appeal bond (ADR 028)
  • Governance: single day-one governance contract surface (DecdnGovernor + TimelockController); served-bytes-weighted operator voting with hardcoded safety bounds — only the process evolves by phase (admin key → bootstrap multisig → DAO), not the contract set (ADR 009, ADR 036)
  • Content takedown: governance-controlled hash blacklisting with regional compliance bodies (ADR 011)
  • Client architecture: lightweight QUIC endpoints; registry bootstrap with fallback; per-connection ephemeral identity binding (ADR 012)
  • Schema evolution: varint-length framing, protocol enums, three-tier evolution model (ADR 013)
  • On-chain verification: single secp256k1 EIP-712 slash signature (slash_sig) per message with optimistic challenge-response; the Ed25519 NodeId is connection identity only, authenticated separately by the QUIC handshake (ADR 014)
  • Liquidity: protocol-owned liquidity via a Uniswap V3 50/50 TOKEN/USDC pool (ADR 018)
  • Production L2: Arbitrum One for all on-chain contracts (appendix)

Development

See CONTRIBUTING.md for development environment setup, build commands, coding standards, and contribution guidelines.

Operations

License

Dual-licensed under either MIT or Apache-2.0, at your option.

About

Decentralized CDN where nodes cache and serve content-addressed blobs over iroh QUIC, and clients pay per-MB via off-chain USDC shared payment pools.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages