Add indexer profileRecency index, recent-profile ordering, and backfill specs; seed profileRecency in the recent-profile-identity fixture; mark the feature in progress in the backlog. By specifier.
psf-memo-indexer
Indexes Memo protocol transactions on Bitcoin Cash. Architecture mirrors psf-slp-indexer-g2.
Overview
Two processes:
- Block indexer — IBD from block 525000, then ZMQ new-block processing
- TX indexer — mempool transactions via ZMQ after IBD signals
/tx-start
Data is stored in psf-memo-db via REST.
Developer documentation
Architecture, theory of operation, and design tradeoffs: dev-docs/.
Requirements
- node ^20
- npm ^10
- BCH full node (RPC + ZMQ)
- Running psf-memo-db
Installation
cd psf-memo-indexer
npm install
cp .env-example .env
Usage
Start the database:
cd ../psf-memo-db && npm start
Block indexer:
npm run block-indexer
TX indexer (separate terminal):
npm run tx-indexer
Configuration
See .env-example. Key variables:
| Variable | Default | Description |
|---|---|---|
PSF_MEMO_DB_URL |
http://localhost:5021 |
psf-memo-db URL |
START_BLOCK_HEIGHT |
525000 |
First block to index |
RPC_IP / RPC_PORT |
172.17.0.1 / 8332 |
Full node RPC |
ZMQ_PORT |
28332 |
Full node ZMQ |
TX_REST_API_PORT |
5455 |
TX indexer control API |
FILTER_CONCURRENCY |
20 |
Parallel Memo tx detection per block |
MEMO_TX_CONCURRENCY |
20 |
Parallel Memo tx processing per block |
DEBUG_LEVEL |
0 |
0 = block summary only; 1 = log each Memo tx action type and success/failure |
Tests
npm test
Production (Docker)
Docker Compose under production/docker runs the full stack. Build context is the psf-memo monorepo root; each image copies its package (psf-memo-db, psf-memo-indexer, or psf-memo-client) from the local checkout.
Services
| Service | Container | Host port | Purpose |
|---|---|---|---|
memo-db |
memo-db |
5021 |
LevelDB REST API (psf-memo-db/) |
block-indexer |
memo-block-indexer |
— | IBD + ZMQ block indexing |
tx-indexer |
memo-tx-indexer |
5455 |
Mempool TX indexing (/tx-start control API) |
memo-client |
memo-client |
3000 |
React SPA (psf-memo-client/), nginx |
LevelDB data persists on the host at production/data/leveldb.
Prerequisites
- Docker Engine and Docker Compose v2 (
docker compose) - A Bitcoin Cash full node with RPC and ZMQ reachable from the containers
- On a typical Linux Docker host, the bridge gateway
172.17.0.1reaches services on the host (RPC, ZMQ, and sibling containers published on host ports)
1. Configure environment files
cd production/docker
cp memo-db/.env-example memo-db/.env
cp block-indexer/.env-example block-indexer/.env
cp tx-indexer/.env-example tx-indexer/.env
cp memo-client/.env-example memo-client/.env
Edit each .env before building or starting.
memo-db/.env
| Variable | Typical value | Description |
|---|---|---|
PORT |
5021 |
REST API listen port |
SVC_ENV |
prod |
Runtime environment |
BACKUP_QTY |
3 |
How many epoch zip backups to keep |
EXIT_ON_MISSING_BACKUP |
false |
Exit if expected backup is missing |
block-indexer/.env and tx-indexer/.env
| Variable | Typical Docker value | Description |
|---|---|---|
PSF_MEMO_DB_URL |
http://172.17.0.1:5021 |
URL of memo-db from inside the container |
RPC_IP / RPC_PORT |
172.17.0.1 / 8332 |
BCH full node RPC |
ZMQ_PORT |
28332 |
BCH full node ZMQ |
RPC_USER / RPC_PASS |
(your node auth) | RPC credentials |
TX_REST_API_PORT |
5455 |
TX indexer HTTP port |
TX_REST_API_IP |
172.17.0.1 |
Where the block indexer reaches the TX indexer |
START_BLOCK_HEIGHT |
525000 |
First block (block indexer only) |
FILTER_CONCURRENCY / MEMO_TX_CONCURRENCY |
20 |
Parallelism (block indexer) |
DEBUG_LEVEL |
0 |
Block-indexer log verbosity |
SEEN_TX_MAX |
100000 |
TX indexer seen-tx cache size |
Use a hostname or IP your containers can actually reach for RPC, ZMQ, and memo-db. 172.17.0.1 is the usual Docker bridge address when those services are published on the host.
memo-client/.env
| Variable | Example | Description |
|---|---|---|
REACT_APP_MEMO_DB_URL |
http://localhost:5021 |
Browser-facing base URL of memo-db (no trailing slash) |
This value is baked into the SPA at image build time. Create React App reads it from memo-client/.env during npm run build.
- Local / same-machine browser:
http://localhost:5021(orhttp://<host-ip>:5021) - Separate domains:
https://api.mydomain.comwhen the client is athttps://client.mydomain.com
Changing REACT_APP_MEMO_DB_URL requires rebuilding the memo-client image (see below).
2. Build images
cd production/docker
docker compose build
Rebuild a single service after changing its Dockerfile or (for the client) .env:
docker compose build --no-cache memo-client
docker compose build block-indexer
docker compose build tx-indexer
docker compose build memo-db
block-indexer and tx-indexer use explicit image names (memo-block-indexer, memo-tx-indexer) so they do not collide with similarly named images from other projects (for example psf-slp-indexer-g2).
3. Start the stack
Preferred order: database first, then indexers, then the client.
cd production/docker
docker compose up -d memo-db
docker compose up -d block-indexer tx-indexer
docker compose up -d memo-client
Or start everything at once:
docker compose up -d
4. Verify
| Check | URL / command |
|---|---|
| Database API / docs | http://localhost:5021/ |
| Database health | http://localhost:5021/health |
| TX indexer | http://localhost:5455/ (control API; /tx-start after IBD) |
| Front-end client | http://localhost:3000/ |
docker compose ps
docker compose logs -f memo-db
docker compose logs -f block-indexer
docker compose logs -f tx-indexer
docker compose logs -f memo-client
5. Day-to-day operations
# Stop all services
docker compose down
# Restart one service
docker compose restart block-indexer
# Rebuild and recreate after config or image changes
docker compose up -d --build memo-client
Start scripts under each service directory (start-*.sh) and .env files are bind-mounted into the containers. Edit them on the host and restart the service (no rebuild) unless you changed something that only applies at image build time (notably memo-client/.env).
Production domains example
When the client and API are on different hostnames:
-
Set
memo-client/.env:REACT_APP_MEMO_DB_URL=https://api.mydomain.com -
Rebuild and redeploy the client:
docker compose build --no-cache memo-client docker compose up -d memo-client -
Reverse-proxy:
client.mydomain.com→ host port3000(memo-client)api.mydomain.com→ host port5021(memo-db)
memo-db enables CORS with origin: '*', so the browser may call the API from another subdomain once HTTPS and DNS are in place.
License
GPL v3