Skip to content

Extract reth-erc8004-indexer into standalone Helm chart with discovery fallback #294

@bussyjd

Description

@bussyjd

Summary

Wire the reth-erc8004-indexer into obol network install ethereum --mode archive as a drop-in reth image swap with ERC-8004 ExEx indexing, plus a 3-tier discovery client for downstream consumers (autoresearch, etc.).

Context

The reth-erc8004-indexer was extracted from PR #288 (Oisin's review: standalone Rust, not wired into the stack). The binary is compiled as reth ([[bin]] name = "reth" in Cargo.toml) — it IS reth with an ExEx bolted on. This means it's a drop-in image swap in the existing ethereum-helm-charts/ethereum-node chart, not a separate Helm chart.

Design

When --execution-client reth --mode archive is specified, the helmfile swaps the upstream ethereum/reth image for ghcr.io/obolnetwork/reth-erc8004-indexer, exposes the indexer API port (3400), and adds a SQLite PVC.

obol network install ethereum --mode archive
  |
  +-- executionClient: reth (default)
  +-- mode: archive
  |
  +-- helmfile renders:
      reth:
        image:
          repository: ghcr.io/obolnetwork/reth-erc8004-indexer
          tag: v0.1.0
        extraPorts:
          - name: indexer-api
            containerPort: 3400

CLI behavior

# Default (unchanged)
obol network install ethereum
# -> reth full sync, no indexer

# Archive mode with ERC-8004 indexing
obol network install ethereum --mode archive
# -> reth-erc8004-indexer image, ExEx enabled, API on :3400

# Archive + non-reth client (indexer N/A)
obol network install ethereum --mode archive --execution-client geth
# -> geth archive sync, no indexer (warn: ERC-8004 indexing only with reth)

Implementation Phases

Phase 1: Template plumbing (unblocks everything)

File Change
internal/embed/networks/ethereum/values.yaml.gotmpl Add Mode field: @enum full,archive @default full
internal/embed/networks/ethereum/helmfile.yaml.gotmpl Conditional image swap when mode=archive + executionClient=reth
internal/embed/networks/ethereum/templates/pvc.yaml Optional indexer PVC (indexer-data, 10Gi) when archive mode

CLI --mode flag is auto-generated from the @enum annotation -- zero Go code needed.

Phase 2: Indexer image CI (parallel)

File Change
reth-erc8004-indexer/ Restore Rust source from extracted commit
Dockerfile.reth-erc8004-indexer Restore
.github/workflows/docker-publish-reth-indexer.yml Build + publish + Trivy scan

Phase 3: Discovery client (parallel)

File Change
internal/discovery/discovery.go DiscoveryClient interface + FallbackClient
internal/discovery/reth.go Client for local indexer API (:3400)
internal/discovery/basescan.go Client for BaseScan ERC-8004 metadata
internal/discovery/eightkcan.go Client for 8004scan.io
internal/discovery/*_test.go Per-client unit + fallback integration tests

Phase 4: Wire into autoresearch

  • Auto-detect indexer when deployed (archive mode)
  • Fallback: no indexer -> BaseScan -> 8004scan.io
  • Integration test: register -> index -> discover -> probe via x402

Dependency graph

Phase 1 (template) --+
Phase 2 (CI)       --+--> Phase 4 (wire autoresearch)
Phase 3 (discovery) -+

Phases 1, 2, 3 run in parallel.

3-Tier Discovery Architecture

Priority 1: Internal Reth Indexer (self-hosted, real-time)
    |  reth-indexer:3400
    |  Latency: <100ms, block-level freshness
    |  Cost: runs archive Base L2 node (~500GB disk)
    v if unavailable
Priority 2: BaseScan API (hosted, reliable)
    |  api.basescan.org -- ERC-8004 metadata natively supported
    |  Latency: <500ms, free tier 5 calls/sec
    v if no API key
Priority 3: 8004scan.io (community, best-effort)
    |  No key required, minutes behind chain
    v if all unavailable
    Error: no discovery backend

Discovery Client Interface

type DiscoveryClient interface {
    ListAgents(ctx context.Context, opts ListOptions) ([]Agent, error)
    SearchAgents(ctx context.Context, query string, limit int) ([]Agent, error)
    GetAgent(ctx context.Context, chainID uint64, tokenID string) (*Agent, error)
    Health(ctx context.Context) error
}

Test Plan

Rust unit tests

  • storage.rs: SQLite CRUD, pagination, search
  • indexer.rs: event log parsing, reorg handling
  • api.rs: response shape matches 8004scan contract

Go tests

  • Discovery client per-tier unit tests
  • FallbackClient integration (priority order, cache TTL)
  • Template rendering: --mode archive produces correct image/port/PVC

Helm tests

  • test-api.yaml: health + stats endpoints

Integration

  • Register agent on-chain -> indexer picks up -> coordinator discovers -> x402 probe

Acceptance Criteria

  1. obol network install ethereum --mode archive deploys reth-erc8004-indexer image
  2. Indexer API serves on :3400 with 8004scan-compatible responses
  3. obol network install ethereum (no --mode) unchanged -- upstream reth image
  4. Discovery fallback works: indexer -> BaseScan -> 8004scan
  5. CI builds and publishes indexer image to ghcr.io

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions