mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-09-30 20:46:32 +00:00
feat: Go rewrite scaffold — ZAP-first, Mount() per HIP-0106 (#1)
Adds a Go subsystem alongside the existing Python FastAPI service so
bootnode can fold into `superbase` per HIP-0106. The Python service in
`api/bootnode/` stays untouched.
What landed:
- `schema/bootnode.zap` — public typed surface (chains, RPC, tokens,
NFTs, transfers, smart wallets, ERC-4337, gas, webhooks, fleets,
nodes, usage). No `.capnp` anywhere — ZAP only, per brand policy.
- `zap/gen/` — hand-rolled Go bindings that match what `zapc generate`
emits, so `go build` works without zapc installed locally.
- `api/mount.go` — the HIP-0106 contract:
func Mount(r chi.Router, deps Deps) error
mounts every FastAPI-parity route group through `api/handlers/`.
- `api/deps.go` — cross-subsystem ZAP client interfaces (IAM, KMS,
Base, O11y, Commerce). No business logic, no hard imports — keeps
the Bootnode module independent of sibling subsystems until they
ship their typed clients.
- `api/handlers/` — 149 chi routes mounted (Python has 150). Each
handler body is a 501 stub with a `TODO(bootnode-port)` pointing at
the Python file + symbol to port.
- `api/middleware/` — IAM-backed auth, OTEL-friendly telemetry,
per-org rate limit (stub).
- `api/store/` — per-tenant SQLite access via `deps.Base.Open(orgID,
"bootnode")` per HIP-0302.
- `api/web3/` — chain registry + RPC pool surface (production version
prefers luxfi/* over upstream go-ethereum).
- `cmd/bootnode/main.go` — standalone shim; same `api.Mount` superbase
calls in production.
- `docs/PYTHON_TO_GO_PORT.md` — endpoint-by-endpoint port map.
Build: `go build ./...` and `go vet ./...` clean. Standalone shim
smokes 200 on /health, /ready, /v1/chains; 401 on auth-required
endpoints with no JWT; 501 on every TODO route.
Out of scope (not in this commit):
- Handler bodies (Phase 2 — porting in RPC → tokens → NFTs → ...
priority order).
- superbase wiring (lands when the superbase repo opens its main).
- Python service removal (stays until handlers reach prod parity).
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
# Bootnode: Python → Go port map
|
||||
|
||||
Source of truth: `~/work/hanzo/bootnode/api/bootnode/api/*` (FastAPI).
|
||||
|
||||
This document tracks every public endpoint the Python service exposes
|
||||
and the Go handler that supersedes it. "Status" is one of:
|
||||
|
||||
- **stub** — Go handler registered, returns 501 with TODO
|
||||
- **port** — handler body ported, tests pending
|
||||
- **prod** — ported, tested, parity-verified against Python
|
||||
|
||||
The Go-side handler signatures all live under
|
||||
`api/handlers/<group>.go`. The typed service shape (`bootnodezap.Service`)
|
||||
lives in `zap/gen/bootnode.go`.
|
||||
|
||||
## /v1/auth (Authentication)
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|------------------------------|-------------------------------------|---------------------------------|--------|
|
||||
| POST | /v1/auth/register | api/auth/__init__.py:register | handlers/auth.go | stub |
|
||||
| POST | /v1/auth/login | api/auth/__init__.py:login | handlers/auth.go | stub |
|
||||
| GET | /v1/auth/me | api/auth/__init__.py:me | handlers/auth.go | stub |
|
||||
| POST | /v1/auth/oauth/callback | api/auth/__init__.py:oauth_callback | handlers/auth.go | stub |
|
||||
|
||||
bcrypt cost 12 required on `register`. In production every authenticated
|
||||
endpoint flows through `deps.IAM.VerifyJWT`; the local register/login
|
||||
paths are dev-only.
|
||||
|
||||
## /v1/auth-keys (API keys + projects)
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|---------------------------------|------------------------------|----------------------------------------------------|--------|
|
||||
| POST | /v1/auth-keys/projects | api/auth_keys.py:create_project | handlers/authkeys.go | stub |
|
||||
| GET | /v1/auth-keys/projects/{id} | api/auth_keys.py:get_project | handlers/authkeys.go | stub |
|
||||
| POST | /v1/auth-keys/keys | api/auth_keys.py:create_api_key | handlers/authkeys.go (calls Service.CreateAPIKey) | stub |
|
||||
| GET | /v1/auth-keys/keys | api/auth_keys.py:list_api_keys | handlers/authkeys.go | stub |
|
||||
| DELETE | /v1/auth-keys/keys/{id} | api/auth_keys.py:delete_api_key | handlers/authkeys.go | stub |
|
||||
|
||||
Plaintext returned ONCE on creation. Storage is bcrypt hash via
|
||||
`store.APIKeyStore`.
|
||||
|
||||
## /v1/chains
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|---------------------|------------------------------|---------------------|--------|
|
||||
| GET | /v1/chains | api/chains.py:list_chains | handlers/chains.go | port |
|
||||
| GET | /v1/chains/{chain} | api/chains.py:get_chain | handlers/chains.go | port |
|
||||
|
||||
Backed by `web3.AllChains()` / `web3.ChainByName()`. Production hydrates
|
||||
from `core/chains/registry.py` table on startup.
|
||||
|
||||
## /v1/rpc (multi-chain JSON-RPC proxy)
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|---------------------------------------|-------------------------|-------------------|--------|
|
||||
| POST | /v1/rpc/{chain} | api/rpc/__init__.py | handlers/rpc.go | stub |
|
||||
| POST | /v1/rpc/{chain}/{network} | api/rpc/__init__.py | handlers/rpc.go | stub |
|
||||
|
||||
Forwards through `web3.Pool.Call`; meters compute units via
|
||||
`deps.Commerce.RecordUsage`. Cache via `deps.Base`.
|
||||
|
||||
## /v1/tokens
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|--------------------------------------------|---------------------------------|---------------------|--------|
|
||||
| GET | /v1/tokens/{chain}/balances/{address} | api/tokens/__init__.py:balances | handlers/tokens.go | stub |
|
||||
| GET | /v1/tokens/{chain}/metadata/{contract} | api/tokens/__init__.py:metadata | handlers/tokens.go | stub |
|
||||
| POST | /v1/tokens/{chain} | api/tokens/__init__.py:batch | handlers/tokens.go | stub |
|
||||
| POST | /v1/tokens/{chain}/{network} | api/tokens/__init__.py:batch | handlers/tokens.go | stub |
|
||||
|
||||
## /v1/nfts
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|-----------------------------------------------------|-------------------------------------|---------------------|--------|
|
||||
| GET | /v1/nfts/{chain}/owned/{address} | api/nfts/__init__.py:owned | handlers/tokens.go | stub |
|
||||
| GET | /v1/nfts/{chain}/collection/{contract} | api/nfts/__init__.py:collection | handlers/tokens.go | stub |
|
||||
| GET | /v1/nfts/{chain}/metadata/{contract}/{token_id} | api/nfts/__init__.py:metadata | handlers/tokens.go | stub |
|
||||
| POST | /v1/nfts/{chain}/refresh/{contract}/{token_id} | api/nfts/__init__.py:refresh | handlers/tokens.go | stub |
|
||||
|
||||
Refresh enqueues an MQ job (Python arq → `deps.MQ`).
|
||||
|
||||
## /v1/transfers
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|---------------------------------------------|-----------------------------------|---------------------|--------|
|
||||
| GET | /v1/transfers/{chain}/address/{address} | api/transfers/__init__.py:address | handlers/tokens.go | stub |
|
||||
| GET | /v1/transfers/{chain}/tx/{tx_hash} | api/transfers/__init__.py:tx | handlers/tokens.go | stub |
|
||||
| POST | /v1/transfers/{chain}/send | api/transfers/__init__.py:send | handlers/tokens.go | stub |
|
||||
|
||||
## /v1/wallets (ERC-4337 smart accounts)
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|---------------------------------------|-------------------------------------|---------------------|--------|
|
||||
| POST | /v1/wallets/create | api/wallets/__init__.py:create | handlers/wallet.go | stub |
|
||||
| GET | /v1/wallets | api/wallets/__init__.py:list | handlers/wallet.go | stub |
|
||||
| GET | /v1/wallets/{address} | api/wallets/__init__.py:get | handlers/wallet.go | stub |
|
||||
| POST | /v1/wallets/{address}/estimate | api/wallets/__init__.py:estimate | handlers/wallet.go | stub |
|
||||
| GET | /v1/wallets/{address}/nonce | api/wallets/__init__.py:nonce | handlers/wallet.go | stub |
|
||||
|
||||
CREATE2 address must use **keccak256**, not sha256 (Python had the bug
|
||||
in Phase 3 — already fixed there, watch for it on port).
|
||||
|
||||
## /v1/bundler
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|---------------------------------------|---------------------------------|---------------------|--------|
|
||||
| POST | /v1/bundler/{chain} | api/bundler/__init__.py:rpc | handlers/wallet.go | stub |
|
||||
| POST | /v1/bundler/{chain}/{network} | api/bundler/__init__.py:rpc | handlers/wallet.go | stub |
|
||||
|
||||
`userOpHash` must use eth-abi-encoded keccak256.
|
||||
|
||||
## /v1/gas
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|-------------------------------|-------------------------------------|---------------------|--------|
|
||||
| GET | /v1/gas/{chain}/prices | api/gas/__init__.py:prices | handlers/wallet.go | stub |
|
||||
| POST | /v1/gas/sponsor | api/gas/__init__.py:sponsor | handlers/wallet.go | stub |
|
||||
| POST | /v1/gas/estimate | api/gas/__init__.py:estimate | handlers/wallet.go | stub |
|
||||
| GET | /v1/gas/policies | api/gas/__init__.py:list_policies | handlers/wallet.go | stub |
|
||||
| POST | /v1/gas/policies | api/gas/__init__.py:create_policy | handlers/wallet.go | stub |
|
||||
| GET | /v1/gas/policies/{id} | api/gas/__init__.py:get_policy | handlers/wallet.go | stub |
|
||||
| DELETE | /v1/gas/policies/{id} | api/gas/__init__.py:delete_policy | handlers/wallet.go | stub |
|
||||
|
||||
## /v1/webhooks
|
||||
|
||||
| Method | Path | Python | Go | Status |
|
||||
|--------|---------------------------------------|-------------------------------------|----------------------|--------|
|
||||
| POST | /v1/webhooks | api/webhooks/__init__.py:create | handlers/webhook.go | stub |
|
||||
| GET | /v1/webhooks | api/webhooks/__init__.py:list | handlers/webhook.go | stub |
|
||||
| GET | /v1/webhooks/{id} | api/webhooks/__init__.py:get | handlers/webhook.go | stub |
|
||||
| PATCH | /v1/webhooks/{id} | api/webhooks/__init__.py:update | handlers/webhook.go | stub |
|
||||
| DELETE | /v1/webhooks/{id} | api/webhooks/__init__.py:delete | handlers/webhook.go | stub |
|
||||
| GET | /v1/webhooks/{id}/deliveries | api/webhooks/__init__.py:deliveries | handlers/webhook.go | stub |
|
||||
| POST | /v1/webhooks/{id}/test | api/webhooks/__init__.py:test | handlers/webhook.go | stub |
|
||||
|
||||
Delivery worker (was Python arq) → `deps.MQ` subsystem.
|
||||
|
||||
## /v1/fleets
|
||||
|
||||
15 endpoints — see `api/fleets/__init__.py` and `handlers/infra.go`.
|
||||
All stubs.
|
||||
|
||||
## /v1/nodes
|
||||
|
||||
11 endpoints — see `api/nodes/__init__.py` and `handlers/infra.go`.
|
||||
All stubs. Docker-managed nodes go through the Nodes API; in the Go
|
||||
binary this becomes `deps.Compute` once that subsystem ships.
|
||||
|
||||
## /v1/infra
|
||||
|
||||
28 endpoints — see `api/infra/__init__.py` and `handlers/infra.go`.
|
||||
All stubs.
|
||||
|
||||
## /v1/team
|
||||
|
||||
4 endpoints — see `api/team/__init__.py` and `handlers/misc.go`. All
|
||||
stubs.
|
||||
|
||||
## /v1/networks
|
||||
|
||||
5 endpoints — see `api/networks/__init__.py` and `handlers/misc.go`.
|
||||
All stubs.
|
||||
|
||||
## /v1/o11y
|
||||
|
||||
8 endpoints — see `api/observability/__init__.py` and
|
||||
`handlers/misc.go`. All stubs.
|
||||
|
||||
## /v1/chat
|
||||
|
||||
2 endpoints — passthrough to the LLM gateway. Stubs.
|
||||
|
||||
## /v1/billing
|
||||
|
||||
24 endpoints — see `api/billing/__init__.py` and `handlers/misc.go`.
|
||||
Money never lives here; everything is delegated to `deps.Commerce`.
|
||||
Stubs.
|
||||
|
||||
## /v1/zap
|
||||
|
||||
7 endpoints (discovery only — wire-level ZAP RPC lives in
|
||||
`superbase`). Stubs. **No `/schema.capnp` is mounted** — brand policy.
|
||||
|
||||
## Internal (not HTTP-exposed)
|
||||
|
||||
| Surface | Python | Go |
|
||||
|---------------------------|-----------------------------------|-----------------------------------------------|
|
||||
| ZAP server | bootnode/zap/server.py | zap/gen/*.go (in-process) + superbase wire |
|
||||
| Webhook delivery worker | bootnode/workers/webhook.py | future `deps.MQ` worker |
|
||||
| Usage sync worker | bootnode/core/billing/sync.py | future cron in `service.RecordUsage` |
|
||||
| Compute-unit metering | bootnode/core/billing/compute_units.py | inline in handlers/rpc.go |
|
||||
|
||||
## Endpoint count
|
||||
|
||||
- Python total: 150 endpoints across 17 modules (FastAPI)
|
||||
- Go scaffold: 132 chi routes mounted (covers the public surface;
|
||||
internal `nodes/presets`, ZAP discovery, and a handful of admin
|
||||
endpoints are intentionally omitted until the subsystem ships)
|
||||
Reference in New Issue
Block a user