PayChain is a minimal payment system prototype built with Go, Kafka, and a blockchain. Transfers are accepted via HTTP API, pushed into Kafka for buffering, concurrently consumed into a pending pool, and periodically batched into blocks that are mined using a ProofâofâWork (PoW) worker pool. A React TypeScript frontend provides a dashboard for submitting transfers and observing balances, pending transactions, and the blockchain.
- Transfer API backed by Kafka for decoupling and buffering
- Concurrent Kafka consumption into a threadâsafe transaction pool
- Asynchronous block packing with batch threshold (default 3)
- PoW mining with a CPUâparallel worker pool and cancelable context
- Threadâsafe blockchain storage and account balance store
- Faucet endpoint for demo balance topâup
- React 18 + TypeScript UI with Ant Design, Tailwind CSS, Zustand, TanStack Query, Axios
Screen.Recording.2025-08-20.221500.mp4
- API (Gin):
- POST /transfer â publish transaction to Kafka
- GET /balance/:user â read balance
- GET /blockchain â list all blocks
- GET /pending â list pending transactions
- POST /faucet â mint to a user (demo only)
- Kafka (Sarama): Async producer and consumer group
- Pool: Mutexâguarded slice as the pending transaction pool
- Blockchain:
- Block and Transaction data structures
- Chain: append with mutex, read with RWMutex
- PoW: parallel nonce search using goroutines over disjoint ranges
- Accounts: RWMutexâprotected map with batch preâvalidation and atomic batch apply
- Frontend: Singleâpage dashboard (React) for transfer, balance, pending, blockchain
- Backend
- Go (Gin, Sarama)
- Concurrency: goroutines, channels, context cancelation, sync.Mutex/RWMutex
- Blockchain: PoW, block hashing, chain storage
- Logging: std log wrapper
- Middleware
- Apache Kafka (Zookeeper for Bitnami image)
- Frontend
- React 18, TypeScript, Vite
- Ant Design, Tailwind CSS
- Zustand (lightweight state)
- TanStack Query (fetching, cache, polling)
- Axios (HTTP client)
- Containerization
- Docker, Docker Compose
- Kafka consumers run in background, pushing messages to a mutexâprotected pool
- A dedicated goroutine performs block packing:
- Only when pool.Size() â„ batchSize (default 3)
- Preâvalidate transactions against an account snapshot to form a valid set
- Mine the candidate block using PoW with N=NumCPU workers
- After a solution, atomically apply the exact mined set; append block if commit succeeds
- No mutation of block contents postâmining (hash remains valid)
- Block fields: Index, Timestamp, Transactions, PrevHash, Hash, Nonce
- Hash = SHAâ256 over concatenated fields + transactions string
- PoW difficulty: leading zeros (default 3)
- Worker pool: each goroutine iterates nonce = start + k*workers; on first success, cancel others via context
- Producer: async, JSONâencodes Transaction to topic
paychain-transactions - Consumer: consumer group with range rebalancing; JSONâdecodes and adds to pool; offsets are marked on consume
- dockerâcompose enables autoâtopic creation for quickstart
- POST /transfer
- Body: { "from": string, "to": string, "amount": number }
- Response: { "status": "queued" }
- GET /balance/:user â { user, balance }
- GET /blockchain â Block[]
- GET /pending â Transaction[]
- POST /faucet
- Body: { "to": string, "amount": number }
- Response: { status, user, balance }
Prerequisites: Docker Desktop with Compose.
- Build images
docker compose build --no-cache
- Start stack
docker compose up -d
- Services
- Backend API: http://localhost:18080
- Frontend (optional service): http://localhost:5173
The compose file sets:
- Kafka broker:
kafka:9092(autoâcreate topics enabled) - Backend env:
KAFKA_BROKERS=kafka:9092 - Frontend env (container mode):
VITE_API_BASE_URL=http://paychain:8080
- Faucet (top up Alice):
POST http://localhost:18080/faucet
Content-Type: application/json
{"to":"alice","amount":1000}
- Transfer (enqueue; needs 3 to mine with defaults):
POST http://localhost:18080/transfer
Content-Type: application/json
{"from":"alice","to":"bob","amount":100}
- Inspect:
GET http://localhost:18080/pending
GET http://localhost:18080/blockchain
GET http://localhost:18080/balance/alice
GET http://localhost:18080/balance/bob
- This is a toy blockchain for demo/education. No persistence, consensus network, or security hardening
- Faucet is for demo only; do not enable in production
- Balances and chain are inâmemory only (lost on restart)
This project is licensed under the MIT License. See the LICENSE file for details.
đ If you found this project helpful, please â it and share it with others!