An activity tracking and updating service for Powerloom's Decentralized Sequencer-Validator (DSV) Protocol that maintains accurate snapshotter and validator activity metrics and synchronizes with the Data Market and Protocol State contracts.
This peer acts as a neutral observer and source for snapshotter and validator activity tracking in the Powerloom protocol. It:
- Tracks Validator Finalizations: Listens to finalized batches from all validators via the validator mesh
- Aggregates by Consensus: Applies majority vote logic to determine canonical state per epoch
- Updates On-Chain State: Keeps protocol contracts synchronized with:
- Finalized submission counts per epoch
- EOD (End of Day) counts of slots passing daily snapshot quota
- EOD final submission counts
- Extensible Protocol Coverage: Designed to track wider protocol activity in future releases
- Event Monitor: Watches
EpochReleasedevents from Protocol State contract - Window Manager: Manages aggregation windows per
(epochID, dataMarket)pair - Batch Processor: Receives and tracks finalized batches from validators
- Consensus Engine: Aggregates validator outputs using majority vote logic
- Activity Updater: Submits on-chain updates for snapshotter activity metrics
- Relayer Integration: Queues and broadcasts update transactions via relayer-py
- Dashboard API: Optional web dashboard for network activity visualization
The optional dashboard API provides real-time visualization of network activity:
- Network Topology: Interactive force-directed graph showing validators, slots, and projects
- Epoch Tracking: View per-epoch aggregations and validator contributions
- Validator Leaderboard: See which validators are most active
- Slot Eligibility: Track slot submission counts and eligibility status
Access at http://localhost:8080 when enabled (see Dashboard Configuration below).
EpochReleased Event
↓
Level 1 Finalization Delay (wait for DSV internal aggregation)
↓
Aggregation Window Open (collect validator batches)
↓
Consensus Aggregation (majority vote per project/CID)
↓
Extract Activity Metrics:
- Finalized submissions per slot
- Slots passing daily quota
- EOD final counts
↓
On-Chain Update (via relayer-py or direct)
- Docker and Docker Compose
- Access to libp2p bootstrap peers (validator mesh)
- RPC URL for event monitoring
- Protocol State and Data Market contract addresses
- Trusted updater signer addresses (pre-configured in ProtocolState)
The docker-compose setup includes:
snapshot-activity-tracker: Main tracking servicerelayer-py: Transaction relayer for on-chain updatesredis: State managementrabbitmq: Transaction queueing
cp .env.example .envEdit .env with your configuration:
# Core networking
BOOTSTRAP_PEERS=/ip4/1.2.3.4/tcp/4001/p2p/QmPeerID1,/ip4/5.6.7.8/tcp/4001/p2p/QmPeerID2
GOSSIPSUB_FINALIZED_BATCH_PREFIX=/powerloom/dsv-devnet-alpha/finalized-batches
GOSSIPSUB_VALIDATOR_PRESENCE_TOPIC=/powerloom/dsv-devnet-alpha/validator/presence
# Contract addresses
PROTOCOL_STATE_CONTRACT=0xYourProtocolStateAddress
DATA_MARKET_ADDRESS=0xYourDataMarketAddress
POWERLOOM_RPC_URL=https://your-powerloom-rpc-url-here
POWERLOOM_RPC_NODES=https://your-rpc-node-1,https://your-rpc-node-2
# Window timing
LEVEL1_FINALIZATION_DELAY_SECONDS=10
AGGREGATION_WINDOW_SECONDS=20
# Update configuration
ENABLE_CONTRACT_UPDATES=true
SUBMISSION_UPDATE_EPOCH_INTERVAL=10
CONTRACT_UPDATE_METHOD=relayer
RELAYER_URL=http://relayer-py:8080
RELAYER_AUTH_TOKEN=your_secure_token_here
# Relayer-py signers (must be in ProtocolState.trustedUpdaters)
VPA_SIGNER_ADDRESSES=0xSigner1,0xSigner2,0xSigner3
VPA_SIGNER_PRIVATE_KEYS=key1,key2,key3
AUTH_TOKEN=${RELAYER_AUTH_TOKEN}
# Tally dumps (optional, for monitoring/debugging)
ENABLE_TALLY_DUMPS=true
TALLY_DUMP_DIR=./tallies
TALLY_RETENTION_DAYS=7Before enabling contract updates, signer addresses must be added to ProtocolState:
// From contract owner
ProtocolState.addTrustedUpdater(0xSigner1)
ProtocolState.addTrustedUpdater(0xSigner2)Verify:
ProtocolState.trustedUpdaters(0xSigner1) // Returns true./bootstrap.sh # Clones relayer-py (optional - start.sh handles this)
./start.sh # Auto-detects and builds or uses pre-built imageThe start.sh script automatically:
- Checks if
./relayer-pyexists - If exists: builds from source (development mode)
- If missing: uses pre-built Docker image (production mode)
The start.sh script supports three operation modes:
./start.sh
# or
./start.sh fullStarts: tracker, redis, relayer-py, rabbitmq, dashboard-api
- Watching + on-chain commitment + dashboard
- Est. RAM: ~1.5GB
./start.sh watcherStarts: tracker, redis, dashboard-api
- Watching + dashboard (no on-chain updates)
- Est. RAM: ~800MB
./start.sh minimalStarts: tracker, redis only
- Watching only (collect finalizations, save tallies)
- No dashboard, no on-chain
- Est. RAM: ~400MB
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f snapshot-activity-tracker
docker-compose logs -f relayer-py
# Health checks
docker-compose exec relayer-py curl http://localhost:8080/health
docker-compose exec redis redis-cli ping./stop.sh-
Finalized Submission Counts (Per Epoch)
- Aggregated from all validators via consensus
- Counts unique slots with submissions per project
- Updated on-chain every N epochs (configurable)
-
EOD Slot Quota Status
- Tracks which slots passed the daily snapshot quota threshold
- Aggregated at end of each day
- Enables accurate reward distribution
-
EOD Final Submission Counts
- Final count of all submissions for the day
- Used for reward calculations and protocol analytics
The service aggregates validator outputs using majority vote:
- Per
(projectID, slotID)combination - Selects CID with most validator votes
- Merges submission metadata from all validators
- Produces canonical finalized batch per epoch
| Variable | Default | Description |
|---|---|---|
BOOTSTRAP_PEERS |
required | Comma-separated validator peer addresses |
PROTOCOL_STATE_CONTRACT |
required | Protocol State contract address |
DATA_MARKET_ADDRESS |
required | Data Market contract address |
POWERLOOM_RPC_URL |
required | RPC URL for event monitoring |
POWERLOOM_RPC_NODES |
required | Comma-separated RPC nodes for relayer |
LEVEL1_FINALIZATION_DELAY_SECONDS |
10 |
Wait for DSV Level 1 aggregation |
AGGREGATION_WINDOW_SECONDS |
20 |
Window to collect validator batches |
ENABLE_CONTRACT_UPDATES |
false |
Enable on-chain updates |
SUBMISSION_UPDATE_EPOCH_INTERVAL |
10 |
Update every N epochs |
CONTRACT_UPDATE_METHOD |
relayer |
relayer or direct |
RELAYER_URL |
http://relayer-py:8080 |
Relayer service URL |
VPA_SIGNER_ADDRESSES |
required | Signer addresses (must be trusted updaters) |
VPA_SIGNER_PRIVATE_KEYS |
required | Signer private keys (no 0x prefix) |
DASHBOARD_PORT |
8080 |
Dashboard API port |
ENABLE_DASHBOARD |
true |
Enable dashboard API service |
The dashboard is an optional service that visualizes network activity from tracker data.
Add to your .env:
# Dashboard API
DASHBOARD_PORT=8080
ENABLE_DASHBOARD=trueWhen iterating on dashboard UI, avoid rebuilding the whole stack:
-
Start backend (watcher or full mode):
./start.sh watcher # or full -
Run frontend locally with hot reload:
cd frontend && npm run dev
UI at http://localhost:3000 (proxies /api to dashboard-api). If DASHBOARD_PORT≠8080, set:
VITE_API_PROXY_TARGET=http://localhost:YOUR_PORT -
Rebuild only dashboard when needed:
docker compose build dashboard-api && docker compose up -d dashboard-api
Dashboard uses Dockerfile.dashboard; tracker uses Dockerfile. They are independent.
# Build dashboard-api binary
go build -o bin/dashboard-api ./cmd/dashboard-api
# Build frontend (in frontend/ directory)
cd frontend && npm install && npm run build && cd ..With docker-compose, the dashboard starts in watcher/full modes:
./start.sh watcher # or fullAccess at (production: embedded UI in container):
- UI:
http://localhost:${DASHBOARD_PORT:-8080} - API health:
http://localhost:${DASHBOARD_PORT:-8080}/api/health
| Endpoint | Description |
|---|---|
/api/health |
Health check |
/api/dashboard/summary |
Overview stats |
/api/network/topology |
Network graph data |
/api/epochs |
List epochs |
/api/validators |
Validator list |
/api/slots |
Slot list |
/api/projects |
Project vote counts |
/api/timeline |
Timeline of events |
- Verify signer addresses are in
ProtocolState.trustedUpdaters - Check
RELAYER_AUTH_TOKENmatchesAUTH_TOKENin relayer-py - Ensure signers have sufficient gas balance
- Verify
RELAYER_URLis correct (http://relayer-py:8080for docker-compose)
- Verify bootstrap peers are correct and reachable
- Check topic names match validator mesh configuration
- Ensure network connectivity to libp2p peers
- Verify
POWERLOOM_RPC_URLis accessible - Check
PROTOCOL_STATE_CONTRACTaddress is correct - Ensure contract emits
EpochReleasedevents
This service is designed to track broader protocol activity:
- Additional snapshotter metrics
- Cross-epoch activity aggregation
- Protocol-wide health monitoring
- Extended reward distribution tracking
MIT License