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:
- 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. - 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).