Skip to content

Chain Service

Providers earn real money on this platform, so they can't be asked to just trust our database that they were paid correctly. The chain service is the answer: it writes every money-affecting event to a private, append-only blockchain anyone can read and verify independently. It's the platform's audit trail you don't have to trust us for.

Not a service with a port — a small in-process library (chain_service.client) that credit_service and the job gateway import, plus an external CometBFT node running the chain.

What gets recorded

Any service calls record_event(type, source, user_id, data) — credit mints/deducts/transfers, job_submit/complete/fail, endpoint lifecycle, revenue payouts. It's fire-and-forget: the event lands on a bounded queue and a background worker takes it from there, so the audit trail can never slow down or break a real request (a flooded queue drops with a log — it never blocks).

Chain + index: trust vs. speed

The worker writes each event to two places, index-first:

  1. Postgres index (chain_events) — written first, and the only thing reads ever touch. Fast queries by user / type / time, and events survive a chain-node outage.
  2. The chain — a CometBFT node running its built-in kvstore app; the full event JSON becomes a transaction. This is the trust anchor: append-only, tamper-evident, readable over plain JSON-RPC by anyone, no fees or keys.

So the index serves the product; the chain makes it verifiable. Today it's one CometBFT node on the master; the design extends to multiple validators across provider nodes.

Using it

from chain_service.client import start, record_event, get_recent_events

start()                                             # background worker, at service boot
record_event("credit_mint", "credit_service", user_id, {"amount": 50.0})
get_recent_events(limit=50)                         # reads the index

platform_service exposes this over /v1/chain/* (the index for event lists, raw CometBFT RPC for direct verification); the SDK's gridweave.chain() / chain_rpc() and the WebUI Activity page are the front ends. migrate_index.py backfills the index from chain history.

Configuration

Variable Default Description
CHAIN_ENABLED false Master switch — off ⇒ record_event/start are no-ops
CHAIN_RPC http://127.0.0.1:26657 CometBFT JSON-RPC endpoint
CHAIN_DATABASE_URL Postgres index (the read path)

Tests: tests/chain_service/test_client.py (recording, the fire-and-forget queue, drop-on-full), test_index.py (index-first writes, indexed reads, backfill).