Prerequisites

🐍

Python 3.11+

Required for all node types. Install via your system package manager or pyenv.

🔥

PyTorch 2.0+

With CUDA support for GPU nodes. CPU works for registry and daemon nodes.

🤖

A Model

HuggingFace-compatible models with supported UNFED runtime architecture. We recommend ./models/Qwen2.5-Coder-0.5B-Instruct for text and HuggingFaceTB/SmolVLM-256M-Instruct for multimodal testing.

Install Python dependencies
pip install torch safetensors grpcio grpcio-tools protobuf
pip install transformers  # for model downloading
pip install fastapi uvicorn websockets  # for web dashboard
pip install web3  # for on-chain staking (optional)

Per-Node System Requirements

Node Type CPU RAM GPU Notes
Registry1 vCPU1-2 GBNoFor larger pools use 2 vCPU / 4 GB.
Daemon2 vCPU4 GBNoPersistent disk recommended for SQLite chain DB.
MPC Node A4 vCPU8-16 GBRecommendedEntry privacy node; usually the heavier MPC side.
MPC Node B4 vCPU8-16 GBRecommendedPeer privacy node; keep low latency to Node A.
Compute (text shard)4+ vCPU8-16 GBRecommendedOne process per shard index.
Vision shard4+ vCPU12-24 GBPreferredNeeded for multimodal image paths.

Step 1: Split a Model

Use unfed-tools to inspect and split a model into shards.

A

Inspect the model

See what you're working with: architecture, layer count, parameter count.

python -m tools inspect /path/to/model
B

Split into shards

Split the model into N text shards (and optionally a vision shard for multimodal models). This creates a shards/ directory with individual weight files and a v2 manifest.

python -m tools split /path/to/model \
  --output shards_smolvlm \
  --num-text-shards 2
C

Verify the split

Confirm that the shards are valid and the manifest is correct.

python -m tools verify shards_smolvlm

Model compatibility: UNFED currently targets decoder-style text models that map to the generic runtime blocks (Qwen/Llama/Mistral-style) and vision-language models via the supported split paths (for example SmolVLM). New models should pass tools inspect + tools verify and a short prompt sanity test before production rollout.

Practical status: the local testnet flow in this repo is validated with ./models/Qwen2.5-Coder-0.5B-Instruct (text) and HuggingFaceTB/SmolVLM-256M-Instruct (vision-language).

Step 2: Start the Registry

The registry is the cluster coordinator — start it first.

Create a cluster config
{
  "name": "My UNFED Pool",
  "chain_rpc_url": "http://localhost:8545",
  "escrow_contract_address": "0x<from deployed.env>",
  "staking_token_address": "0x<from deployed.env>",
  "operator_private_key": "0x<operator private key>",
  "daemon_required_count": 1
}

Token name is not required: you only provide staking_token_address. The registry/escrow reads token metadata (like symbol/name) directly from the ERC-20 contract on-chain.

Start the registry
python -m network.registry_server \
  --port 50050 \
  --cluster-config cluster_config.json

Important: this starts only the registry service (gRPC). If you also want the browser UI for easier querying, start the web server separately:

python -m web.server --port 8080 --registry localhost:50050

Policy scope: cluster_config.json is loaded by the registry process at startup. Quorum knobs like daemon_required_count are registry-local policy.

Stake amount control: registry-side default_min_stake defines the minimum stake required for node admission (compute/vision/MPC). If a node is below this threshold, registration is rejected until re-staked.

On-chain admission auth (new): when on-chain escrow is enabled, compute/vision/MPC/daemon registration must include an EVM signature over the canonical registration payload (node identity, address, model, shard, share-signing key, timestamp, nonce). The recovered signer must match node_id.

# Recommended: store stake key in a file (OPSEC)
umask 077
printf '%s' "0x<staked wallet private key>" > ~/.unfed/node_stake.key
export UNFED_STAKE_EVM_PRIVATE_KEY_FILE=~/.unfed/node_stake.key

Tip: The registry serves the model manifest to nodes automatically. Point --shards-dir at the split output if you want manifest auto-discovery.

Step 3: Start the Daemon

The chain daemon records compute shares and produces settlement blocks.

export UNFED_STAKE_EVM_PRIVATE_KEY_FILE=~/.unfed/daemon_stake.key
python -m network.daemon_node \
  --port 50070 \
  --registry localhost:50050 \
  --eth-address 0x<daemon staked wallet address> \
  --db ~/.unfed/chain.db

The daemon connects to the registry, syncs share chain state, and begins accepting shares from compute nodes. Settlement blocks are produced approximately every 10 seconds.

Step 4: Node-Type Startup Tutorials

Pick the node type you want to run and follow its exact startup flow.

Strict startup order: start nodes in this order to avoid readiness and admission failures.

  1. Registry
  2. Daemon
  3. MPC Node B, then MPC Node A (for full_output_2pc and input MPC)
  4. All required compute shards (and vision shard if multimodal)
  5. Web UI (optional)

Readiness gate: if your client policy requires MPC (for example UNFED_REQUIRE_MPC=1), model status stays INCOMPLETE until at least one healthy input MPC pair and one healthy output MPC pair are registered (the same A/B pair can advertise both).

Reproducibility rule: in on-chain mode, stake each node wallet before startup and always pass both:

  • UNFED_STAKE_EVM_PRIVATE_KEY_FILE (or UNFED_STAKE_EVM_PRIVATE_KEY)
  • --eth-address matching that staked wallet address

Registry Node

Use this for cluster coordination, admission, and adjudication.

Start command
python -m network.registry_server \
  --port 50050 \
  --cluster-config cluster_config.json

Tutorial: start this first, then start daemon and workers. If you want a convenient client UI, also run web.server in a separate process.

Daemon Node

Use this for sharechain persistence, block production, and fee telemetry.

Start command
export UNFED_STAKE_EVM_PRIVATE_KEY_FILE=~/.unfed/daemon_stake.key
python -m network.daemon_node \
  --port 50070 \
  --registry localhost:50050 \
  --eth-address 0x<daemon staked wallet address> \
  --db ~/.unfed/chain.db

Tutorial: start after registry, before compute/MPC nodes.

Compute Node (Text Shard)

Use this for normal text shard execution. Run one process per shard index.

Shard 0 example
export UNFED_STAKE_EVM_PRIVATE_KEY_FILE=~/.unfed/node0_stake.key
python -m node.server \
  --shard-index 0 \
  --port 50051 \
  --model-type smolvlm \
  --shards-dir shards_smolvlm \
  --registry localhost:50050 \
  --eth-address 0xNodeAddress1
Shard 1 example
export UNFED_STAKE_EVM_PRIVATE_KEY_FILE=~/.unfed/node1_stake.key
python -m node.server \
  --shard-index 1 \
  --port 50052 \
  --model-type smolvlm \
  --shards-dir shards_smolvlm \
  --registry localhost:50050 \
  --eth-address 0xNodeAddress2

Tutorial: start all required shard indices for your model.

Vision Node (Multimodal)

Use this only for multimodal pipelines that require a vision encoder path.

Vision shard example
export UNFED_STAKE_EVM_PRIVATE_KEY_FILE=~/.unfed/vision_stake.key
python -m node.server \
  --shard-index 0 \
  --port 50060 \
  --model-type smolvlm_vision \
  --shards-dir shards_smolvlm \
  --registry localhost:50050 \
  --eth-address 0xVisionNodeAddress

Tutorial: run alongside text compute nodes for image + text requests.

MPC Pair (Node B then Node A)

Use this when you want shard-0 privacy via secret sharing.

Start Node B first
# Start MPC Node B first
export UNFED_STAKE_EVM_PRIVATE_KEY_FILE=~/.unfed/mpcb_stake.key
python -m network.mpc_shard0 \
  --role B --port 50063 \
  --peer localhost:50061 \
  --registry localhost:50050 \
  --shards-dir shards_smolvlm \
  --eth-address 0xMPCBAddress

# Then start MPC Node A
export UNFED_STAKE_EVM_PRIVATE_KEY_FILE=~/.unfed/mpca_stake.key
python -m network.mpc_shard0 \
  --role A --port 50061 \
  --peer localhost:50063 \
  --registry localhost:50050 \
  --shards-dir shards_smolvlm \
  --eth-address 0xMPCAddress

Tutorial: once MPC is running, route shard-0 traffic to MPC A.

Public Node Hardening (All Node Types)

Before exposing any node publicly, run preflight and enforce TLS.

python -m scripts.testnet_preflight node \
  --advertise 203.0.113.42:50051 \
  --tls-cert /path/to/server.crt \
  --tls-key /path/to/server.key

Tutorial: treat preflight failures as NO-GO for rollout.

Detailed config docs moved: to keep this page focused on startup, full per-node config documentation now lives in a dedicated route with value-by-value explanations.

Open Config Reference → for registry, daemon, compute, vision, and MPC config fields.

Staking note: if on-chain staking is enabled, each compute/vision/MPC/daemon node must meet min_stake before registration is accepted.

Continuous enforcement: stake eligibility is re-checked during live operation. Nodes that fall below eligibility are excluded from discovery and health views until re-staked.

Privacy note: If you run public-facing UNFED nodes and do not want your home/office IP exposed, consider operating behind a VPN, proxy, or hosted relay endpoint. Your node address can be discovered by other participants through registry/network activity.

Step 5: Open the Dashboard

The web UI for sending prompts and monitoring the network.

python -m web.server \
  --port 8080 \
  --registry localhost:50050

Open http://localhost:8080 in your browser. You can type prompts, attach images (for multimodal models), and watch tokens stream in real-time. The dashboard shows per-request cost based on the cluster's token pricing.

Security defaults: the dashboard now binds to 127.0.0.1 by default (not 0.0.0.0), demo auth is disabled by default, and wallet auth is expected for chat/faucet flows.

Faucet default: faucet is disabled unless UNFED_FAUCET_ENABLED=1. When enabled, it requires an authenticated wallet session by default (UNFED_FAUCET_REQUIRE_AUTH=1).

Step 6: Run Preflight

Use Go/No-Go checks before exposing services.

# Web service checks
python -m scripts.testnet_preflight web --host 127.0.0.1

# Public node checks (TLS required for public advertise)
python -m scripts.testnet_preflight node \
  --advertise 203.0.113.42:50051 \
  --tls-cert /path/to/server.crt \
  --tls-key /path/to/server.key

# Runtime checks against running web/registry stack
python -m scripts.testnet_preflight runtime --web-url http://127.0.0.1:8080

# Optional one-command profile check
./scripts/run_public_testnet_checklist.sh

If any check fails, treat the result as NO-GO and fix the reported issue before rollout.

Output privacy modes: use he_compute_mode with off, decode_client_sample, or full_output_2pc. The legacy server_sample mode is retired.

Vision MPC validation: run the lightweight pytest path by default, then opt into heavy E2E when ready.

# Default: unit-level vision checks (pytest-friendly)
python -m pytest tests/test_vision.py -q

# Heavy E2E vision network check (requires model/shards and more resources)
RUN_VISION_E2E=1 python -m pytest tests/test_vision.py -q

Cheating + Staking Model

What happens when nodes cheat, and why staking is required for operators.

Common cheating cases

  • Skipping layers to save compute
  • Returning corrupted activations or biased logits
  • Sending invalid HE/MPC-bound artifacts
  • Trying to pass forged forward-attestation metadata

Detection and dispute intake are handled by registry-native adjudication and evidence-bound report paths.

Fraud Proof Details →

Economic consequence flow

  • Node stakes to become eligible
  • Suspicion report is submitted and validated
  • Registry applies slashing policy when confirmed
  • Node below min_stake is excluded until re-staked

This is the core incentive design: honest compute remains profitable, cheating becomes expensive.

Staking Model → Slashing Flow →

Operator checklist: before public rollout, confirm your cluster_config.json sets sensible values for default_min_stake, default_slash_fraction, challenge_window_seconds, and he_dispute_rollout_stage.

After startup, verify readiness:

python -m client.client --list-models --registry localhost:50050

Expected: your target model shows Status: READY before serving users.

On-Chain Staking Setup

For local testing with Foundry's Anvil.

1

Install Foundry

curl -L https://foundry.paradigm.xyz | bash
foundryup
2

Start Anvil (local chain)

anvil --block-time 2

This starts a local Ethereum node with pre-funded accounts.

3

Deploy contracts

# Deploy ERC-20 token
forge create contracts/UnfedToken.sol:UnfedToken \
  --rpc-url http://localhost:8545 \
  --private-key $DEPLOYER_KEY

# Deploy escrow contract
forge create contracts/UnfedEscrow.sol:UnfedEscrow \
  --rpc-url http://localhost:8545 \
  --private-key $DEPLOYER_KEY \
  --constructor-args $TOKEN_ADDRESS $OPERATOR_ADDRESS
4

Fund and stake nodes

# Transfer tokens to a node address
cast send $TOKEN_ADDRESS \
  "transfer(address,uint256)" $NODE_ADDRESS 200000000000000000000 \
  --rpc-url http://localhost:8545 --private-key $DEPLOYER_KEY

# Approve escrow to spend tokens
cast send $TOKEN_ADDRESS \
  "approve(address,uint256)" $ESCROW_ADDRESS 200000000000000000000 \
  --rpc-url http://localhost:8545 --private-key $NODE_KEY

# Stake
cast send $ESCROW_ADDRESS \
  "stake(uint256)" 200000000000000000000 \
  --rpc-url http://localhost:8545 --private-key $NODE_KEY

Convenience: The start_smolvlm_staked.sh script automates the entire process: Anvil startup, contract deployment, token distribution, staking, and launching all nodes. Check the repository for the full script.

What's Next

Learn the Architecture

Understand how sharding, MPC, and onion routing work together.

Architecture →

Explore Economics

Dive into pricing, staking, slashing, and reward schemes.

Economics →

Understand the Protocol

Share chains, verification tickets, fraud proofs, and settlements.

Protocol →