ioswarm

package
v2.3.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 25, 2026 License: Apache-2.0 Imports: 44 Imported by: 0

README

ioSwarm Coordinator

The ioSwarm coordinator runs as a module inside iotex-core on a delegate node. It distributes transaction validation to a swarm of agents over gRPC, compares agent results against on-chain execution (shadow mode), and settles rewards on-chain via the AgentRewardPool contract.

IIP-58: ioSwarm — Distributed AI Execution Layer for IoTeX Delegates

Architecture

Delegate Machine
┌──────────────────────────────────────────────────┐
│  iotex-core (ioswarm-v2.3.5 branch)              │
│  ├── actpool         ← pending transactions      │
│  ├── statedb         ← account/contract state    │
│  └── ioswarm/        ← coordinator module        │
│       ├── Poll actpool for pending txs            │
│       ├── SimulateAccessList → prefetch state     │
│       ├── Build TaskPackages (tx + state)         │
│       ├── Dispatch to agents via gRPC streaming   │
│       ├── Collect results, shadow-compare         │
│       ├── Stream state diffs to L4 agents         │
│       └── On-chain reward settlement              │
│                         │                         │
│  gRPC :14689            │  HTTP :14690            │
└─────────────────────────┼─────────────────────────┘
                          │
          ┌───────────────┼───────────────┐
          │               │               │
       Agent-1         Agent-2         Agent-N
       L3 stateless    L4 stateful     anywhere

Delegate Guide: Enable ioSwarm on Your Node

Any IoTeX delegate can opt-in to ioSwarm with zero consensus changes. Your delegate continues to sign blocks exactly as before — ioSwarm adds a sidecar that distributes execution work to agents and rewards them on-chain.

Step 1 — Pull the ioSwarm-enabled image
docker pull raullen/iotex-core:ioswarm-v16

Or build from source (ioswarm-v2.3.5 branch):

cd iotex-core && git checkout ioswarm-v2.3.5
docker buildx build --platform linux/amd64 -t your-image:tag .
Step 2 — Add ioSwarm config to your config.yaml
ioswarm:
  enabled: true
  grpcPort: 14689                # agent gRPC connections
  swarmApiPort: 14690            # HTTP monitoring API (0 to disable)
  maxAgents: 100
  taskLevel: "L4"                # L1, L2, L3, or L4
  shadowMode: true               # compare agent results vs on-chain (recommended)
  pollIntervalMs: 1000           # actpool poll interval
  masterSecret: "<your-secret>"  # HMAC master secret for agent auth (hex string)
  delegateAddress: ""            # delegate address (auto-detected if empty)
  epochRewardIOTX: 0.5           # IOTX reward per epoch

  # On-chain reward settlement (optional — omit to run without rewards)
  rewardContract: "0x236CBF52125E68Db8fA88b893CcaFB2EE542F2d9"
  rewardSignerKey: "<hex-key>"   # coordinator hot wallet private key (hex, no 0x prefix)

  # State diff for L4 agents
  diffStoreEnabled: true
  diffStorePath: "/var/data/statediffs.db"

  # Reward parameters
  reward:
    delegateCutPct: 10           # delegate keeps 10% of epoch reward
    epochBlocks: 1               # 1 block per epoch (= 10s at IoTeX 10s block time)
    minTasksForReward: 1         # minimum tasks to qualify for reward
    bonusAccuracyPct: 99.5       # accuracy threshold for bonus multiplier
    bonusMultiplier: 1.2         # weight multiplier for high-accuracy agents

Config field reference:

Field Required Description
masterSecret Yes Hex string used to derive agent API keys via HMAC-SHA256
taskLevel Yes Highest validation level to dispatch. L4 enables state diff streaming
rewardContract For rewards AgentRewardPool v2 contract address on IoTeX mainnet
rewardSignerKey For rewards Private key of the coordinator hot wallet (hex, no 0x prefix). This wallet calls depositAndSettle() and must have IOTX balance
diffStoreEnabled For L4 Enable persistent diff storage so L4 agents can catch up after disconnect
diffStorePath For L4 Path to BoltDB file for diff storage
epochBlocks Yes Blocks per reward epoch. 1 = every block (10s), 3 = every 30s
shadowMode Recommended When true, compares agent results against on-chain receipts for accuracy tracking
Step 3 — TLS + networking

Important: Do NOT expose port 14689 directly to the public internet. HMAC tokens are sent in gRPC metadata and must be protected by TLS.

Recommended architecture (TLS termination via reverse proxy):

Agent (--tls) → Load Balancer (:443 TCP) → nginx (TLS terminate) → gRPC (:14689 localhost)
# Bind gRPC and HTTP to localhost only — not accessible from outside
docker run -d --name iotex \
  -p 4689:4689 -p 14014:14014 \
  -p 127.0.0.1:14689:14689 -p 127.0.0.1:14690:14690 \
  -v /data:/var/data \
  -v /etc/iotex/config.yaml:/etc/iotex/config_override.yaml \
  raullen/iotex-core:ioswarm-v16

# Use nginx or a cloud load balancer to terminate TLS on :443
# and proxy to localhost:14689 (gRPC) / localhost:14690 (HTTP)
#
# IMPORTANT: Set grpc_read_timeout to at least 3600s for gRPC streaming.
# The default 60s causes GetTasks streams to disconnect with 504 errors.
# Example nginx config:
#   location / {
#       grpc_pass grpc://127.0.0.1:14689;
#       grpc_read_timeout 3600s;
#       grpc_send_timeout 3600s;
#       client_body_timeout 3600s;
#   }

# Verify coordinator is running
curl http://localhost:14690/swarm/status

For local development / testing without TLS, you can bind directly:

docker run -d --name iotex \
  -p 4689:4689 -p 14014:14014 -p 14689:14689 -p 14690:14690 \
  ...
# Agents connect with: --coordinator=host:14689 --tls=false
Step 4 — Deploy AgentRewardPool contract (optional)

Skip this step if you use the shared mainnet contract (0x236CBF52125E68Db8fA88b893CcaFB2EE542F2d9).

To deploy your own:

./ioswarm-agent deploy \
  --private-key=<deployer-key> \
  --coordinator=0x<coordinator-hot-wallet>

Set the returned contract address in rewardContract.

Step 5 — Export L4 snapshot (for L4 agents)

L4 agents need a state snapshot to bootstrap. The snapshotexporter tool reads trie.db via iotex-core's KVStore layer (handles both BoltDB and PebbleDB).

# Build the snapshot exporter (requires CGO for crypto)
docker run --rm --platform linux/amd64 \
  -v $(pwd):/go/apps/iotex-core -w /go/apps/iotex-core \
  golang:1.23.0-alpine sh -c \
  'apk add --no-cache gcc musl-dev linux-headers git && \
   CGO_ENABLED=1 go build -ldflags "-extldflags \"-static\"" \
   -o bin/snapshotexporter ./tools/snapshotexporter/'

# Export Account+Code only (~1 min, ~209 MB — sufficient for L4)
# NOTE: trie.db must NOT be locked by a running iotex-server.
# Stop iotex first, or copy trie.db while stopped.
docker stop iotex
cp /var/data/trie.db /var/data/trie.db.snap
docker start iotex
./bin/snapshotexporter --source /var/data/trie.db.snap --namespaces Account,Code --output acctcode.snap.gz

# Export full state including Contract trie (~1 hour, ~1.4 GB)
./bin/snapshotexporter --source /var/data/trie.db.snap --output baseline.snap.gz

# Host it for agent download (CDN, object store, or file server)

Public snapshot: https://ts.iotex.me — updated daily via cron.

Daily cron setup (automates the above):

# /root/export-snapshot.sh — runs at 04:00 UTC daily
# 1. docker stop iotex → cp trie.db → docker start iotex (~2 min downtime)
# 2. snapshotexporter --namespaces Account,Code (~1 min)
# 3. rsync to snapshot server
# 4. Total: ~4 min, of which ~2 min is delegate downtime

crontab -e
# Add: 0 4 * * * /root/export-snapshot.sh

Why Account+Code only? Contract storage (MPT trie nodes, 80M+ entries) takes ~1 hour to export. L4 agents sync Contract state incrementally via StreamStateDiffs after loading the Account+Code snapshot. The DiffStore retains 10,000 blocks (~27 hours), so a daily snapshot keeps agents within the catch-up window.

Step 6 — Generate agent API keys and onboard agents

Keys are HMAC-SHA256 derived from the master secret:

key = "iosw_" + hex(HMAC-SHA256(masterSecret, agentID))

Share the key + agent ID with each agent operator. They will use them to connect:

ioswarm-agent \
  --coordinator=<your-delegate-ip>:14689 \
  --agent-id=<agent-id> \
  --api-key=iosw_<key> \
  --wallet=<agent-reward-wallet>

See the ioswarm-agent README for full agent setup instructions.

Step 7 — Monitor your swarm
# Public stats (CORS-enabled, no auth — safe to expose to community dashboards)
curl http://localhost:14690/api/stats

# Swarm status (detailed)
curl http://localhost:14690/swarm/status

# Connected agents
curl http://localhost:14690/swarm/agents

# Shadow accuracy
curl http://localhost:14690/swarm/shadow

# Agent leaderboard
curl http://localhost:14690/swarm/leaderboard
Public Stats API

GET /api/stats returns a JSON summary designed for community dashboards and landing pages. It requires no authentication and includes CORS headers (Access-Control-Allow-Origin: *).

{
  "active_agents": 47,
  "agents_by_level": {"L3": 35, "L4": 12},
  "tasks_dispatched": 128473,
  "tasks_received": 128470,
  "shadow_accuracy": 99.87,
  "shadow_compared": 100000,
  "shadow_matched": 99876,
  "current_epoch": 24,
  "epoch_tasks": 4562,
  "epoch_accuracy": 99.83,
  "task_level": "L4",
  "uptime": "24h12m30s",
  "updated_at": 1710340200
}

Response is cached for 30 seconds (Cache-Control: public, max-age=30).

Per-Agent Rewards API

GET /api/rewards?agent=<agent-id> returns reward history for a specific agent. No authentication required, CORS-enabled.

{
  "agent_id": "beta-008",
  "history": [
    {"epoch": 42, "amount_iotx": 0.045, "tasks": 120, "accuracy_pct": 99.8, "rank": 1, "bonus_applied": true},
    {"epoch": 41, "amount_iotx": 0.038, "tasks": 95, "accuracy_pct": 98.5, "rank": 3, "bonus_applied": false}
  ],
  "totals": {"earned_iotx": 0.083, "total_tasks": 215, "avg_accuracy": 99.15}
}
What happens after you enable ioSwarm
  1. Zero risk: Your delegate continues signing blocks exactly as before. ioSwarm runs in shadow mode — agent results are compared but never used for block production.
  2. Agents connect: They receive transaction validation tasks via gRPC streaming.
  3. Rewards flow: Every epoch (~10s), the coordinator calls depositAndSettle() on the AgentRewardPool contract, distributing IOTX to agents proportional to their work.
  4. Shadow accuracy: You can monitor agent accuracy in real-time via /swarm/shadow. If all agents disappear, the delegate falls back to running solo.

Validation Levels

Level What the agent does State provided by coordinator
L1 Signature verification None
L2 + Nonce/balance checks AccountSnapshot (sender, receiver)
L3 + Full EVM execution Account snapshots + contract code + storage slots (via SimulateAccessList)
L4 Same as L3, but agent uses its own local state (BoltDB) State diffs streamed in real-time
L3 State Prefetch: SimulateAccessList

For contract calls, the coordinator runs a read-only EVM simulation (similar to eth_createAccessList) to discover every storage slot the transaction will access. These slots are sent with the task so the agent has complete state for deterministic EVM execution.

Mainnet result: 230+ transactions, 100% shadow accuracy (agent results identical to on-chain execution).

Key implementation details:

  • Uses evm.SimulateAndCollectAccessList() in adapter.go
  • Requires full blockchain context (bc.Context()) including BaseFee, GetBlockHash, GetBlockTime
  • All io1 addresses are converted to 0x hex format before sending to agents (go-ethereum only accepts 20-byte hex addresses)
  • BlockContext.Random must be set (even to zero hash) for Shanghai/Cancun opcode support
L4 State Sync

L4 agents maintain a full copy of IoTeX EVM state locally (BoltDB). This allows fully independent transaction validation without relying on coordinator-provided state.

How it works:

  1. Bootstrap: Agent loads an IOSWSNAP snapshot (~209 MB for Account+Code, ~1.4 GB for full state including Contract trie nodes)
  2. State diffs: After each block commit, coordinator captures the ordered changeset from workingset.SerializeQueue() and streams to agents via StreamStateDiffs gRPC
  3. Agent applies: diffs to local BoltDB, maintaining state in sync with the delegate
  4. Recovery: On disconnect, agent requests missing diffs from coordinator's DiffStore (last 1000 blocks retained)

Production results (mainnet, March 2026):

  • Shadow accuracy: 100% — nonce race false positives are automatically excluded (same-sender tx consumed nonce between dispatch and commit)
  • Kill/restart recovery: <200ms from BoltDB state store, no snapshot reload needed
  • Memory: ~679 MiB, CPU: ~24.5%
  • State store: ~931 MB BoltDB after sync

State data needed (3 of 10+ namespaces):

Namespace Content Size Estimate
Account All accounts: nonce, balance, codeHash ~50-100 MB
Code Contract bytecode, keyed by codeHash ~50-100 MB
Contract Contract storage (MPT trie nodes) ~200 MB - 1 GB
IOSWSNAP Snapshot Format

Binary format for bootstrapping L4 agents:

header:  magic("IOSWSNAP") + version(uint32) + height(uint64)
entries: [marker(0x01) + ns_len(uint8) + ns + key_len(uint32) + key + val_len(uint32) + val]*
end:     marker(0x00)
trailer: count(uint64) + sha256(32 bytes) + end_magic("SNAPEND\0")

Export tool: ioswarm/cmd/l4baseline reads trie.db (BoltDB) and outputs gzip-compressed IOSWSNAP.

# Stats only
go run ./ioswarm/cmd/l4baseline --source trie.db --stats

# Export Account+Code only (~209 MB compressed)
go run ./ioswarm/cmd/l4baseline --source trie.db --output acctcode.snap.gz --namespaces Account,Code

# Export full baseline (~1.4 GB compressed)
go run ./ioswarm/cmd/l4baseline --source trie.db --output baseline.snap.gz

On-Chain Reward Settlement

Every epoch (configurable, default 1 block = 10s), the coordinator:

  1. Calculates each agent's weight: tasks x (accuracy >= 99.5% ? 1.2 : 1.0)
  2. Calls depositAndSettle(agents[], weights[]) on the AgentRewardPool contract, sending epochReward x (1 - delegateCut) as IOTX value
  3. The contract uses F1 (cumulative reward-per-weight) algorithm for O(1) proportional distribution
  4. Agents call claim() at any time to withdraw accumulated rewards

AgentRewardPool v2 contract (mainnet): 0x236CBF52125E68Db8fA88b893CcaFB2EE542F2d9

Source in ioswarm-agent/contracts/.

E2E test results (mainnet, March 2026):

  • Single agent payout: PASS
  • Multi-agent proportional split: PASS (50/50)
  • 10 agents x 5 epochs: PASS (0.225 IOTX each)
  • Dynamic join/leave: PASS (contract balance = 0 after all claims)
  • MinTasks threshold: PASS (weight=0 gets 0)
  • Delegate cut: PASS (10% retained, 90% to agents)

gRPC Protocol

service IOSwarm {
  rpc Register(RegisterRequest) returns (RegisterResponse);
  rpc GetTasks(GetTasksRequest) returns (stream TaskBatch);       // server push
  rpc SubmitResults(BatchResult) returns (SubmitResponse);
  rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
  rpc StreamStateDiffs(StateDiffRequest) returns (stream StateDiffBatch);  // L4
}

Agents connect via Register, authenticate with HMAC key, then open a server-streaming GetTasks call. Results flow back via SubmitResults. Epoch payouts are delivered in HeartbeatResponse.

L4 agents additionally open StreamStateDiffs to receive per-block state mutations. The coordinator's StateDiffBroadcaster fans out diffs from a ring buffer, and DiffStore persists recent diffs for catch-up.

Integration with iotex-core

The coordinator is wired into iotex-core via server/itx/server.go:

// In newServer():
if cfg.IOSwarm.Enabled {
    actPoolAdapter := ioswarm.NewActPoolAdapter(cs.ActPool(), cs.Blockchain())
    stateAdapter := ioswarm.NewStateReaderAdapter(cs.StateFactory(), cs.Blockchain(), cs.Genesis())
    svr.ioswarmCoord = ioswarm.NewCoordinator(cfg.IOSwarm, actPoolAdapter, stateAdapter)
}

// In Start():
if svr.ioswarmCoord != nil {
    svr.ioswarmCoord.Start(ctx)
}

Two interfaces decouple the coordinator from iotex-core internals:

type ActPoolReader interface {
    PendingActions() []*PendingTx
    BlockHeight() uint64
}

type StateReader interface {
    AccountState(addr string) (*pb.AccountSnapshot, error)
    GetCode(addr string) ([]byte, error)
    GetStorageAt(addr, slot string) (string, error)
    SimulateAccessList(from, to string, data []byte, value string, gasLimit uint64) (map[string][]string, error)
}

State diff integration hooks into stateDB.PutBlock():

// In server/itx/server.go:
svr.ioswarmCoord.SetupStateDiffCallback(cs.StateFactory())
// Callback chain: stateDB.Finalize() → diffCallback → coordinator.ReceiveStateDiff()
//   → DiffStore.Append() + StateDiffBroadcaster.Publish()
//   → gRPC StreamStateDiffs to all connected L4 agents

Source Layout

File Purpose
config.go Config struct with YAML tags, defaults
coordinator.go Main loop: poll → prefetch → build tasks → dispatch → shadow compare
adapter.go ActPoolAdapter + StateReaderAdapter (wraps iotex-core internals)
prefetcher.go Concurrent state prefetch + SimulateAccessList for EVM access lists
registry.go Agent lifecycle: register, heartbeat, evict stale, HMAC auth
scheduler.go Round-robin dispatch to agents via buffered channels
shadow.go Compare agent results vs actual block receipts, track accuracy
grpc_handler.go gRPC service: Register, GetTasks (server-stream), SubmitResults, Heartbeat, StreamStateDiffs
auth.go HMAC-SHA256 agent authentication
swarm_api.go HTTP API for monitoring (:14690), including public /api/stats and /api/rewards
reward.go Epoch-based reward calculation (weight = tasks x accuracy bonus)
reward_onchain.go On-chain depositAndSettle() to AgentRewardPool contract
statediff.go State diff capture from stateDB commits and broadcasting to L4 agents
diffstore.go Persistent diff storage (BoltDB) for agent catch-up
integration.go Wiring docs + adapter interface definitions
proto/ gRPC service definition + Go types + codec
CLI Tools (cmd/)
Tool Usage Purpose
l4baseline go run ./ioswarm/cmd/l4baseline --source trie.db --output snap.gz Export IOSWSNAP snapshot from trie.db for L4 agent bootstrap
keygen go run ./ioswarm/cmd/keygen --secret <master> --agent-id <id> Generate HMAC-SHA256 API key for an agent
sim go run ./ioswarm/cmd/sim --agents=10 --duration=30s L1-L3 simulation with synthetic workload
l4sim go run ./ioswarm/cmd/l4sim --agents=10 --duration=60s L4 multi-agent stress test (9/9 checks PASS, race-clean)
l4test go run ./ioswarm/cmd/l4test --coordinator=host:14689 Live validation of StreamStateDiffs

L5 Roadmap: Agent Block Building (ePBS)

L4 stateful agents are the foundation for L5 block building, following Ethereum's ePBS (EIP-7732) model adapted for IoTeX's DPoS architecture.

Level Capability Status
L1-L3 Per-tx validation (L3 = 100% via SimulateAccessList) Production
L4 Per-tx EVM execution, full local state, independent validation Production
L5 Full block building (ePBS) Design phase

Key advantage: IoTeX's deltaStateDigest is a hash of the ordered state change queue (not a Merkle Trie root). Agents need only a flat KV store — no full MPT required. This makes block building feasible on commodity hardware.

For detailed L5 design, see design-epbs-block-building.md.

Repository Description
ioswarm-agent Agent binary (L1-L4 validation, claim/deploy/fund tools)
ioswarm-portal Dashboard and monitoring UI
IIP-58 ioSwarm protocol specification

Documentation

Overview

Package ioswarm provides integration points for embedding the IOSwarm coordinator into an iotex-core node.

Integration into iotex-core requires:

1. Add to config/config.go:

type Config struct {
    ...
    IOSwarm ioswarm.Config `yaml:"ioswarm"`
}

2. Add to server/itx/server.go — newServer():

if cfg.IOSwarm.Enabled {
    svr.ioswarmCoord = ioswarm.NewCoordinator(
        cfg.IOSwarm,
        ioswarm.NewActPoolAdapter(cs.ActionPool(), cs.Blockchain()),
        ioswarm.NewStateReaderAdapter(cs.StateFactory()),
    )
}

3. Add to server/itx/server.go — Start():

if svr.ioswarmCoord != nil {
    svr.ioswarmCoord.Start(ctx)
}

4. Add to server/itx/server.go — Stop():

if svr.ioswarmCoord != nil {
    svr.ioswarmCoord.Stop()
}

5. Add to config YAML:

ioswarm:
  enabled: true
  grpcPort: 14689
  maxAgents: 100
  taskLevel: "L2"
  shadowMode: true
  pollIntervalMs: 1000

Production adapters (ActPoolAdapter, StateReaderAdapter) are in adapter.go.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AgentIDFromContext

func AgentIDFromContext(ctx context.Context) string

AgentIDFromContext extracts the verified agent ID from the context. Returns empty string if not present (e.g., auth disabled).

func DeriveAgentToken

func DeriveAgentToken(masterSecret, agentID string) string

DeriveAgentToken generates an API key for the given agent using HMAC-SHA256. The key format is "iosw_" + hex(HMAC-SHA256(masterSecret, agentID)).

func FormatIOTX

func FormatIOTX(rau *big.Int) string

FormatIOTX formats a rau amount as a human-readable IOTX string.

func IOTXToWei

func IOTXToWei(iotx float64) *big.Int

IOTXToWei converts IOTX float to wei (1 IOTX = 10^18 wei).

func PrintPayoutTable

func PrintPayoutTable(summary *EpochSummary) string

PrintPayoutTable formats a payout summary as a readable table.

func RegisterIOSwarmServer

func RegisterIOSwarmServer(s *grpc.Server, srv IOSwarmServer)

RegisterIOSwarmServer registers the gRPC service handler. In production, this would be generated by protoc-gen-go-grpc.

func SetupStateDiffCallback

func SetupStateDiffCallback(sf factory.Factory, coord *Coordinator)

SetupStateDiffCallback wires the state diff callback from the state factory to the coordinator's diff broadcaster. This enables L4 agents to receive per-block state diffs for stateful validation.

func ValidateAgentToken

func ValidateAgentToken(masterSecret, agentID, token string) bool

ValidateAgentToken checks that the token matches HMAC-SHA256(masterSecret, agentID). Uses constant-time comparison to prevent timing attacks.

Types

type ActPoolAdapter

type ActPoolAdapter struct {
	// contains filtered or unexported fields
}

ActPoolAdapter wraps iotex-core's actpool.ActPool and blockchain.Blockchain to implement ActPoolReader for production use.

func NewActPoolAdapter

func NewActPoolAdapter(pool actpool.ActPool, bc blockchain.Blockchain) *ActPoolAdapter

NewActPoolAdapter creates a new ActPoolAdapter.

func (*ActPoolAdapter) BlockHeight

func (a *ActPoolAdapter) BlockHeight() uint64

BlockHeight returns the current tip block height.

func (*ActPoolAdapter) PendingActions

func (a *ActPoolAdapter) PendingActions() (txs []*PendingTx)

PendingActions reads all pending transactions from the actpool and converts them to the ioswarm PendingTx format.

type ActPoolReader

type ActPoolReader interface {
	PendingActions() []*PendingTx
	BlockHeight() uint64
}

ActPoolReader is the interface for reading pending transactions. In production, this wraps iotex-core's ActPool.

type AgentAccuracy

type AgentAccuracy struct {
	Compared uint64
	Matched  uint64
}

AgentAccuracy holds per-agent shadow match counts for a comparison batch.

type AgentInfo

type AgentInfo struct {
	ID             string
	Capability     pb.TaskLevel
	Region         string
	Version        string
	RegisteredAt   time.Time
	LastHeartbeat  time.Time
	TasksProcessed uint32
	TasksPending   uint32
	CPUUsage       float64
	MemUsage       float64
	TaskChan       chan *pb.TaskBatch // channel to push tasks to this agent's stream
	// contains filtered or unexported fields
}

AgentInfo tracks a connected agent's state.

func (*AgentInfo) CloseTaskChan

func (a *AgentInfo) CloseTaskChan()

CloseTaskChan safely closes the TaskChan exactly once.

type AgentWork

type AgentWork struct {
	AgentID        string
	WalletAddress  string // agent's IOTX address for payout
	TasksProcessed uint64
	TasksCorrect   uint64 // matched in shadow mode
	TotalLatencyUs uint64
	Uptime         time.Duration // time since registration
	Level          string        // L1, L2, L3
}

AgentWork tracks an agent's contribution in the current epoch.

func (*AgentWork) Accuracy

func (w *AgentWork) Accuracy() float64

Accuracy returns the agent's shadow mode accuracy (0.0-1.0).

type Config

type Config struct {
	Enabled         bool    `yaml:"enabled"`
	GRPCPort        int     `yaml:"grpcPort"`        // default 14689
	SwarmAPIPort    int     `yaml:"swarmApiPort"`    // default 14690 (0 to disable)
	MaxAgents       int     `yaml:"maxAgents"`       // default 100
	TaskLevel       string  `yaml:"taskLevel"`       // "L1", "L2", "L3", "L4"
	ShadowMode      bool    `yaml:"shadowMode"`      // default true
	PollIntervalMS  int     `yaml:"pollIntervalMs"`  // default 1000
	MasterSecret    string  `yaml:"masterSecret"`    // HMAC master secret for agent auth (empty = no auth)
	DelegateAddress string  `yaml:"delegateAddress"` // delegate's IOTX address for reward payout
	EpochRewardIOTX float64 `yaml:"epochRewardIOTX"` // IOTX per epoch for reward distribution (default 800)

	// On-chain reward pool settlement
	RewardContract  string `yaml:"rewardContract"`  // AgentRewardPool contract address (empty = disabled)
	RewardSignerKey string `yaml:"rewardSignerKey"` // hex private key for signing depositAndSettle txs
	RewardRPCURL    string `yaml:"rewardRpcUrl"`    // RPC endpoint (default: https://babel-api.mainnet.iotex.io)
	RewardChainID   int64  `yaml:"rewardChainId"`   // chain ID (default: 4689 for IoTeX mainnet)

	DiffBufferSize   int          `yaml:"diffBufferSize"`   // ring buffer size for state diff broadcaster (default 100)
	DiffStoreEnabled bool         `yaml:"diffStoreEnabled"` // persist state diffs to disk (default true for L4)
	DiffStorePath    string       `yaml:"diffStorePath"`    // path to statediffs.db (default: <datadir>/statediffs.db)
	DiffRetainHeight uint64       `yaml:"diffRetainHeight"` // prune diffs older than this many blocks (default 10000 ≈ 27h; 0 = keep all)
	Reward           RewardConfig `yaml:"reward"`
}

Config holds IOSwarm coordinator configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sane defaults.

type Coordinator

type Coordinator struct {
	// contains filtered or unexported fields
}

Coordinator is the central orchestrator that polls the actpool, prefetches account state, and dispatches validation tasks to agents.

func NewCoordinator

func NewCoordinator(cfg Config, actPool ActPoolReader, stateReader StateReader, opts ...Option) *Coordinator

NewCoordinator creates a new IOSwarm coordinator. actPool and stateReader are in-memory interfaces from iotex-core.

func (*Coordinator) CompareEVMShadow

func (c *Coordinator) CompareEVMShadow(agentResults []*pb.TaskResult, actualResults map[uint32]*EVMActualResult, blockHeight uint64)

CompareEVMShadow feeds EVM reference results to the shadow comparator for comparison against agent-submitted EVM results.

func (*Coordinator) DiffBroadcaster

func (c *Coordinator) DiffBroadcaster() *StateDiffBroadcaster

DiffBroadcaster returns the state diff broadcaster for gRPC streaming.

func (*Coordinator) DiffStore

func (c *Coordinator) DiffStore() *DiffStore

DiffStore returns the persistent diff store (may be nil if disabled).

func (*Coordinator) DrainRecentResults

func (c *Coordinator) DrainRecentResults() []*pb.TaskResult

DrainRecentResults removes and returns all recent task results (for EVM shadow comparison).

func (*Coordinator) LastTaskID

func (c *Coordinator) LastTaskID() uint32

LastTaskID returns the most recently assigned task ID.

func (*Coordinator) OnBlockExecuted

func (c *Coordinator) OnBlockExecuted(blockHeight uint64, actualResults map[uint32]bool, taskSenders map[uint32]string)

OnBlockExecuted should be called after iotex-core executes a block. It compares agent results against actual execution and invalidates the prefetcher cache so stale state isn't served to agents.

actualResults maps task_id → whether the tx was actually valid. In production, this is wired from iotex-core's block executor. In simulation, pass generated results.

func (*Coordinator) ReceiveBlock

func (c *Coordinator) ReceiveBlock(blk *block.Block) error

ReceiveBlock implements blockchain.BlockCreationSubscriber. Called by iotex-core after each block is committed to chain. It maps on-chain tx results back to dispatched task IDs for shadow comparison.

func (*Coordinator) ReceiveStateDiff

func (c *Coordinator) ReceiveStateDiff(height uint64, entries []StateDiffEntry, digest []byte)

ReceiveStateDiff is called by the stateDB diff callback after each block commit. It converts WriteQueueEntry to StateDiffEntry and publishes to the broadcaster.

func (*Coordinator) ShadowStats

func (c *Coordinator) ShadowStats() ShadowStats

ShadowStats returns the current shadow comparison statistics.

func (*Coordinator) Start

func (c *Coordinator) Start(ctx context.Context) error

Start launches the coordinator's gRPC server and main polling loop.

func (*Coordinator) Stop

func (c *Coordinator) Stop()

Stop gracefully shuts down the coordinator with a 5-second timeout. If GracefulStop doesn't complete in time, it falls back to a hard Stop to avoid blocking the node's shutdown sequence.

type DiffStore

type DiffStore struct {
	// contains filtered or unexported fields
}

DiffStore persists state diffs to a BoltDB file so that StreamStateDiffs can serve any historical range (not just the last N blocks from the ring buffer).

func OpenDiffStore

func OpenDiffStore(path string, logger *zap.Logger) (*DiffStore, error)

OpenDiffStore opens or creates a DiffStore at the given path.

func (*DiffStore) Append

func (ds *DiffStore) Append(diff *StateDiff) error

Append writes a state diff to the store. Idempotent by height — if a diff for this height already exists, it is silently overwritten.

func (*DiffStore) Close

func (ds *DiffStore) Close() error

Close closes the underlying BoltDB.

func (*DiffStore) Get

func (ds *DiffStore) Get(height uint64) (*StateDiff, error)

Get retrieves a single state diff by height.

func (*DiffStore) GetRange

func (ds *DiffStore) GetRange(from, to uint64) ([]*StateDiff, error)

GetRange returns state diffs for heights [from, to] inclusive, ordered by height. Uses cursor seeking for efficient range scans.

func (*DiffStore) LatestHeight

func (ds *DiffStore) LatestHeight() uint64

LatestHeight returns the highest stored height, or 0 if empty.

func (*DiffStore) OldestHeight

func (ds *DiffStore) OldestHeight() uint64

OldestHeight returns the lowest stored height, or 0 if empty.

func (*DiffStore) Prune

func (ds *DiffStore) Prune(keepAfter uint64) (int, error)

Prune deletes all diffs with height < keepAfter. Returns the number of entries deleted.

type EVMActualResult

type EVMActualResult struct {
	TaskID       uint32
	GasUsed      uint64
	StateChanges []*pb.StateChange
	ExecError    string
}

EVMActualResult holds the reference EVM execution result for shadow comparison.

type EpochSummary

type EpochSummary struct {
	Epoch           uint64
	TotalReward     *big.Int
	DelegateCut     *big.Int
	DelegateAddress string
	AgentPool       *big.Int
	Payouts         []Payout
	AgentCount      int
	TotalTasks      uint64
	Timestamp       time.Time
}

EpochSummary records a completed epoch's distribution.

type IOSwarmServer

IOSwarmServer is the gRPC service interface.

func NewGRPCHandler

func NewGRPCHandler(c *Coordinator) IOSwarmServer

NewGRPCHandler creates a gRPC handler for this coordinator. Use with RegisterIOSwarmServer to register on a grpc.Server.

type IOSwarm_GetTasksServer

type IOSwarm_GetTasksServer interface {
	Send(*pb.TaskBatch) error
	grpc.ServerStream
}

IOSwarm_GetTasksServer is the server-side streaming interface for GetTasks.

type IOSwarm_StreamStateDiffsServer

type IOSwarm_StreamStateDiffsServer interface {
	Send(*pb.StateDiffResponse) error
	grpc.ServerStream
}

IOSwarm_StreamStateDiffsServer is the server-side streaming interface for StreamStateDiffs.

type OnChainSettler

type OnChainSettler struct {
	// contains filtered or unexported fields
}

OnChainSettler implements RewardSettler using go-ethereum's ethclient.

func NewOnChainSettler

func NewOnChainSettler(cfg Config, logger *zap.Logger) (*OnChainSettler, error)

NewOnChainSettler creates a settler from Config. Returns (nil, nil) if RewardContract or RewardSignerKey is empty.

func (*OnChainSettler) Settle

func (s *OnChainSettler) Settle(ctx context.Context, agents []string, weights []*big.Int, value *big.Int, claimees []string) error

Settle calls depositSettleAndClaim (or depositAndSettle if no claimees) on the reward pool contract.

type Option

type Option func(*options)

Option configures the coordinator.

func WithDataDir

func WithDataDir(dir string) Option

WithDataDir sets the directory for persistent stores (e.g. statediffs.db).

func WithLogger

func WithLogger(l *zap.Logger) Option

WithLogger sets the coordinator's logger.

func WithRewardSettler

func WithRewardSettler(s RewardSettler) Option

WithRewardSettler sets the on-chain reward settler. When set, distributeEpochReward will call depositAndSettle on the contract.

type Payout

type Payout struct {
	AgentID       string
	WalletAddress string
	Amount        *big.Int // in rau (1 IOTX = 10^18 rau)
	AmountIOTX    float64  // human-readable
	TasksDone     uint64
	Accuracy      float64
	Share         float64 // percentage of agent pool
	BonusApplied  bool
}

Payout represents a single agent's reward for an epoch.

type PendingTx

type PendingTx struct {
	Hash     string
	From     string
	To       string
	Nonce    uint64
	Amount   string // big.Int as string
	GasLimit uint64
	GasPrice string
	Data     []byte
	RawBytes []byte // serialized envelope
}

PendingTx represents a pending transaction from the actpool.

type Prefetcher

type Prefetcher struct {
	// contains filtered or unexported fields
}

Prefetcher batch-reads account state for pending transactions.

func NewPrefetcher

func NewPrefetcher(sr StateReader, logger *zap.Logger) *Prefetcher

NewPrefetcher creates a new state prefetcher.

func (*Prefetcher) InvalidateCache

func (p *Prefetcher) InvalidateCache()

InvalidateCache clears cached state (call on new block). Uses atomic pointer swap to avoid races with concurrent Prefetch.

func (*Prefetcher) Prefetch

func (p *Prefetcher) Prefetch(txs []*PendingTx) map[string]*pb.AccountSnapshot

Prefetch gathers account state for all addresses involved in the pending txs. Returns a map of address → AccountSnapshot.

func (*Prefetcher) PrefetchCode

func (p *Prefetcher) PrefetchCode(addresses []string) map[string][]byte

PrefetchCode fetches contract bytecode for the given addresses with a 5s timeout.

func (*Prefetcher) PrefetchStorage

func (p *Prefetcher) PrefetchStorage(address string, slots []string) map[string]string

PrefetchStorage fetches storage slots for a contract address with a 5s timeout.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry tracks all connected agents.

func NewRegistry

func NewRegistry(maxAgents int) *Registry

NewRegistry creates a new agent registry.

func (*Registry) Count

func (r *Registry) Count() int

Count returns the number of registered agents.

func (*Registry) EvictStale

func (r *Registry) EvictStale(threshold time.Duration) []string

EvictStale removes agents that haven't sent a heartbeat within the threshold.

func (*Registry) GetAgent

func (r *Registry) GetAgent(agentID string) (*AgentInfo, bool)

GetAgent returns agent info by ID.

func (*Registry) Heartbeat

func (r *Registry) Heartbeat(req *pb.HeartbeatRequest) bool

Heartbeat updates an agent's last heartbeat time and stats.

func (*Registry) LiveAgents

func (r *Registry) LiveAgents(threshold time.Duration) []*AgentInfo

LiveAgents returns all agents with a heartbeat within the given threshold.

func (*Registry) Register

func (r *Registry) Register(req *pb.RegisterRequest) (*AgentInfo, bool)

Register adds an agent to the registry. Returns false if at capacity.

func (*Registry) Unregister

func (r *Registry) Unregister(agentID string)

Unregister removes an agent from the registry.

type RewardConfig

type RewardConfig struct {
	// DelegateCutPct is the percentage the delegate keeps (0-100).
	// Default: 10 (delegate keeps 10%, agents split 90%)
	DelegateCutPct float64 `yaml:"delegateCutPct"`

	// EpochBlocks is how many blocks per reward epoch.
	// Default: 360 (IoTeX epoch = 1 hour at 10s blocks)
	EpochBlocks uint64 `yaml:"epochBlocks"`

	// MinTasksForReward is the minimum tasks an agent must process
	// in an epoch to receive rewards. Prevents freeloading.
	// Default: 10
	MinTasksForReward uint64 `yaml:"minTasksForReward"`

	// BonusAccuracyPct: agents with shadow accuracy above this get a bonus.
	// Default: 99.5
	BonusAccuracyPct float64 `yaml:"bonusAccuracyPct"`

	// BonusMultiplier: bonus multiplier for high-accuracy agents.
	// Default: 1.2 (20% bonus)
	BonusMultiplier float64 `yaml:"bonusMultiplier"`
}

RewardConfig controls reward distribution parameters.

func DefaultRewardConfig

func DefaultRewardConfig() RewardConfig

DefaultRewardConfig returns sane defaults.

type RewardDistributor

type RewardDistributor struct {
	// contains filtered or unexported fields
}

RewardDistributor tracks agent work and calculates reward distribution.

Flow:

  1. Coordinator calls RecordWork() on every SubmitResults
  2. At epoch end (every N blocks), delegate calls Distribute()
  3. Distribute() returns a payout list: agent_address → IOTX amount
  4. Delegate signs a batch transfer tx (or calls a RewardPool contract)

The delegate keeps a configurable cut (e.g. 10%) for operating costs, and distributes the rest proportionally by tasks validated.

func NewRewardDistributor

func NewRewardDistributor(cfg RewardConfig, delegateAddress string, logger *zap.Logger) *RewardDistributor

NewRewardDistributor creates a new reward distributor.

func (*RewardDistributor) CurrentEpoch

func (r *RewardDistributor) CurrentEpoch() uint64

CurrentEpoch returns the current epoch number.

func (*RewardDistributor) CurrentWork

func (r *RewardDistributor) CurrentWork() map[string]*AgentWork

CurrentWork returns a snapshot of current epoch work stats.

func (*RewardDistributor) Distribute

func (r *RewardDistributor) Distribute(totalReward *big.Int) *EpochSummary

Distribute computes payouts, freezes the snapshot, and advances the epoch atomically under a single lock hold. The returned summary is the exact snapshot that should be used for on-chain settlement.

func (*RewardDistributor) EpochElapsed

func (r *RewardDistributor) EpochElapsed() time.Duration

EpochElapsed returns the time since the current epoch started.

func (*RewardDistributor) EpochHistory

func (r *RewardDistributor) EpochHistory() []EpochSummary

EpochHistory returns all past epoch summaries.

func (*RewardDistributor) RecordShadowAccuracy

func (r *RewardDistributor) RecordShadowAccuracy(agentID string, matched uint64)

RecordShadowAccuracy adds verified correct tasks from shadow comparison. Called from OnBlockExecuted after ground-truth comparison.

func (*RewardDistributor) RecordWork

func (r *RewardDistributor) RecordWork(agentID string, tasksProcessed, tasksCorrect uint64, totalLatencyUs uint64)

RecordWork records an agent's completed work. Called on every SubmitResults.

func (*RewardDistributor) SetAgentWallet

func (r *RewardDistributor) SetAgentWallet(agentID, walletAddress string)

SetAgentWallet sets the payout address for an agent.

type RewardSettler

type RewardSettler interface {
	// Settle calls depositSettleAndClaim on the reward pool contract.
	// agents: list of 0x-prefixed agent wallet addresses
	// weights: corresponding weight for each agent (same length)
	// value: total IOTX to deposit in wei/rau
	// claimees: optional list of agent addresses to auto-claim for (can be nil)
	Settle(ctx context.Context, agents []string, weights []*big.Int, value *big.Int, claimees []string) error
}

RewardSettler sends on-chain settlement transactions to the AgentRewardPool contract.

type Scheduler

type Scheduler struct {
	// contains filtered or unexported fields
}

Scheduler assigns task batches to agents using least-loaded dispatch with capability filtering and a bounded retry queue.

func NewScheduler

func NewScheduler(registry *Registry, logger *zap.Logger) *Scheduler

NewScheduler creates a new task scheduler.

func (*Scheduler) Dispatch

func (s *Scheduler) Dispatch(tasks []*pb.TaskPackage, batchSize int) int

Dispatch sends tasks to available agents using least-loaded selection. Tasks are split into batches and dispatched with capability filtering. Returns the number of tasks dispatched.

func (*Scheduler) RetryQueueLen

func (s *Scheduler) RetryQueueLen() int

RetryQueueLen returns the number of batches in the retry queue. For testing.

type ShadowComparator

type ShadowComparator struct {
	// contains filtered or unexported fields
}

ShadowComparator compares agent validation results against iotex-core's actual block execution. In shadow mode, agent results never affect block production — they're purely observational.

func NewShadowComparator

func NewShadowComparator(logger *zap.Logger) *ShadowComparator

NewShadowComparator creates a new shadow comparator.

func (*ShadowComparator) CompareEVMResults

func (s *ShadowComparator) CompareEVMResults(agentResults []*pb.TaskResult, actualResults map[uint32]*EVMActualResult, blockHeight uint64)

CompareEVMResults compares agent EVM results against reference results.

func (*ShadowComparator) CompareWithActual

func (s *ShadowComparator) CompareWithActual(actualResults map[uint32]bool, taskSenders map[uint32]string, blockHeight uint64) ([]ShadowResult, map[string]*AgentAccuracy)

CompareWithActual compares stored agent results against actual execution. actualResults maps task_id → whether the tx was actually valid. taskSenders maps task_id → sender address (for nonce race detection). Returns mismatches and per-agent accuracy counts.

func (*ShadowComparator) RecordAgentResults

func (s *ShadowComparator) RecordAgentResults(agentID string, batch *pb.BatchResult)

RecordAgentResults stores agent results for later comparison.

func (*ShadowComparator) ResetStats

func (s *ShadowComparator) ResetStats()

ResetStats resets the statistics counters.

func (*ShadowComparator) Stats

func (s *ShadowComparator) Stats() ShadowStats

Stats returns current shadow comparison statistics.

type ShadowResult

type ShadowResult struct {
	TaskID      uint32
	AgentResult *pb.TaskResult
	ActualValid bool
	Match       bool
	AgentID     string
	BlockHeight uint64
}

ShadowResult holds the comparison between agent and actual results.

type ShadowStats

type ShadowStats struct {
	TotalCompared     uint64
	TotalMatched      uint64
	TotalMismatched   uint64
	FalsePositives    uint64 // agent said valid, actual invalid
	FalseNegatives    uint64 // agent said invalid, actual valid
	NonceRaceExcluded uint64 // false positives excused due to nonce race

	// EVM-specific shadow stats (L3)
	EVMGasMatches      uint64
	EVMGasMismatches   uint64
	EVMStateMatches    uint64
	EVMStateMismatches uint64
}

ShadowStats tracks shadow mode accuracy metrics.

type StateDiff

type StateDiff struct {
	Height      uint64
	Entries     []StateDiffEntry
	DigestBytes []byte // raw SerializeQueue output hash for verification
}

StateDiff contains all state changes for a single block.

type StateDiffBroadcaster

type StateDiffBroadcaster struct {
	// contains filtered or unexported fields
}

StateDiffBroadcaster buffers recent state diffs and fans them out to subscribers.

func NewStateDiffBroadcaster

func NewStateDiffBroadcaster(maxBuffer int, logger *zap.Logger) *StateDiffBroadcaster

NewStateDiffBroadcaster creates a new broadcaster with the given buffer size.

func (*StateDiffBroadcaster) BufferedCount

func (b *StateDiffBroadcaster) BufferedCount() int

BufferedCount returns the number of diffs currently in the ring buffer.

func (*StateDiffBroadcaster) DroppedCount

func (b *StateDiffBroadcaster) DroppedCount(agentID string) int64

DroppedCount returns the number of diffs dropped for a subscriber.

func (*StateDiffBroadcaster) GetRange

func (b *StateDiffBroadcaster) GetRange(from, to uint64) []*StateDiff

GetRange returns state diffs for heights [from, to] inclusive. Returns nil entries for heights that have been evicted from the buffer.

func (*StateDiffBroadcaster) LatestHeight

func (b *StateDiffBroadcaster) LatestHeight() uint64

LatestHeight returns the height of the most recent state diff, or 0 if empty.

func (*StateDiffBroadcaster) Publish

func (b *StateDiffBroadcaster) Publish(diff *StateDiff)

Publish adds a state diff to the ring buffer and fans out to all subscribers.

func (*StateDiffBroadcaster) Subscribe

func (b *StateDiffBroadcaster) Subscribe(agentID string) <-chan *StateDiff

Subscribe returns a channel that receives new state diffs. The channel has a buffer of 64 to absorb brief bursts. If an agent is already subscribed, the old subscription is closed first.

func (*StateDiffBroadcaster) SubscriberCount

func (b *StateDiffBroadcaster) SubscriberCount() int

SubscriberCount returns the number of active subscribers.

func (*StateDiffBroadcaster) Unsubscribe

func (b *StateDiffBroadcaster) Unsubscribe(agentID string)

Unsubscribe removes a subscriber and closes its channel.

type StateDiffEntry

type StateDiffEntry struct {
	Type      uint8 // 0=Put, 1=Delete
	Namespace string
	Key       []byte
	Value     []byte
}

StateDiffEntry represents a single state mutation (Put or Delete).

type StateReader

type StateReader interface {
	AccountState(address string) (*pb.AccountSnapshot, error)
	GetCode(address string) ([]byte, error)            // contract bytecode
	GetStorageAt(address, slot string) (string, error) // storage slot value (hex)
	// SimulateAccessList runs a read-only EVM simulation and returns all storage
	// slots accessed by the transaction. Returns nil map if not supported.
	SimulateAccessList(from, to string, data []byte, value string, gasLimit uint64) (map[string][]string, error)
}

StateReader is the interface for reading account state. In production, this wraps iotex-core's StateFactory.

type StateReaderAdapter

type StateReaderAdapter struct {
	// contains filtered or unexported fields
}

StateReaderAdapter wraps iotex-core's factory.Factory to implement StateReader for production use.

func NewStateReaderAdapter

func NewStateReaderAdapter(sf factory.Factory, bc blockchain.Blockchain, g genesis.Genesis) *StateReaderAdapter

NewStateReaderAdapter creates a new StateReaderAdapter.

func (*StateReaderAdapter) AccountState

func (s *StateReaderAdapter) AccountState(addr string) (snap *pb.AccountSnapshot, err error)

AccountState reads the confirmed account state from the stateDB.

func (*StateReaderAdapter) GetCode

func (s *StateReaderAdapter) GetCode(addr string) (code []byte, err error)

GetCode returns contract bytecode from the stateDB.

func (*StateReaderAdapter) GetStorageAt

func (s *StateReaderAdapter) GetStorageAt(addr, slot string) (val string, err error)

GetStorageAt returns a storage slot value from the stateDB. slot is a hex-encoded 32-byte key (e.g. "0x0000...0000").

func (*StateReaderAdapter) SimulateAccessList

func (s *StateReaderAdapter) SimulateAccessList(from, to string, data []byte, value string, gasLimit uint64) (result map[string][]string, err error)

SimulateAccessList runs a read-only EVM simulation and returns all storage slots accessed during execution, keyed by contract address (io1 format).

type SwarmAPI

type SwarmAPI struct {
	// contains filtered or unexported fields
}

SwarmAPI serves HTTP endpoints for monitoring the IOSwarm. Endpoints:

GET /api/stats         — public network stats (CORS-enabled, no auth)
GET /swarm/status      — overall swarm status
GET /swarm/agents      — list all connected agents
GET /swarm/leaderboard — agents ranked by tasks processed
GET /swarm/epoch       — current epoch work stats
GET /swarm/shadow      — shadow mode comparison stats
GET /healthz           — health check

func NewSwarmAPI

func NewSwarmAPI(coord *Coordinator, reward *RewardDistributor) *SwarmAPI

NewSwarmAPI creates a new swarm API.

func (*SwarmAPI) Handler

func (s *SwarmAPI) Handler() http.Handler

Handler returns an http.Handler with all swarm routes registered.

Directories

Path Synopsis
cmd
keygen command
Command keygen generates HMAC-based API keys for IOSwarm agents.
Command keygen generates HMAC-based API keys for IOSwarm agents.
l4baseline command
l4baseline converts a mainnet trie.db (BoltDB) into an IOSWSNAP baseline snapshot for L4 agent state sync.
l4baseline converts a mainnet trie.db (BoltDB) into an IOSWSNAP baseline snapshot for L4 agent state sync.
l4sim command
l4sim is a multi-agent stress simulation for the IOSwarm L4 state diff pipeline.
l4sim is a multi-agent stress simulation for the IOSwarm L4 state diff pipeline.
l4test command
l4test connects to a live delegate and validates StreamStateDiffs.
l4test connects to a live delegate and validates StreamStateDiffs.
sim command
sim runs a full IOSwarm simulation: 1 delegate coordinator + N agents.
sim runs a full IOSwarm simulation: 1 delegate coordinator + N agents.
Package proto contains the IOSwarm gRPC types.
Package proto contains the IOSwarm gRPC types.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL