diff --git a/Makefile b/Makefile index 4ef94efd..84da7614 100644 --- a/Makefile +++ b/Makefile @@ -79,3 +79,11 @@ utils-docker: rm -rf utils mkdir -p utils docker build -f docker-compose/utils/Dockerfile --output=utils . + +MONITOR_PORT ?= 8090 +monitoring: + docker build -f docker-compose/monitoring/Dockerfile -t monitoring . + docker run \ + -p $(MONITOR_PORT):$(MONITOR_PORT) \ + -e MONITOR_PORT=$(MONITOR_PORT) \ + monitoring diff --git a/README.md b/README.md index 12648b65..edd4b69c 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,31 @@ on special cases. This script requires an input file whose structure can be foun - **refund_user_pegout**: executes a refund for a user's peg-out operation through the Liquidity Bridge Contract. This is used when a peg-out operation needs to be refunded back to the user's RSK address. The script requires the quote hash of the operation to refund. - **key_conversion**: shows the corresponding BTC and RSK address for a given private key and encrypts it into a keystore, accepts the key either in WIF or hex format. The key can be provided through the terminal, a file or an existing keystore. +### Monitoring Service +The project includes a Bitcoin balance monitoring service that tracks specified BTC addresses and exposes metrics at `http://:8080/metrics` using Prometheus `https://prometheus.io/`. + +To run the monitoring service with the default port (8090): +```bash +make monitoring +``` + +To run the monitoring service with a custom port (e.g., 8091): +```bash +make monitoring MONITOR_PORT=8091 +``` + +The service is configured in `docker-compose/monitoring/src/config.ts` and supports both testnet and mainnet monitoring: + +- MONITORED_ADDRESSES: The set of addresses to be monitored. Each address should have an alias that will be used in the metrics. +- MONITOR_CONFIG: The configuration for the monitoring service. + - pollingIntervalSeconds: How often the service will check the bitcoin balance of the monitored addresses in seconds. + - monitorName: The name of the monitoring service. + - network: The network to monitor (mainnet or testnet). + - port: The port where the service will be exposed. + +The service can be configured to monitor other addresses by modifying the `MONITORED_ADDRESSES` array in `docker-compose/monitoring/src/config.ts`. + + ### More information If you're looking forward to integrate with Flyover Protocol then you can check the [Flyover SDK repository](https://github.com/rsksmart/unified-bridges-sdk/tree/main/packages/flyover-sdk). diff --git a/docker-compose/monitoring/.dockerignore b/docker-compose/monitoring/.dockerignore new file mode 100644 index 00000000..3f1fdea4 --- /dev/null +++ b/docker-compose/monitoring/.dockerignore @@ -0,0 +1,5 @@ +node_modules +**/node_modules +npm-debug.log +dist +lib \ No newline at end of file diff --git a/docker-compose/monitoring/Dockerfile b/docker-compose/monitoring/Dockerfile new file mode 100644 index 00000000..01568f3b --- /dev/null +++ b/docker-compose/monitoring/Dockerfile @@ -0,0 +1,13 @@ +FROM node:18-alpine + +# Set working directory to monitoring project +WORKDIR /app/monitoring + +# Copy only the monitoring project files +COPY docker-compose/monitoring ./ + +# Install dependencies and build +RUN npm install && npm run build + +# Run the monitoring service +CMD ["npx", "ts-node", "src/index.ts"] \ No newline at end of file diff --git a/docker-compose/monitoring/package.json b/docker-compose/monitoring/package.json new file mode 100644 index 00000000..b80049ae --- /dev/null +++ b/docker-compose/monitoring/package.json @@ -0,0 +1,20 @@ +{ + "name": "bitcoin", + "version": "1.0.0", + "description": "Bitcoin balance monitor sample", + "main": "dist/index.js", + "scripts": { + "build": "tsc", + "start": "ts-node src/index.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@mempool/mempool.js": "^2.3.0", + "@types/node": "^20.11.19", + "ts-node": "^10.9.2", + "typescript": "^5.3.3", + "@rsksmart/rsk-monitor": "^0.1.0" + } +} diff --git a/docker-compose/monitoring/src/config.ts b/docker-compose/monitoring/src/config.ts new file mode 100644 index 00000000..0426ec1b --- /dev/null +++ b/docker-compose/monitoring/src/config.ts @@ -0,0 +1,14 @@ +import { type BitcoinAddress } from '@rsksmart/rsk-monitor' + +export const MONITORED_ADDRESSES: BitcoinAddress[] = [ + { address: 'mwEc...', alias: 'testnet1' }, + { address: 'mvL2...', alias: 'testnet2' }, + { address: 'tb1q7...', alias: 'testnet3' } +] + +export const MONITOR_CONFIG = { + pollingIntervalSeconds: 10, + monitorName: 'bitcoin-balance-monitor', + network: 'testnet' as 'mainnet' | 'testnet', + port: parseInt(process.env.MONITOR_PORT || '8090', 10) +} \ No newline at end of file diff --git a/docker-compose/monitoring/src/index.ts b/docker-compose/monitoring/src/index.ts new file mode 100644 index 00000000..434eae4b --- /dev/null +++ b/docker-compose/monitoring/src/index.ts @@ -0,0 +1,24 @@ +import { BitcoinMempoolMonitorBuilder, ConsoleExporter, MonitorConfig, PrometheusExporter } from '@rsksmart/rsk-monitor' +import { MONITORED_ADDRESSES, MONITOR_CONFIG } from './config' + +async function main (): Promise { + await BitcoinMempoolMonitorBuilder.create({ + pollingIntervalSeconds: MONITOR_CONFIG.pollingIntervalSeconds, + monitorName: MONITOR_CONFIG.monitorName, + network: MONITOR_CONFIG.network + } as MonitorConfig, MONITORED_ADDRESSES) + .withBalanceMetric() + .withExporters(new ConsoleExporter(), new PrometheusExporter(MONITOR_CONFIG.port, 'bitcoinbalancemonitor')) + .build() + .run() + + console.log('Starting Bitcoin balance monitor...') + console.log('Monitoring addresses:', MONITORED_ADDRESSES) + + process.on('SIGINT', () => { + console.log('Stopping monitor...') + process.exit(0) + }) +} + +main().catch(console.error) diff --git a/docker-compose/monitoring/tsconfig.json b/docker-compose/monitoring/tsconfig.json new file mode 100644 index 00000000..9c583519 --- /dev/null +++ b/docker-compose/monitoring/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} \ No newline at end of file