> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blocklight.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> Complete reference for config/config.yaml settings with limits and recommendations

Blocklight uses a single `config.yaml` file. Validate it with `./blocklight config check`.

<Warning>
  **Validation:** All configuration values have strict minimum and maximum limits to prevent system collapse. Invalid values will cause startup errors.

  **Automatic Validation:** Blocklight automatically validates your configuration before starting (`./blocklight start` or Docker). If validation fails, the server will not start and will display descriptive error messages.

  **Before Production:** Always run `./blocklight config check` before deploying to production to catch configuration issues early.

  **Configuration-Only:** All engine parameters are configured exclusively through `config.yaml`. No code changes are required to adjust performance, limits, or behavior. This ensures easy deployment and maintenance without forking the codebase.
</Warning>

## Overview

The configuration file is organized into several sections:

* `chains` - Blockchain connections
* `go_core` - Core engine settings
* `analysis` - Analysis settings (transaction, contract)
* `alerting` - Notification channels
* `storage` - In-memory storage limits
* `logging` - Log configuration
* `monitoring` - Prometheus metrics

## Network Configuration

Configure blockchain connections. Each chain needs an RPC URL. WebSocket is optional but recommended for real-time monitoring.

<Info>
  **API Keys:** Use `${API_KEY}` placeholders in URLs. Set API keys in `.env` file (see `env.template`). This keeps sensitive keys out of `config.yaml` and allows different keys per environment.
</Info>

### Chain Settings

```yaml theme={null}
chains:
  ethereum:
    enabled: true
    # Use ${API_KEY} placeholder - set YOUR_PROVIDER_API_KEY in .env
    # Works with any provider: Alchemy, Infura, QuickNode, Ankr, your own node, etc.
    rpc_url: https://your-rpc-endpoint.com/v1/${YOUR_PROVIDER_API_KEY}
    ws_url: wss://your-rpc-endpoint.com/v1/${YOUR_PROVIDER_API_KEY}
    chain_id: 1
    name: "Ethereum Mainnet"
    polling_interval: 12  # seconds (fallback if WebSocket fails)
    batch_size: 100
```

#### `enabled` (boolean, required)

* **Purpose:** Enable or disable monitoring for this chain
* **Default:** `true`
* **Limits:** N/A (boolean)

#### `rpc_url` (string, required)

* **Purpose:** HTTP/HTTPS RPC endpoint for blockchain queries
* **Format:** Must be a valid URL (http\:// or https\://)
* **Security:** HTTPS recommended for production
* **Limits:** N/A (valid URL required)
* **API Keys:** Use `${YOUR_PROVIDER_API_KEY}` placeholders. Set keys in `.env` file.
* **Works with ANY provider:**
  * Alchemy: `https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`
  * Infura: `https://mainnet.infura.io/v3/${INFURA_API_KEY}`
  * QuickNode: `https://your-endpoint.quiknode.pro/${QUICKNODE_API_KEY}/`
  * Ankr: `https://rpc.ankr.com/eth/${ANKR_API_KEY}`
  * Chainstack: `https://nd-123-456-789.p2pify.com/${CHAINSTACK_API_KEY}`
  * Your own node: `https://your-node.example.com:8545`
  * Any other EVM-compatible RPC provider

#### `ws_url` (string, optional)

* **Purpose:** WebSocket endpoint for real-time block/transaction streaming
* **Format:** Must be a valid WebSocket URL (ws\:// or wss\://)
* **Behavior:** If empty, falls back to polling mode using `polling_interval`
* **Security:** WSS (secure WebSocket) recommended for production
* **Limits:** N/A (valid WebSocket URL or empty string)
* **API Keys:** Use `${YOUR_PROVIDER_API_KEY}` placeholders (same as `rpc_url`)
* **Works with ANY provider:**
  * Alchemy: `wss://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`
  * Infura: `wss://mainnet.infura.io/ws/v3/${INFURA_API_KEY}`
  * QuickNode: `wss://your-endpoint.quiknode.pro/${QUICKNODE_API_KEY}/`
  * Your own node: `wss://your-node.example.com:8546`
* **Recommendation:** Always provide WebSocket URL for real-time monitoring

#### `chain_id` (integer, required)

* **Purpose:** Chain identifier (1 for Ethereum, 137 for Polygon, etc.)
* **Limits:** N/A (must match actual chain ID)

#### `name` (string, optional)

* **Purpose:** Human-readable chain name for logs and alerts
* **Limits:** N/A

#### `polling_interval` (integer, seconds)

* **Purpose:** How often to poll for new blocks when WebSocket is unavailable
* **Limits:** **Minimum: 1, Maximum: 60**
* **Recommendations:**
  * **Ethereum:** 12 seconds (12s block time)
  * **Polygon:** 2 seconds (2s block time)
  * **Fast chains (BSC, Arbitrum):** 1-3 seconds
  * **Slow chains:** 12-15 seconds
* **Warning:** Values > 60 seconds may cause missed blocks

#### `batch_size` (integer)

* **Purpose:** Number of transactions to fetch per batch request
* **Limits:** **Minimum: 10, Maximum: 500**
* **Recommendations:**
  * **High-volume chains (Polygon, BSC):** 50-100
  * **Standard chains (Ethereum):** 100
  * **Low-volume chains:** 50-100
* **Impact:** Larger batches = fewer RPC calls but more memory usage

<Info>
  **Environment Variables:** Set `{CHAIN}_NODE_URL` and `{CHAIN}_WS_URL` in `.env` to override defaults. Example: `ETH_NODE_URL`, `POLYGON_NODE_URL`. This allows you to use private API keys without committing them.
</Info>

## Core Engine Configuration

The core engine processes transactions and evaluates rules. These settings control performance and resource usage.

```yaml theme={null}
go_core:
  host: "blocklight-core"
  port: 50051
  
  # Rules
  rules_dir: ./rules/default
  custom_rules_dir: ./rules/custom
  schema_path: ./rules/schema/rule_schema.json
  
  # Hot reload
  hot_reload: true
  reload_interval: 5  # seconds
  
  # Performance tuning
  workers: 16             # Number of parallel rule evaluators
  batch_size: 50          # Transactions per batch
  channel_buffer: 5000    # Channel buffer size
  
  # Rule evaluation limits
  max_condition_depth: 10  # Maximum recursion depth
  timeout_seconds: 5      # Timeout per rule evaluation
  connection_pool_size: 10 # Max concurrent RPC connections per chain
```

### Service Configuration

#### `host` (string)

* **Purpose:** Service hostname (for Docker deployments)
* **Limits:** N/A
* **Default:** `"blocklight-core"`

#### `port` (integer)

* **Purpose:** gRPC port for API communication
* **Limits:** **Minimum: 1024, Maximum: 65535**
* **Default:** `50051`

### Rules Configuration

#### `rules_dir` (string, required)

* **Purpose:** Directory containing default detection rules
* **Limits:** N/A (must be valid directory path)
* **Default:** `./rules/default`

#### `custom_rules_dir` (string, optional)

* **Purpose:** Directory for custom user-defined rules
* **Limits:** N/A (must be valid directory path if provided)
* **Default:** `./rules/custom`

#### `schema_path` (string, required)

* **Purpose:** Path to JSON schema for rule validation
* **Limits:** N/A (must be valid file path)
* **Default:** `./rules/schema/rule_schema.json`

### Hot Reload Configuration

#### `hot_reload` (boolean)

* **Purpose:** Automatically reload rules when files change (development)
* **Limits:** N/A (boolean)
* **Default:** `true`
* **Production:** Set to `false` for production deployments

#### `reload_interval` (integer, seconds)

* **Purpose:** How often to check for rule file changes
* **Limits:** **Minimum: 1, Maximum: 300**
* **Default:** `5`
* **Recommendations:**
  * **Development:** 3-5 seconds
  * **Production:** 30-60 seconds (if hot\_reload enabled)
* **Warning:** Values \< 3 seconds may impact performance

### Performance Tuning

#### `workers` (integer)

* **Purpose:** Number of parallel goroutines that evaluate rules simultaneously
* **Limits:** **Minimum: 1, Maximum: 64**
* **Default:** `8`
* **Recommendations:**
  * **Single chain, low volume:** 8-12 workers
  * **Single chain, high volume (Polygon, BSC):** 16-24 workers
  * **Multiple chains:** 12-16 workers per chain
  * **CPU-constrained:** 4-8 workers
* **Impact:** More workers = faster processing but higher CPU/memory usage
* **Formula:** `workers = (CPU cores × 2) - 2` (general guideline)

#### `batch_size` (integer)

* **Purpose:** Number of transactions processed together before evaluating rules
* **Limits:** **Minimum: 10, Maximum: 500**
* **Default:** `100`
* **Recommendations:**
  * **Fast chains (Polygon, BSC):** 50-100
  * **Standard chains (Ethereum):** 100
  * **Memory-constrained:** 50
* **Impact:** Larger batches = better throughput but more memory per batch

#### `channel_buffer` (integer)

* **Purpose:** Size of internal event channel buffer (prevents "channel full" warnings)
* **Limits:** **Minimum: 100, Maximum: 50000**
* **Default:** `1000`
* **Recommendations:**
  * **Single chain, low volume:** 1000-2000
  * **Single chain, high volume (Polygon, BSC):** 5000-10000
  * **Multiple chains:** 5000-10000 per chain
  * **Very high volume:** 10000-20000
* **Warning:** If you see `"Event channel full, dropping event"` warnings, increase this value
* **Memory Impact:** Each buffered event uses \~1-2KB memory
* **Formula:** `channel_buffer = (expected_tx_per_second × processing_time_seconds) × 2`

<Warning>
  **Channel Full Warning:** If you see `{"level":"warn","message":"Event channel full, dropping event"}` in logs, it means:

  1. Transactions are arriving faster than they can be processed
  2. The channel buffer is full (events are being dropped)
  3. **Solution:** Increase `channel_buffer` and/or `workers` to process faster
</Warning>

### Rule Evaluation Limits

#### `max_condition_depth` (integer)

* **Purpose:** Maximum recursion depth for complex nested conditions (prevents stack overflow)
* **Limits:** **Minimum: 1, Maximum: 50**
* **Default:** `10`
* **Recommendations:**
  * **Simple rules:** 5-10
  * **Complex rules with nested AND/OR:** 10-20
  * **Very complex rules:** 20-30
* **Warning:** Values > 50 risk stack overflow

#### `timeout_seconds` (integer)

* **Purpose:** Maximum time allowed for a single rule evaluation
* **Limits:** **Minimum: 1, Maximum: 60**
* **Default:** `5`
* **Recommendations:**
  * **Simple rules:** 3-5 seconds
  * **Complex rules with many conditions:** 5-10 seconds
  * **Rules with complex chained methods:** 5-10 seconds
* **Impact:** Rules exceeding timeout are skipped (logged as warning)

#### `connection_pool_size` (integer)

* **Purpose:** Maximum number of concurrent RPC connections per chain
* **Limits:** **Minimum: 1, Maximum: 100**
* **Default:** `10`
* **Recommendations:**
  * **Single chain:** 10-20 connections
  * **Multiple chains:** 10 connections per chain
  * **High-volume chains:** 20-30 connections
  * **RPC rate-limited:** 5-10 connections
* **Impact:** More connections = faster parallel requests but higher RPC quota usage
* **Note:** Each chain has its own connection pool

## Analysis Configuration

Analyzers run automatically when RPC client is available. Configure what data to fetch and cache.

```yaml theme={null}
analysis:
  transaction:
    fetch_receipt: true
    decode_input: true
    analyze_gas: false
    timeout_seconds: 5
    cache_ttl_seconds: 300
```

### Transaction Analyzer

**Always enabled** if RPC client is available. Provides essential transaction fields.

#### `fetch_receipt` (boolean)

* **Purpose:** Fetch transaction receipt (required for `tx.status`, `tx.gas_used`, `tx.logs_count`)
* **Limits:** N/A (boolean)
* **Default:** `true`
* **Required for:** `tx.status`, `tx.gas_used`, `tx.logs_count`, `tx.logs`
* **Cost:** Low (1 RPC call per transaction)

#### `decode_input` (boolean)

* **Purpose:** Parse function selector from transaction input data
* **Limits:** N/A (boolean)
* **Default:** `true`
* **Required for:** `tx.function` (function selector)
* **Cost:** Negligible (local parsing)

#### `analyze_gas` (boolean)

* **Purpose:** Perform detailed gas analysis (efficiency, cost calculations)
* **Limits:** N/A (boolean)
* **Default:** `false`
* **Cost:** Negligible (local calculation)
* **Use case:** Advanced gas monitoring rules

#### `timeout_seconds` (integer)

* **Purpose:** Maximum time to wait for RPC response
* **Limits:** **Minimum: 1, Maximum: 60**
* **Default:** `5`
* **Recommendations:** 5-10 seconds (RPC calls are usually fast)

#### `cache_ttl_seconds` (integer)

* **Purpose:** How long to cache transaction analysis results
* **Limits:** **Minimum: 60, Maximum: 86400 (1 day)**
* **Default:** `300` (5 minutes)
* **Recommendations:**
  * **High-volume chains:** 300-600 seconds (5-10 minutes)
  * **Standard chains:** 300 seconds (5 minutes)
* **Impact:** Longer TTL = fewer RPC calls but potentially stale data

## Storage Configuration

Blocklight keeps recent findings in memory for API queries. For long-term storage, use webhook integration.

```yaml theme={null}
storage:
  max_findings: 1000  # Maximum findings to keep in memory
```

#### `max_findings` (integer)

* **Purpose:** Maximum number of findings to keep in memory (for API queries)
* **Limits:** **Minimum: 100, Maximum: 100000**
* **Default:** `1000`
* **Recommendations:**
  * **Development/testing:** 1000
  * **Production with API:** 5000-10000
  * **Memory-constrained:** 1000-2000
* **Memory Impact:** Each finding uses \~2-5KB memory
* **Formula:** `max_findings × 5KB = approximate memory usage`
* **Note:** Old findings are automatically evicted when limit is reached

<Info>
  **Long-term Storage:** For persistent storage, configure a webhook channel to send findings to your database or SIEM system.
</Info>

## Logging Configuration

Configure log output format and destinations.

```yaml theme={null}
logging:
  level: "INFO"   # DEBUG, INFO, WARNING, ERROR
  format: "json"  # json, text
  
  file:
    enabled: false
    path: ./logs/threat_detection.log
    max_size_mb: 10
    max_backups: 5
  
  console:
    enabled: true
    level: "INFO"
```

#### `level` (string)

* **Purpose:** Minimum log level to output
* **Options:** `DEBUG`, `INFO`, `WARNING`, `ERROR`
* **Default:** `INFO`
* **Recommendations:**
  * **Development:** `DEBUG` (verbose)
  * **Production:** `INFO` (standard)
  * **High-volume:** `WARNING` (only warnings/errors)

#### `format` (string)

* **Purpose:** Log output format
* **Options:** `json`, `text`
* **Default:** `json`
* **Recommendations:**
  * **Production/containers:** `json` (structured, easy to parse)
  * **Development:** `text` (human-readable)

#### `file.enabled` (boolean)

* **Purpose:** Enable file logging
* **Default:** `false`
* **Production:** Set to `true` for log persistence

#### `file.path` (string)

* **Purpose:** Path to log file
* **Default:** `./logs/threat_detection.log`

#### `file.max_size_mb` (integer)

* **Purpose:** Maximum log file size before rotation
* **Limits:** **Minimum: 1, Maximum: 1000**
* **Default:** `10`
* **Recommendations:** 10-100 MB depending on log volume

#### `file.max_backups` (integer)

* **Purpose:** Number of rotated log files to keep
* **Limits:** **Minimum: 1, Maximum: 100**
* **Default:** `5`
* **Recommendations:** 5-10 backups

#### `console.enabled` (boolean)

* **Purpose:** Enable console logging
* **Default:** `true`

#### `console.level` (string)

* **Purpose:** Minimum log level for console output (can differ from file)
* **Options:** `DEBUG`, `INFO`, `WARNING`, `ERROR`
* **Default:** `INFO`

## Monitoring Configuration

<Info>
  **Optional:** Prometheus monitoring is optional. Blocklight works perfectly without it. Enable only if you need to monitor Blocklight's health and performance in production.
</Info>

Basic Prometheus metrics for production observability (monitors Blocklight itself, not detections):

```yaml theme={null}
monitoring:
  enabled: true
  
  prometheus:
    enabled: true
    path: "/api/v1/system/metrics"  # Requires REST API to be enabled
  
  health_check:
    enabled: true
    interval: 30  # seconds
```

#### `enabled` (boolean)

* **Purpose:** Enable monitoring features
* **Default:** `true`

#### `prometheus.enabled` (boolean)

* **Purpose:** Enable Prometheus metrics endpoint (optional)
* **Default:** `true`
* **Requires:** REST API enabled (`api.enabled: true`)
* **Note:** Blocklight works perfectly without Prometheus. Enable only for production monitoring.

#### `prometheus.path` (string)

* **Purpose:** HTTP path for metrics endpoint
* **Default:** `"/api/v1/system/metrics"`

#### `health_check.enabled` (boolean)

* **Purpose:** Enable health check endpoint
* **Default:** `true`

#### `health_check.interval` (integer, seconds)

* **Purpose:** How often to perform health checks
* **Limits:** **Minimum: 5, Maximum: 300**
* **Default:** `30`
* **Recommendations:** 30-60 seconds

## Alert Configuration

Configure notification channels for alerts.

```yaml theme={null}
alerting:
  enabled: true
  
  channels:
    - type: "log"
      enabled: true
      min_severity: "WARNING"
    
    - type: "file"
      enabled: true
      path: "./output/detections.jsonl"
      min_severity: "NOTICE"
    
    - type: "webhook"
      enabled: false
      url: ${WEBHOOK_URL}
      min_severity: "CRITICAL"
```

#### `enabled` (boolean)

* **Purpose:** Enable alerting system
* **Default:** `true`

#### `channels[].type` (string)

* **Purpose:** Alert channel type
* **Options:** `log`, `file`, `webhook`
* **Limits:** N/A

#### `channels[].enabled` (boolean)

* **Purpose:** Enable this specific channel
* **Default:** `true`

#### `channels[].min_severity` (string)

* **Purpose:** Minimum severity level to send through this channel
* **Options:** `NOTICE`, `WARNING`, `CRITICAL`
* **Default:** `NOTICE`
* **Recommendations:**
  * **Log channel:** `WARNING` (reduce noise)
  * **File channel:** `NOTICE` (capture all)
  * **Webhook channel:** `CRITICAL` (only critical alerts)

#### `channels[].path` (string, file channel only)

* **Purpose:** File path for JSONL output
* **Limits:** N/A (must be writable path)

#### `channels[].url` (string, webhook channel only)

* **Purpose:** Webhook URL for HTTP POST requests
* **Limits:** N/A (must be valid HTTPS URL)
* **Security:** Must use HTTPS (HTTP will generate warning)

## Environment Variables

Use environment variables for **API keys only**. RPC URLs are configured in `config.yaml` using `${API_KEY}` placeholders.

### API Keys in `.env`

Create a `.env` file from `env.template`:

```bash theme={null}
# Copy template
cp env.template .env

# Edit .env and add your API keys
nano .env
```

**Example `.env` file:**

```bash theme={null}
# Blockchain RPC API Keys (ONLY keys, not full URLs)
# Use ANY provider: Alchemy, Infura, QuickNode, Ankr, Chainstack, your own node, etc.
MY_PROVIDER_API_KEY=abc123def456...

# Alert webhooks
WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
```

**Then in `config.yaml`, use placeholders:**

```yaml theme={null}
chains:
  ethereum:
    # Works with ANY RPC provider
    rpc_url: https://your-rpc-endpoint.com/v1/${MY_PROVIDER_API_KEY}
    ws_url: wss://your-rpc-endpoint.com/v1/${MY_PROVIDER_API_KEY}
```

### How It Works

1. **Set API key in `.env`:** `MY_PROVIDER_API_KEY=abc123...`
2. **Use placeholder in `config.yaml`:** `rpc_url: https://your-rpc-endpoint.com/v1/${MY_PROVIDER_API_KEY}`
3. **Blocklight automatically replaces** `${MY_PROVIDER_API_KEY}` with the value from `.env`

### Benefits

* **Security:** API keys stay out of `config.yaml` (which may be committed to git)
* **Flexibility:** Different keys per environment (dev, staging, production)
* **Simplicity:** URLs configured once in `config.yaml`, keys per environment in `.env`

<Warning>
  **Never commit `.env` to git!** Use `.env.example` or `env.template` for documentation only.
</Warning>

### Advanced: Override Complete URLs (Optional)

For advanced use cases, you can override complete URLs using environment variables:

```bash theme={null}
# In .env (optional - only if you need to override complete URLs)
ETH_NODE_URL=https://custom-rpc.example.com
ETH_WS_URL=wss://custom-rpc.example.com
```

These completely override the URLs in `config.yaml` if set. **Recommended:** Use API key placeholders instead.

Blocklight automatically loads variables from `.env` file or system environment.

## Configuration Recommendations by Chain Type

### Ethereum Mainnet

```yaml theme={null}
chains:
  ethereum:
    polling_interval: 12
    batch_size: 100

go_core:
  workers: 12
  batch_size: 100
  channel_buffer: 2000
```

### Polygon (High Volume)

```yaml theme={null}
chains:
  polygon:
    polling_interval: 2
    batch_size: 50

go_core:
  workers: 16
  batch_size: 50
  channel_buffer: 5000
```

### Multiple Chains

```yaml theme={null}
go_core:
  workers: 16
  batch_size: 50
  channel_buffer: 10000  # Higher buffer for multiple chains
```

## Configuration Validation

Blocklight automatically validates your configuration before starting. This prevents system failures due to invalid settings.

### Automatic Validation

When you run `./blocklight start` or start with Docker, Blocklight will:

1. **Load** the configuration file
2. **Validate** all settings against strict limits
3. **Report errors** if any values are outside allowed ranges
4. **Prevent startup** if critical errors are found

### Manual Validation

Before deploying to production, always validate your configuration:

```bash theme={null}
./blocklight config check
```

This command will:

* Check all configuration values against limits
* Report errors and warnings
* Display a summary of enabled features
* Exit with error code if validation fails

### Validation Errors

If validation fails, you'll see detailed error messages:

```
❌ Configuration validation failed

Configuration errors must be fixed before starting the server:

  Error Performance
    • workers must be at least 1
      Field: go_core.workers
    • channel_buffer cannot exceed 50000
      Field: go_core.channel_buffer

Run './blocklight config check' for detailed validation.
```

**Fix the errors** shown in the output, then validate again before starting.

### Validation Warnings

Warnings don't prevent startup but indicate potential issues:

* Security warnings (HTTP instead of HTTPS)
* Performance warnings (suboptimal settings)
* Configuration recommendations

Review warnings and adjust settings as needed for your environment.

## Troubleshooting

### "Event channel full, dropping event" Warning

**Symptom:** Logs show `{"level":"warn","message":"Event channel full, dropping event"}`

**Cause:** Transactions arriving faster than processing capacity

**Solutions:**

1. **Increase `channel_buffer`:** Set to 5000-10000 for high-volume chains
2. **Increase `workers`:** Add more parallel processors (up to 64)
3. **Reduce `batch_size`:** Process smaller batches more frequently
4. **Check RPC latency:** Slow RPC calls can cause backlog

### High Memory Usage

**Symptom:** System consuming excessive memory

**Solutions:**

1. **Reduce `channel_buffer`:** Lower buffer size (minimum 100)
2. **Reduce `storage.max_findings`:** Keep fewer findings in memory
3. **Reduce `workers`:** Fewer parallel processors
4. **Optimize rule conditions:** Use simple conditions when possible

### Slow Rule Evaluation

**Symptom:** Rules taking too long to evaluate

**Solutions:**

1. **Increase `timeout_seconds`:** Allow more time (up to 60s)
2. **Reduce `max_condition_depth`:** Simplify complex conditions
3. **Enable caching:** Ensure analyzers have appropriate `cache_ttl_seconds`
4. **Optimize rules:** Simplify condition logic

### Missed Blocks

**Symptom:** Not detecting transactions from recent blocks

**Solutions:**

1. **Use WebSocket:** Provide `ws_url` for real-time monitoring
2. **Reduce `polling_interval`:** Check more frequently (minimum 1s)
3. **Check RPC connection:** Ensure RPC endpoint is responsive
