A high-performance Golang microservice that indexes pet transfer events from the Hyperledger Besu blockchain and provides gRPC API for querying transfer history.
- Real-time Event Listening: Subscribes to
ControllerChangedevents from PetDIDRegistry smart contract - Historical Sync: Syncs past events in chunks to avoid RPC range limits
- PostgreSQL Storage: Efficient storage and querying of transfer history
- gRPC API: Fast inter-service communication with api-gateway
- Health Checks: Kubernetes-ready health check endpoints
- Minimal Resources: Optimized for ~10m CPU, 32Mi RAM usage
blockchain-indexer/
├── cmd/indexer/ # Application entry point
├── internal/
│ ├── listener/ # Blockchain event listener
│ ├── grpc/ # gRPC server implementation
│ ├── db/ # PostgreSQL database layer
│ └── models/ # Data models
├── proto/ # Protobuf definitions
├── config/ # Configuration management
└── Dockerfile # Container image
- Go 1.21+
- PostgreSQL 13+
- Protocol Buffers compiler (protoc)
- Access to Hyperledger Besu RPC endpoint
- Clone and setup:
cd blockchain-indexer
cp .env.example .env
# Edit .env with your configuration- Install dependencies:
make deps- Generate protobuf code:
make proto- Build the application:
make buildEdit .env file:
# Server
GRPC_PORT=50052
# Blockchain
RPC_URL=http://your-besu-node:8545
PET_DID_REGISTRY_ADDRESS=0xYourContractAddress
START_BLOCK=0
CHAIN_ID=1337
# Database
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=blockchain_indexer
DB_SSL_MODE=disablemake runmake docker-build
make docker-runGet complete transfer history for a specific pet.
Request:
message GetPetTransferHistoryRequest {
string petDID = 1;
int32 limit = 2;
int32 offset = 3;
}Response:
message GetPetTransferHistoryResponse {
bool success = 1;
string petDID = 2;
int32 totalTransfers = 3;
repeated TransferEvent history = 4;
string error = 5;
}Get the current controller of a pet.
Request:
message GetPetCurrentControllerRequest {
string petDID = 1;
}Get all transfers involving a specific controller address.
Request:
message GetTransfersByControllerRequest {
string controllerAddress = 1;
int32 limit = 2;
int32 offset = 3;
}Get indexer synchronization statistics.
Response:
message GetIndexerStatsResponse {
bool success = 1;
int64 totalPetsTracked = 2;
int64 totalTransfers = 3;
int64 lastIndexedBlock = 4;
int64 currentBlockNumber = 5;
bool isSyncing = 6;
string lastSyncTime = 7;
}Kubernetes health check endpoint.
CREATE TABLE transfer_events (
id SERIAL PRIMARY KEY,
pet_did VARCHAR(255) NOT NULL,
previous_controller VARCHAR(255) NOT NULL,
new_controller VARCHAR(255) NOT NULL,
block_number BIGINT NOT NULL,
transaction_hash VARCHAR(255) NOT NULL,
timestamp BIGINT NOT NULL,
transfer_index INTEGER NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(pet_did, block_number, transaction_hash)
);CREATE TABLE indexer_status (
id SERIAL PRIMARY KEY,
last_indexed_block BIGINT NOT NULL DEFAULT 0,
is_syncing BOOLEAN NOT NULL DEFAULT false,
last_sync_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);The api-gateway communicates with this service via gRPC. Add to api-gateway:
// api-gateway/src/indexer/indexer.module.ts
ClientsModule.register([
{
name: 'INDEXER_GRPC_SERVICE',
transport: Transport.GRPC,
options: {
package: 'indexer',
protoPath: join(__dirname, '../../proto/indexer.proto'),
url: process.env.INDEXER_SERVICE_URL || 'localhost:50052',
},
},
])- CPU: ~10m (idle) to 50m (syncing)
- Memory: 32-64Mi
- Storage: ~1KB per transfer event
- Sync Speed: ~5000 blocks/second
See k8s/deployment.yaml for Kubernetes manifest with:
- Resource limits: 50m CPU, 64Mi RAM
- Health checks and readiness probes
- Single replica (event ordering)
The service logs all events:
- Event processing:
Processed transfer: PetDID=..., From=..., To=... - Sync progress:
Syncing blocks X to Y... - Health checks: Database and blockchain connectivity
MIT