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
97 changes: 97 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
decdn_ref:
description: decdn/decdn branch, tag or SHA to build against
default: main

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

# This workspace path-depends on its sibling `decdn` checkout
# (`../decdn/crates/*`), so every job checks both repos out side by side:
# `sponsord/` and `decdn/` under the workspace root. `decdn` is `main` unless a
# manual run names another ref.
jobs:
linux:
name: linux (workspace)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: sponsord
- uses: actions/checkout@v4
with:
repository: decdn/decdn
ref: ${{ inputs.decdn_ref || 'main' }}
path: decdn
- uses: dtolnay/rust-toolchain@1.95
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
workspaces: sponsord
- working-directory: sponsord
run: cargo fmt --all --check
- working-directory: sponsord
run: cargo clippy --workspace --all-targets -- -D warnings
- working-directory: sponsord
run: cargo test --workspace

# `decdn-sponsored` is the end-user CLI, installed by `decdn.sh` on macOS and
# Linux and by `decdn.ps1` on Windows x64 and ARM64. The server (`sponsord`)
# runs only on Linux, so these legs cover the client crate alone.
client:
name: client (${{ matrix.target }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- runner: macos-latest
target: aarch64-apple-darwin
test: true
- runner: windows-latest
target: x86_64-pc-windows-msvc
test: true
# Cross-compiled on the x64 runner, so it is linted, not run.
- runner: windows-latest
target: aarch64-pc-windows-msvc
test: false
steps:
- uses: actions/checkout@v4
with:
path: sponsord
- uses: actions/checkout@v4
with:
repository: decdn/decdn
ref: ${{ inputs.decdn_ref || 'main' }}
path: decdn
- uses: dtolnay/rust-toolchain@1.95
with:
components: clippy
# From inside the checkout, so the target lands on the toolchain that
# `rust-toolchain.toml` pins rather than on the action's own.
- working-directory: sponsord
run: rustup target add ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
workspaces: sponsord
key: ${{ matrix.target }}
- working-directory: sponsord
run: cargo clippy -p decdn-sponsored --all-targets --target ${{ matrix.target }} -- -D warnings
- if: matrix.test
working-directory: sponsord
run: cargo test -p decdn-sponsored --target ${{ matrix.target }}
25 changes: 11 additions & 14 deletions Cargo.lock

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

19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ pool's own balance — there's no per-signer monthly accumulator.
## Crates

- `crates/server` (binary `sponsord`) — the HTTP gateway: `/healthz`,
`/decdn.sh` (templated installer), `/fund` (captcha page + capability
`/decdn.sh` and `/decdn.ps1` (templated installers for macOS/Linux and
Windows), `/fund` (captcha page + capability
issuance), `/capability` (poll for an issued capability).
- `crates/wrapper` (binary `decdn-sponsored`) — the end-user CLI: reads
`~/.decdn/sponsor.toml` (written by the installer), obtains a capability
Expand Down Expand Up @@ -62,7 +63,7 @@ pool up from the treasury whenever its remaining balance falls below
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `SPONSOR_BIND` | no | `127.0.0.1:8080` | Address the HTTP server listens on |
| `SPONSOR_PUBLIC_URL` | no | `https://up.decdn.org` | This gateway's own public base URL; baked into the `/decdn.sh` installer as `{{GATEWAY_BASE}}` |
| `SPONSOR_PUBLIC_URL` | no | `https://up.decdn.org` | This gateway's own public base URL; baked into the `/decdn.sh` and `/decdn.ps1` installers as `{{GATEWAY_BASE}}` |
| `SPONSOR_RPC_URL` | **yes** | — | Arbitrum Sepolia RPC endpoint |
| `SPONSOR_CHAIN_ID` | no | `421614` | Chain id (Arbitrum Sepolia) |
| `SPONSOR_PAYMENT_POOL_ADDR` | **yes** | — | `PaymentPool` contract address |
Expand All @@ -82,13 +83,20 @@ pool up from the treasury whenever its remaining balance falls below
## The `decdn-sponsored` flow

The website shows one command per model, with the model's BLAKE3 hash from
`models.json`:
`models.json`. On macOS and Linux:

```bash
curl -fsSL https://up.decdn.org/decdn.sh | sh -s -- pull b3:<hash>
```

1. The installer served at `GET /decdn.sh` (`assets/decdn.sh`) installs the
On Windows (x64 and ARM64), in PowerShell:

```powershell
irm https://up.decdn.org/decdn.ps1 | iex; decdn-sponsored pull b3:<hash>
```

1. The installer served at `GET /decdn.sh` (`assets/decdn.sh`), or its
PowerShell twin at `GET /decdn.ps1` (`assets/decdn.ps1`), installs the
`decdn` and `decdn-sponsored` binaries and writes `~/.decdn/sponsor.toml`
with the gateway's contract addresses and RPC URL filled in. Any
arguments are passed on to `decdn-sponsored`. Running it again is
Expand All @@ -112,7 +120,8 @@ curl -fsSL https://up.decdn.org/decdn.sh | sh -s -- pull b3:<hash>
a new captcha.

The `~/.decdn/sponsor.toml` schema is a hard contract between the installer
(`assets/decdn.sh`) and the wrapper (`crates/wrapper/src/config.rs`): field
(`assets/decdn.sh`, `assets/decdn.ps1`) and the wrapper
(`crates/wrapper/src/config.rs`): field
names must match exactly. Current fields: `gateway_base`, `decdn_bin`,
`data_dir`, `rpc_url`, `payment_pool`, `capacity_bond` (optional),
`slash_judge` (optional), `chain_id`. Unknown fields are ignored.
Expand Down
101 changes: 101 additions & 0 deletions crates/server/assets/decdn.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# decdn-sponsored installer for Windows - served by sponsord at GET /decdn.ps1,
# with the placeholders below substituted server-side (see
# crates/server/src/http/installer.rs) from ServerConfig. The POSIX twin is
# assets/decdn.sh; the two write the same profile.
#
# Install, then download:
# irm <gateway>/decdn.ps1 | iex; decdn-sponsored pull b3:<hash>
# Or pass the arguments through in one call:
# & ([scriptblock]::Create((irm <gateway>/decdn.ps1))) pull b3:<hash>
#
# Everything runs inside one script block, so `iex` leaves no variables or
# preference changes behind in the caller's session, and nothing here calls
# `exit` (which would close the caller's window). The one process-wide
# setting it touches, the TLS protocol list, is restored on the way out.
& {
$ErrorActionPreference = 'Stop'
# Invoke-WebRequest's progress bar slows downloads sharply in Windows
# PowerShell 5.1.
$ProgressPreference = 'SilentlyContinue'
$PriorProtocol = [Net.ServicePointManager]::SecurityProtocol
[Net.ServicePointManager]::SecurityProtocol =
$PriorProtocol -bor [Net.SecurityProtocolType]::Tls12
try {

$Gateway = '{{GATEWAY_BASE}}'
$RpcUrl = '{{RPC_URL}}'
$PaymentPool = '{{PAYMENT_POOL}}'
$CapacityBond = '{{CAPACITY_BOND}}'
$ChainId = '{{CHAIN_ID}}'

$BinDir = Join-Path $env:LOCALAPPDATA 'decdn\bin'
$DecdnDir = Join-Path $HOME '.decdn'
New-Item -ItemType Directory -Force -Path $BinDir, $DecdnDir | Out-Null

# The OS architecture, not the process's: x64 PowerShell under emulation on
# an ARM64 machine reports AMD64 in PROCESSOR_ARCHITECTURE.
$OsArch = try {
[System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString()
} catch {
$env:PROCESSOR_ARCHITECTURE
}
$Arch = switch ($OsArch) {
{ $_ -in 'X64', 'AMD64' } { 'x86_64' }
{ $_ -in 'Arm64', 'ARM64' } { 'aarch64' }
default { throw "decdn: unsupported Windows architecture: $OsArch" }
}

# 1. Install the decdn and decdn-sponsored binaries.
#
# NOTE: release hosting (GET /dl/<bin>-<os>-<arch>) is not wired up on the
# gateway yet; until it is, this step fails with a 404.
foreach ($bin in 'decdn', 'decdn-sponsored') {
Write-Host "Installing $bin..."
Invoke-WebRequest -UseBasicParsing -Uri "$Gateway/dl/$bin-windows-$Arch.exe" `
-OutFile (Join-Path $BinDir "$bin.exe")
}

# 2. Put the binaries on PATH: permanently for the user, and right away for
# this session so the next command on the same line finds them.
$UserPath = [Environment]::GetEnvironmentVariable('Path', 'User')
if (-not (($UserPath -split ';') -contains $BinDir)) {
$NewPath = if ($UserPath) { "$BinDir;$UserPath" } else { $BinDir }
[Environment]::SetEnvironmentVariable('Path', $NewPath, 'User')
}
if (-not (($env:Path -split ';') -contains $BinDir)) {
$env:Path = "$BinDir;$env:Path"
}

# 3. Write the wrapper's profile. Field names and shape MUST match
# crates/wrapper/src/config.rs's `Profile` struct exactly. Paths use
# forward slashes, which Windows accepts and TOML strings need no
# escaping for. Each download gets its own throwaway key under data_dir.
$Fwd = { param($p) $p.Replace('\', '/') }
$DecdnBin = & $Fwd (Join-Path $BinDir 'decdn.exe')
$DataDir = & $Fwd (Join-Path $DecdnDir 'sponsored')
$ProfileToml = @"
gateway_base = "$Gateway"
decdn_bin = "$DecdnBin"
data_dir = "$DataDir"
rpc_url = "$RpcUrl"
payment_pool = "$PaymentPool"
capacity_bond = "$CapacityBond"
chain_id = $ChainId
"@
# UTF-8 without a byte-order mark: Windows PowerShell 5.1's `-Encoding UTF8`
# writes one, and a BOM is not valid TOML.
[IO.File]::WriteAllText((Join-Path $DecdnDir 'sponsor.toml'), $ProfileToml,
(New-Object System.Text.UTF8Encoding $false))

if ($args.Count -gt 0) {
& (Join-Path $BinDir 'decdn-sponsored.exe') @args
return
}

Write-Host ''
Write-Host 'decdn-sponsored is ready. Download with:'
Write-Host ' decdn-sponsored pull b3:<hash> [-o <dir>]'
} finally {
[Net.ServicePointManager]::SecurityProtocol = $PriorProtocol
}
} @args
12 changes: 9 additions & 3 deletions crates/server/assets/decdn.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/bin/sh
# decdn-sponsored installer - served by sponsord at GET /decdn.sh, with the
# decdn-sponsored installer for macOS/Linux - served by sponsord at
# GET /decdn.sh, with the
# placeholders below substituted server-side (see
# crates/server/src/http/installer.rs) from ServerConfig, so nothing here
# needs an environment variable to run.
# needs an environment variable to run. The Windows twin is assets/decdn.ps1;
# the two write the same profile.
#
# Arguments, when given, are passed to decdn-sponsored after installing, so
# one line installs and downloads:
Expand All @@ -21,7 +23,11 @@ DECDN_DIR="${HOME}/.decdn"
mkdir -p "$BINDIR" "$DECDN_DIR"

OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m)"
case "$(uname -m)" in
x86_64 | amd64) ARCH=x86_64 ;;
arm64 | aarch64) ARCH=aarch64 ;;
*) echo "decdn: unsupported architecture: $(uname -m)" >&2; exit 1 ;;
esac

# 1. Install the decdn and decdn-sponsored binaries.
#
Expand Down
Loading
Loading