forked from Lumen-Scribe/Lumenqraph
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.env.example
More file actions
201 lines (194 loc) · 12.1 KB
/
Copy path.env.example
File metadata and controls
201 lines (194 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# ---- Database ----
# Local dev via docker-compose. Swap for a managed Postgres URL in production.
DATABASE_URL=postgres://lumenqraph:lumenqraph@localhost:5432/lumenqraph
# Maximum number of database connections in the pool (default: 10).
# Indexer: set higher for high-throughput backfill; lower for constrained environments.
# API: set based on expected concurrent requests (e.g., 20-50 for production).
# Webhooks: typically 5-10 suffices (low traffic, mainly delivery retries).
# Free-tier managed Postgres often allows 20-40 connections; check your provider's limit.
DATABASE_MAX_CONNECTIONS=10
# Minimum number of idle connections to maintain in the pool (default: 0).
# Set to 1 or higher for faster query execution by reducing cold-start latency.
# Trade-off: higher values consume more resources while idle. Recommended: 0-2.
DATABASE_MIN_CONNECTIONS=0
# ---- Soroban RPC ----
# Testnet: https://soroban-testnet.stellar.org
# Mainnet: https://mainnet.sorobanrpc.com
RPC_URL=https://soroban-testnet.stellar.org
# HTTP request timeout for every outbound RPC call, in seconds (default: 30).
# Raise this for slow or heavily-loaded paid endpoints; lower it if you prefer
# tight liveness (a hung request will fail faster and trigger the retry logic).
# Applies to both the indexer and the API. Must be at least 1.
# For deep historical backfills against a slow archive RPC, 120 is a good
# starting point — see docs/DEEP_BACKFILL.md and scripts/backfill.sh --rpc-timeout.
RPC_TIMEOUT_SECS=30
# ---- Indexer ----
# Comma-separated contract IDs to index. Empty = index ALL contract events.
# The Soroban RPC getEvents method supports at most 25 contract IDs per request
# (5 filters × 5 IDs per filter). Providing more than 25 IDs here will cause
# the indexer to exit at startup with a clear error. To index more than 25
# contracts, run multiple indexer instances each covering a different subset.
CONTRACT_IDS=
POLL_INTERVAL_SECS=5
PAGE_SIZE=1000
# Maximum number of entries in the in-memory spec cache. Prevents unbounded
# memory growth when indexing all contracts. Evicted entries are re-fetched
# from the database on next miss. Default: 2000. Set higher for better cache
# hit rates when dealing with many unique contracts; lower to reduce memory usage.
SPEC_CACHE_MAX_ENTRIES=2000
# Maximum number of concurrent spec fetches allowed (default: 4).
# During a large catch-up with many new contracts, the indexer calls RPC
# to fetch contract specs. This semaphore bounds those simultaneous connections
# to prevent rate limiting or exhaustion. Already-cached specs bypass this limit.
# Increase for faster catch-up on permissive RPC; decrease for tight rate limits.
SPEC_FETCH_CONCURRENCY=4
# Start ledger for a fresh index. 0 = start near the tip. Clamped to the
# RPC retention window (~7 days, ~120k ledgers on SDF public RPC). Also used
# as the default for `backfill`.
START_LEDGER=0
# Max ledgers behind the tip to fetch in one live polling cycle. This is a
# conservative safety limit for performance, NOT the RPC retention window.
# The RPC retention window is ~7 days (~120k ledgers on SDF public RPC).
# Public Soroban RPCs reject getEvents whose startLedger is too far behind
# ("-32001 processing limit"), so if the cursor falls further behind (e.g.
# after downtime) the indexer skips ahead to this window and logs the
# unrecoverable gap instead of stalling. Raise it with a retaining/paid RPC.
# Default 4000 (~5–6 hours) is conservative for the SDF public endpoints.
MAX_CATCHUP_LEDGERS=4000
# Watch tracked contracts for upgrades: Soroban contracts are upgradable in
# place, so when a contract's executable changes the indexer re-reads its
# on-chain interface, appends it to `contract_spec_versions`, and records a
# semantic diff against the previous version (see /contracts/:id/interface/diff
# and the `upgrade` webhook kind). Defaults to ON when CONTRACT_IDS is set (a
# bounded set = one cheap RPC call per contract per cycle) and OFF otherwise,
# where it would cost one call per *active* contract per cycle. STATE_INDEXING
# already reads the same ledger entry, so enabling both costs nothing extra.
# UPGRADE_WATCH=true
# Snapshot each contract's instance storage into `contract_state` (versioned).
# Off by default; costs one extra RPC call per tracked contract per cycle. With
# CONTRACT_IDS set, those contracts are tracked every cycle; otherwise only
# contracts active in a cycle are snapshotted. Best paired with CONTRACT_IDS.
STATE_INDEXING=false
# Snapshot *per-holder* balances into `contract_data` (versioned). For each
# holder named in a token's transfer/mint/burn events, the indexer fetches its
# individual Balance(Address) entry. Off by default; costs one RPC call per
# newly-active holder per cycle, so pair it with CONTRACT_IDS.
KEY_INDEXING=false
# The symbol naming the balance storage-key variant (DataKey::Balance in the
# soroban token reference). Override only for tokens that name it differently.
BALANCE_KEY_SYMBOL=Balance
# Durability of the balance storage entry: persistent (default) or temporary.
BALANCE_KEY_DURABILITY=persistent
# Configurable key templates for per-key state indexing (JSON array).
# Each template defines: symbol (storage key variant), events (triggering event names),
# params (topic indices to extract addresses from), durability (persistent/temporary),
# and label (optional grouping tag). Examples:
# Allowance tracking: [{"symbol":"Allowance","events":["approve"],"params":[1,2],"durability":"persistent","label":"allowance"}]
# Position tracking: [{"symbol":"Position","events":["open_position","update_position"],"params":[1],"durability":"persistent","label":"position"}]
# Multiple templates: [{"symbol":"Allowance","events":["approve"],"params":[1,2],"label":"allowance"},{"symbol":"Position","events":["open_position"],"params":[1],"label":"position"}]
KEY_TEMPLATES=
# Keep only the last N ledgers of history: once the tip is further ahead than
# this, older events (and their token_transfers, via cascade) are pruned, as are
# superseded contract_state/contract_data versions. The newest version of each
# key is always kept, however old — it's current state, not history. 0 = keep
# everything (the default; disk is yours to manage). Set this when the database
# has a hard size cap that an unbounded index would hit: a free-tier Postgres is
# typically ~500MB, while a busy SAC emits ~500 events/ledger. ~17280 ledgers
# ≈ 1 day at ~5s/ledger; 120960 ≈ 7 days, past which public RPC can't backfill
# the gap anyway.
RETENTION_LEDGERS=0
# Keep at least N interface versions per contract in contract_spec_versions,
# pruning older versions once they fall outside the RETENTION_LEDGERS window.
# The newest N versions (by version number) per contract are always preserved,
# even if they're outside the retention window. This ensures you can always view
# the recent upgrade history of a contract. 0 = no minimum (default; spec versions
# follow the normal RETENTION_LEDGERS pruning). Set when you want to keep a buffer
# of upgrade history, e.g. 5 to always retain the last 5 interfaces per contract.
SPEC_VERSION_RETENTION=0
# Keep only the last N versions of each contract's spec in contract_spec_versions,
# pruning older versions once they fall outside the retention window. 0 (default)
# = keep everything. Newest N versions per contract are always preserved even if
# outside the window. When RETENTION_LEDGERS is set, specs outside the window
# are pruned unless they're among the newest N for their contract.
SPEC_VERSION_RETENTION=0
# Warn if the not-enriched fraction (events that couldn't be decoded/enriched)
# exceeds this threshold in a single poll cycle. Range: 0.0-1.0. Default 0.5
# means warn if >50% of events fail enrichment (spec unparseable, contract fetch
# failed, etc.). Set to 0.0 to disable warnings, or 1.0+ to warn only at 100%.
ENRICHMENT_WARN_THRESHOLD=0.5
# ---- API ----
API_BIND_ADDR=0.0.0.0:8080
# Maximum allowed request body size in bytes (default: 65536 = 64 KB).
# POST /contracts/:id/call, POST /contracts/:id/simulate, and POST /graphql
# accept JSON bodies; this limit prevents large-payload denial-of-service.
# Axum returns 413 Payload Too Large for requests that exceed this value.
# Raise it only if your payloads legitimately require more (e.g. complex args).
MAX_REQUEST_BODY_BYTES=65536
# CORS (Cross-Origin Resource Sharing) configuration: comma-separated list of allowed origins,
# * for all origins, or unset (default) for same-origin only (no CORS headers added).
# Examples:
# CORS_ALLOWED_ORIGINS=* # allow all origins (development only)
# CORS_ALLOWED_ORIGINS=https://example.com,https://app.example.com # allow specific origins
# Default (unset): browsers enforce same-origin policy; no Access-Control headers added.
# CORS_ALLOWED_ORIGINS=
# Instance mounts: comma-separated list of sibling Lumenqraph instances to reverse-proxy
# under path prefixes. Enables serving multiple networks (mainnet, testnet, etc.) from
# one deployment. Format: name=url (e.g. testnet=http://127.0.0.1:8081).
# See docs/MULTI_NETWORK.md for patterns and configuration.
# Example: INSTANCE_MOUNTS=testnet=http://127.0.0.1:8081,futurenet=http://127.0.0.1:8082
# INSTANCE_MOUNTS=
# Require a valid API key on data routes (health/metrics stay public).
REQUIRE_API_KEY=false
# Require a valid API key on GET /metrics (default: false = public, matching
# the documented behaviour). Set to true in production deployments where
# Prometheus is reachable from the internet and you don't want to expose
# indexer lag, RPC error rates, or per-contract enrichment rates publicly.
# The same API key mechanism used by data routes applies: present the key via
# `Authorization: Bearer <key>` or `x-api-key: <key>`.
METRICS_REQUIRE_API_KEY=false
# Requests/min for unauthenticated callers when REQUIRE_API_KEY=false.
ANON_RATE_LIMIT_PER_MIN=60
# GraphQL query depth limit (default: 12). Prevents deep nested queries that exhaust resources.
GRAPHQL_MAX_DEPTH=12
# GraphQL query complexity limit (default: 1000). Prevents expensive queries within rate limits.
GRAPHQL_MAX_COMPLEXITY=1000
# Enable GraphQL introspection and GraphiQL playground (default: false). Should be false in production.
GRAPHQL_INTROSPECTION_ENABLED=false
# Trust X-Forwarded-For header for rate limiting (enable only behind a trusted proxy).
RATE_LIMIT_TRUST_XFF=false
# Rate limiter backend: "memory" (default, per-instance) or "redis" (global across replicas)
RATE_LIMIT_BACKEND=memory
# Redis URL for global rate limiting (required when RATE_LIMIT_BACKEND=redis)
# REDIS_URL=redis://localhost:6379
# ---- Health and Readiness Probes ----
# Max ledger lag (in ledgers) for /readyz to return 200 (default: 100).
READYZ_LAG_THRESHOLD=100
# Max age of indexer cursor (in seconds) for /readyz to return 200 (default: 120).
READYZ_MAX_AGE_SECS=120
# Max ledger lag for /health to show "ok" status (default: 100).
HEALTH_MAX_LAG_LEDGERS=100
# Max age of indexer cursor for /health to show "ok" status (default: 120).
HEALTH_MAX_STALE_SECS=120
# ---- RPC Routes (expensive operations like /call and /simulate) ----
# These routes hit upstream Soroban RPC and use separate, tighter rate limits
# to prevent exhaustion of the shared RPC quota. They can optionally require
# authentication even when other routes don't.
# Requests/min for unauthenticated callers on RPC routes (default: 10).
RPC_ROUTE_RATE_LIMIT_PER_MIN=10
# Require API key specifically for expensive RPC routes (/contracts/:id/call,
# /contracts/:id/simulate) even when REQUIRE_API_KEY=false (default: false).
RPC_REQUIRE_API_KEY=false
# ---- Webhooks service ----
# REQUIRED: Encryption key for webhook secrets. Generate with: openssl rand -hex 32
# DO NOT use the default test key in production - it provides NO security.
WEBHOOK_ENCRYPTION_KEY=GENERATE_ME_WITH_openssl_rand_hex_32
WEBHOOK_TICK_SECS=3
WEBHOOK_BATCH_SIZE=100
WEBHOOK_MAX_ATTEMPTS=6
# Maximum total webhook subscriptions allowed across the system (default: 100).
# Protects the webhook dispatcher and database from unbounded subscription creation.
WEBHOOK_MAX_SUBSCRIPTIONS=100
# Requests/min for unauthenticated callers creating webhooks on POST /webhooks (default: 10).
WEBHOOK_CREATION_RATE_LIMIT_PER_MIN=10
# ---- Logging ----
RUST_LOG=info,lumenqraph_indexer=debug,lumenqraph_api=debug,lumenqraph_webhooks=debug