diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index 821ab843cbb..a385e8b31f0 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -265,6 +265,7 @@ export default function getBaseConfigFactory() { }, }, metrics: { + enabled: false, host: '127.0.0.1', port: 9091, }, diff --git a/packages/dashmate/configs/defaults/getLocalConfigFactory.js b/packages/dashmate/configs/defaults/getLocalConfigFactory.js index 42254deb5de..11d47f1c830 100644 --- a/packages/dashmate/configs/defaults/getLocalConfigFactory.js +++ b/packages/dashmate/configs/defaults/getLocalConfigFactory.js @@ -30,6 +30,9 @@ export default function getLocalConfigFactory(getBaseConfig) { rpc: { port: 20002, }, + zmq: { + port: 49998, + }, }, platform: { gateway: { @@ -45,6 +48,13 @@ export default function getLocalConfigFactory(getBaseConfig) { enabled: false, }, }, + dapi: { + rsDapi: { + metrics: { + port: 29091, + }, + }, + }, drive: { tenderdash: { p2p: { diff --git a/packages/dashmate/configs/defaults/getTestnetConfigFactory.js b/packages/dashmate/configs/defaults/getTestnetConfigFactory.js index 5ea3bccc701..6d0aeafece3 100644 --- a/packages/dashmate/configs/defaults/getTestnetConfigFactory.js +++ b/packages/dashmate/configs/defaults/getTestnetConfigFactory.js @@ -30,6 +30,9 @@ export default function getTestnetConfigFactory(homeDir, getBaseConfig) { rpc: { port: 19998, }, + zmq: { + port: 39998, + }, spork: { address: 'yjPtiKh2uwk3bDutTEA2q9mCtXyiZRWn55', }, @@ -153,6 +156,13 @@ export default function getTestnetConfigFactory(homeDir, getBaseConfig) { }, }, }, + dapi: { + rsDapi: { + metrics: { + port: 19091, + }, + }, + }, }, network: NETWORK_TESTNET, }; diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index d1c091bf09d..735eacb86a4 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -1226,6 +1226,67 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) return configFile; }, + '2.2.0-dev.1': (configFile) => { + Object.entries(configFile.configs) + .forEach(([name, options]) => { + const defaultConfig = getDefaultConfigByNameOrGroup(name, options.group); + if (!options.platform.dapi.rsDapi) { + options.platform.dapi.rsDapi = lodash.cloneDeep(defaultConfig.get('platform.dapi.rsDapi')); + } + + const defaultMetrics = defaultConfig.get('platform.dapi.rsDapi.metrics'); + const defaultZmqPort = defaultConfig.get('core.zmq.port'); + const baseMetricsPort = base.get('platform.dapi.rsDapi.metrics.port'); + const baseZmqPort = base.get('core.zmq.port'); + + if (!options.platform.dapi.rsDapi.metrics) { + options.platform.dapi.rsDapi.metrics = lodash.cloneDeep(defaultMetrics); + } + + if (typeof options.platform.dapi.rsDapi.metrics.enabled === 'undefined') { + options.platform.dapi.rsDapi.metrics.enabled = defaultMetrics.enabled; + } + + if (!options.core.zmq) { + options.core.zmq = lodash.cloneDeep(defaultConfig.get('core.zmq')); + } else { + options.core.zmq = lodash.cloneDeep(options.core.zmq); + } + + if (typeof options.core.zmq.port === 'undefined') { + options.core.zmq.port = defaultConfig.get('core.zmq.port'); + } + + if (typeof options.platform.dapi.rsDapi.metrics.port === 'undefined') { + options.platform.dapi.rsDapi.metrics.port = defaultMetrics.port; + } + + const targetMetricsPort = Number(defaultMetrics.port); + const targetZmqPort = Number(defaultZmqPort); + const configuredMetricsPort = Number(options.platform.dapi.rsDapi.metrics.port); + const configuredZmqPort = Number(options.core.zmq.port); + const baseMetricsPortNumber = Number(baseMetricsPort); + const baseZmqPortNumber = Number(baseZmqPort); + + if ( + !Number.isNaN(targetMetricsPort) + && targetMetricsPort !== configuredMetricsPort + && configuredMetricsPort === baseMetricsPortNumber + ) { + options.platform.dapi.rsDapi.metrics.port = targetMetricsPort; + } + + if ( + !Number.isNaN(targetZmqPort) + && targetZmqPort !== configuredZmqPort + && (configuredZmqPort === baseZmqPortNumber || configuredZmqPort === 29998) + ) { + options.core.zmq.port = targetZmqPort; + } + }); + + return configFile; + }, }; } diff --git a/packages/dashmate/docker-compose.yml b/packages/dashmate/docker-compose.yml index dc0ba8f2710..5ca9175d830 100644 --- a/packages/dashmate/docker-compose.yml +++ b/packages/dashmate/docker-compose.yml @@ -229,9 +229,6 @@ services: expose: - 3009 # JSON-RPC - 3010 # gRPC (different from current DAPI to avoid conflict) - - ${PLATFORM_DAPI_RS_DAPI_METRICS_PORT:?err} # Metrics - ports: - - ${PLATFORM_DAPI_RS_DAPI_METRICS_HOST:?err}:${PLATFORM_DAPI_RS_DAPI_METRICS_PORT:?err}:${PLATFORM_DAPI_RS_DAPI_METRICS_PORT:?err} profiles: - platform-dapi-rs diff --git a/packages/dashmate/docs/config/core.md b/packages/dashmate/docs/config/core.md index 9f41aacca25..1fc8ec17f53 100644 --- a/packages/dashmate/docs/config/core.md +++ b/packages/dashmate/docs/config/core.md @@ -73,7 +73,7 @@ The `core.zmq` section configures the ZeroMQ notification interface, which provi | Option | Description | Default | Example | |--------|-------------|---------|---------| -| `core.zmq.port` | Port for ZMQ notifications | `29998` | `30998` | +| `core.zmq.port` | Port for ZMQ notifications | `29998` (mainnet),`39998` (testnet), `49998` (local) | `30998` | | `core.zmq.host` | Host binding for Docker port mapping | `127.0.0.1` | `0.0.0.0` | ZMQ settings control real-time blockchain event notifications: @@ -81,7 +81,7 @@ ZMQ settings control real-time blockchain event notifications: - **host**: Controls Docker port exposure: - `127.0.0.1`: ZMQ port exposed only on localhost (local machine access) - `0.0.0.0`: ZMQ port exposed on all interfaces (public internet access - use with caution) -- **port**: The port number for ZMQ notifications +- **port**: The port number for ZMQ notifications. Dashmate offsets the default to prevent clashes between environments (`29998` mainnet, `39998` testnet, `49998` local presets). - DAPI uses ZMQ to receive real-time blockchain data for streaming to clients - ZMQ notifications include raw transactions, blocks, instantlocks, and chainlocks - ZMQ is always enabled in Dash Core as it's used by internal components diff --git a/packages/dashmate/docs/config/dapi.md b/packages/dashmate/docs/config/dapi.md index 54e7989bb4b..7c6a7d90fd4 100644 --- a/packages/dashmate/docs/config/dapi.md +++ b/packages/dashmate/docs/config/dapi.md @@ -53,10 +53,12 @@ This timeout setting controls how long DAPI will wait for state transition resul | Option | Description | Default | Example | |--------|-------------|---------|---------| | `platform.dapi.rsDapi.metrics.host` | Host interface exposed on the Docker host | `127.0.0.1` | `0.0.0.0` | -| `platform.dapi.rsDapi.metrics.port` | Host port for both health checks and Prometheus metrics | `9091` | `9191` | +| `platform.dapi.rsDapi.metrics.port` | Host port for both health checks and Prometheus metrics | `9091` (mainnet), `19091` (testnet), `29091` (local) | `9191` | The rs-dapi metrics server exposes `/health` and `/metrics`. Prometheus-compatible metrics are served from `/metrics` on the configured port, allowing separate node instances on the same machine to use distinct ports. The `/health` endpoint aggregates dependency checks (Drive, Tenderdash, Core) and returns `503` when any upstream component is unhealthy. +Dashmate offsets the default metrics port per preset (mainnet 9091, testnet 19091, local 29091) to avoid clashes when running multiple environments concurrently. + ### Logging | Option | Description | Default | Example | diff --git a/packages/dashmate/docs/services/core.md b/packages/dashmate/docs/services/core.md index 0bb40ec8a73..db42799f96f 100644 --- a/packages/dashmate/docs/services/core.md +++ b/packages/dashmate/docs/services/core.md @@ -33,7 +33,7 @@ Core exposes P2P and RPC ports for communication with other services. It also pr |----------------------|--------------|---------------|---------------------|----------------------|------------------| | **Core** | P2P | 9999 | `core.p2p.port` | 0.0.0.0 (all) | `core.p2p.host` | | | RPC | 9998 | `core.rpc.port` | 127.0.0.1 (local) | `core.rpc.host` | -| | ZMQ | 29998 | `core.zmq.port` | 127.0.0.1 (local) | `core.zmq.host` | +| | ZMQ | 29998 (mainnet), 39998 (testnet), 49998 (local) | `core.zmq.port` | 127.0.0.1 (local) | `core.zmq.host` | | **Insight API/UI** | HTTP | 3001 | `core.insight.port` | 127.0.0.1 (local) | (fixed) | To interact with Core RPC use `dashmate core cli` command. diff --git a/packages/dashmate/docs/services/index.md b/packages/dashmate/docs/services/index.md index f3fd04d5d2c..ec16757e948 100644 --- a/packages/dashmate/docs/services/index.md +++ b/packages/dashmate/docs/services/index.md @@ -73,13 +73,13 @@ Dashmate runs and orchestrate Dash Platform components: | Type | Ports | Default Host Binding | |---------------------|--------------------------------------------------------------|---------------------| | **Public-facing** | Core P2P (9999)
Tenderdash P2P (26656)
Gateway API (443) | 0.0.0.0 (all) | -| **Configurable** | Core ZMQ (29998) | configurable (see below) | +| **Configurable** | Core ZMQ (29998 mainnet / 39998 testnet / 49998 local) | configurable (see below) | | **Localhost-only** | Core RPC (9998)
Insight UI (3001)
Dashmate Helper (9100)
Drive ABCI Metrics (29090)
Drive Debug Tools (6669, 8083)
Tenderdash RPC (26657)
Tenderdash Metrics (26660)
Tenderdash Debug (6060)
Gateway Metrics (9090)
Gateway Admin (9901)
Rate Limiter Metrics (9102) | 127.0.0.1 (local) | | **Internal only** | Drive ABCI (26658)
Drive gRPC (26670)
DAPI JSON-RPC (3004)
DAPI gRPC (3005)
DAPI Streams (3006)
Rate Limiter gRPC (8081)
Rate Limiter StatsD (9125)
Rate Limiter Redis (6379) | (not exposed) | #### Core ZMQ Exposure Configuration -The Core ZMQ port (29998) exposure is configurable via `core.zmq.host`: +The Core ZMQ port (29998 on mainnet, 39998 on testnet, 49998 on local presets) exposure is configurable via `core.zmq.host`: - **`host: '127.0.0.1'`** (default): ZMQ port exposed on localhost only - **`host: '0.0.0.0'`**: ZMQ port exposed on all interfaces (use with caution) diff --git a/packages/dashmate/docs/services/platform.md b/packages/dashmate/docs/services/platform.md index 7bf3d1cd371..d0d5e4e7ef1 100644 --- a/packages/dashmate/docs/services/platform.md +++ b/packages/dashmate/docs/services/platform.md @@ -154,6 +154,6 @@ Tenderdash is the consensus engine that provides Byzantine Fault Tolerant (BFT) | **DAPI API** | JSON-RPC | 3004 | (fixed internal) | (internal) | - | | | gRPC | 3005 | (fixed internal) | (internal) | - | | **DAPI Core Streams** | gRPC Streaming | 3006 | (fixed internal) | (internal) | - | -| **rs-dapi (Rust)** | Health + Metrics | 9091 | `platform.dapi.rsDapi.metrics.port` | 127.0.0.1 | `platform.dapi.rsDapi.metrics.host` | +| **rs-dapi (Rust)** | Health + Metrics | 9091 (mainnet), 19091 (testnet), 29091 (local) | `platform.dapi.rsDapi.metrics.port` | 127.0.0.1 | `platform.dapi.rsDapi.metrics.host` | -The rs-dapi metrics server exposes health endpoints alongside Prometheus data on `/metrics` from the same port. +The rs-dapi metrics server exposes health endpoints alongside Prometheus data on `/metrics` from the same port. Dashmate applies network-specific defaults (mainnet 9091, testnet 19091, local 29091) so multiple presets can coexist on a host without conflicts. diff --git a/packages/dashmate/src/config/configJsonSchema.js b/packages/dashmate/src/config/configJsonSchema.js index cdf693c62a5..8c391cb9525 100644 --- a/packages/dashmate/src/config/configJsonSchema.js +++ b/packages/dashmate/src/config/configJsonSchema.js @@ -880,20 +880,7 @@ export default { additionalProperties: false, }, metrics: { - type: 'object', - properties: { - host: { - type: 'string', - minLength: 1, - }, - port: { - type: 'integer', - minimum: 1, - maximum: 65535, - }, - }, - required: ['host', 'port'], - additionalProperties: false, + $ref: '#/definitions/enabledHostPort', }, logs: { type: 'object', diff --git a/packages/dashmate/src/config/generateEnvsFactory.js b/packages/dashmate/src/config/generateEnvsFactory.js index b2c5190fe75..5da58368fec 100644 --- a/packages/dashmate/src/config/generateEnvsFactory.js +++ b/packages/dashmate/src/config/generateEnvsFactory.js @@ -135,6 +135,13 @@ export default function generateEnvsFactory(configFile, homeDir, getConfigProfil envs.PLATFORM_DAPI_RS_DAPI_LOGS_ACCESS_LOG_PATH = ''; } + if ( + config.has('platform.dapi.rsDapi.metrics.enabled') + && !config.get('platform.dapi.rsDapi.metrics.enabled') + ) { + envs.PLATFORM_DAPI_RS_DAPI_METRICS_PORT = '0'; + } + return envs; } diff --git a/packages/dashmate/templates/core/insight/dashcore-node.json.dot b/packages/dashmate/templates/core/insight/dashcore-node.json.dot index cfb92e73b14..8fb9000f204 100644 --- a/packages/dashmate/templates/core/insight/dashcore-node.json.dot +++ b/packages/dashmate/templates/core/insight/dashcore-node.json.dot @@ -14,8 +14,8 @@ "rpcport": {{= it.core.rpc.port }}, "rpcuser": "dashmate", "rpcpassword": "{{= it.core.rpc.users.dashmate.password }}", - "zmqpubrawtx": "tcp://core:29998", - "zmqpubhashblock": "tcp://core:29998" + "zmqpubrawtx": "tcp://core:{{= it.core.zmq.port }}", + "zmqpubhashblock": "tcp://core:{{= it.core.zmq.port }}" }] }, "@dashevo/insight-api": { diff --git a/packages/dashmate/templates/dynamic-compose.yml.dot b/packages/dashmate/templates/dynamic-compose.yml.dot index 6ed120930fe..9db8a26827c 100644 --- a/packages/dashmate/templates/dynamic-compose.yml.dot +++ b/packages/dashmate/templates/dynamic-compose.yml.dot @@ -28,6 +28,22 @@ services: - {{=it.platform.drive.tenderdash.log.path}}:/var/log/tenderdash/tenderdash.log {{?}} + {{? it.platform.dapi && it.platform.dapi.rsDapi }} + rs_dapi: + expose: + - 3009 + - 3010 + {{? it.platform.dapi.rsDapi.metrics.enabled }} + - {{=it.platform.dapi.rsDapi.metrics.port}} + {{?}} + {{? it.platform.dapi.rsDapi.metrics.enabled }} + ports: + - {{=it.platform.dapi.rsDapi.metrics.host}}:{{=it.platform.dapi.rsDapi.metrics.port}}:{{=it.platform.dapi.rsDapi.metrics.port}} + {{??}} + ports: [] + {{?}} + {{?}} + {{ gatewayLogs = it.platform.gateway.log.accessLogs.filter((l) => l.type === 'file'); }} {{? gatewayLogs.length > 0 }} gateway: