Releases: ar-io/ar-io-node
Release 77
This is a recommended release focused on cross-gateway GraphQL fan-out, ClickHouse query-path hardening, and composite query resilience. Key highlights include GatewaysGqlQueryable, a new adapter that fans GraphQL queries out to configured upstream ar-io-node gateways and merges the results — letting a node compose its local index with broader upstream coverage — and a parallelized composite ClickHouse/SQLite GraphQL path protected by a SQLite circuit breaker that surfaces PARTIAL_RESULT warnings via extensions.warnings instead of silent partials. ClickHouse gets several query-path improvements: dropping FINAL in favor of LIMIT 1 BY dedupe to re-enable projection planning, a new owner_address bloom with projection skipping on tag filters, a tag_names / tag_values fix for owner_projection, a configurable query timeout (default 3s), and a max_rows_to_read guardrail that fails noisy full-scans fast. It also adds per-job status tracking to the Parquet export admin API and bundles an Observer update to ddd3a9c with reference-gateway chunk-header offset validation and continuous-observer reliability hardening, alongside a set of ClickHouse auto-import reliability fixes.
Added
-
Fan-Out GraphQL Over Upstream Gateways (
GatewaysGqlQueryable): A newGqlQueryableadapter fans GraphQL queries out to configured upstream ar-io-node gateways and merges the results, letting a node act as a thin fan-out proxy or compose its local index with upstream sources for broader coverage. Single-record queries use first-non-null resolution; connection queries k-way merge by the ar-io-node cursor tuple and dedupe by id. Per-endpoint circuit breakers isolate slow or failing upstreams. Configured viaGATEWAYS_GQL_URLS; disabled by default. -
Configurable ClickHouse GraphQL Query Timeout: The ClickHouse GQL backend now applies a configurable timeout both server-side (as
max_execution_time, so ClickHouse aborts runaway queries and frees resources) and client-side (as the HTTPrequest_timeout, with a 2s grace window so the server-side timeout error surfaces before the client aborts). Default 3s. -
max_rows_to_readGuardrail on ClickHouse GraphQL Queries: Every GraphQL query against the ClickHousetransactionstable now appendsSETTINGS max_rows_to_read = N. Queries that would scan more than the configured threshold throwCode: 158: Limit for rows ... exceededinstead of silently scanning the whole table — catches projection-shadowing bugs and planner regressions where a skip index is bypassed. Default 10M rows (~20% of current table size); tunable viaCLICKHOUSE_GQL_MAX_ROWS_TO_READ. -
Per-Job Status Tracking for Parquet Export API:
POST /ar-io/admin/export-parquetnow returns ajobId, and the exporter keeps a bounded per-job history (32 entries) so concurrent callers can each poll their own record atGET /ar-io/admin/export-parquet/status/:jobId. The legacy singleton status endpoint is retained for back-compat and still reflects the most-recent update.scripts/parquet-exportprefers the per-job endpoint when ajobIdis returned and falls back to the singleton-with-drift-detection path for older gateways.
Changed
-
Observer Update to
ddd3a9c: Bundles two upstream PRs on top of the previous21098d2pin.- Reference-gateway chunk-header offset validation: The observer now HEADs the reference gateway's
/chunk/{offset}/dataand anchors the advertisedx-arweave-chunk-*headers (tx id, boundaries, data root) to the chain via/tx/{id}/offsetand/tx/{id}, replacing the block-and-tx binary search as the default offset-validation path. Typical cost drops from ~20–30 node lookups per offset to one HEAD plus two O(1) lookups per unique tx, with a per-tx LRU cache for repeated offsets. Any header/chain mismatch or missing header falls back to the legacy chain search, so older gateways keep working. New metricobserver_chunk_metadata_anchor_total{result}(hit / cache_hit / metadata_missing / mismatch / error / fallback) tracks the rollout. Gateways that return an HTTP error on the new probe are no longer blacklisted from the shared pool — only transport failures do. - Continuous observer reliability hardening: The per-gateway schedule map is replaced with a flat list of
ScheduledObservationevents so duplicates, restart catch-up, and overdue retries are deterministic (legacy state auto-migrates on load). An explicit submission deadline (windowEnd + submissionBufferMs) now bounds the epoch — once exceeded, the scheduler clears pending work, marks the epochexpired, and stops issuing observations instead of spinning on stale state. Finalization is gated on both the window being complete and the pending queue being empty, and only flipsreportSubmittedon a successful submit so transient submit failures retry. Unsubmitted prior epochs are discarded on epoch transition rather than force-finalized into the wrong epoch. - Report telemetry: Reports now record each gateway's
releasefield from/ar-io/info, ayarn summarizescript prints pass/fail counts grouped by release, and offset rendering now shows<failures>/<observed> (<pct>)so the denominator reflects the sampled subset.
- Reference-gateway chunk-header offset validation: The observer now HEADs the reference gateway's
-
ClickHouse GraphQL query no longer uses
FINAL: The composite ClickHouse backend previously issuedFROM transactions AS t FINALto deduplicate unmergedReplacingMergeTreeversions at read time.FINALpreventedowner_projectionfrom being selected and forced aPrimaryKeyExpandthat widened the skip-index-pruned granule set by ~4×. It is replaced with aLIMIT 1 BY height, block_transaction_index, is_data_item, idclause that dedupes in-engine as a post-sort filter without disabling projection planning or PREWHERE push-down. Safe because Arweave transaction data is immutable: all versions of a given primary key are byte-identical by construction. -
Composite ClickHouse GraphQL Parallelized With SQLite Circuit Breaker: The
CompositeClickHouseDatabasenow runs its ClickHouse and SQLite legs concurrently instead of serially, and wraps the SQLite leg in an opossum circuit breaker. ClickHouse errors (timeout,max_rows_to_read) still propagate to the caller, while SQLite failures degrade the response to ClickHouse-only results with aPARTIAL_RESULTwarning attached via GraphQLextensions.warnings— ending silent partials for tip-of-chain rows and for the single-recordtransaction(id)lookup, which previously returned a barenullwhen SQLite was unavailable. The ClickHouse max-height boundary-optimization cache is now read non-blocking from the request path, with a background refresh keeping it warm. Fan-out preserves warnings end-to-end:RemoteGqlQueryablepulls upstreamextensions.warningsoff each response,GatewaysGqlQueryablemerges them across sources, and synthesizesUPSTREAM_UNAVAILABLE/UPSTREAM_CIRCUIT_OPENwarnings for partially-failed aggregates that were previously logged-and-dropped. New env vars underCLICKHOUSE_SQLITE_CIRCUIT_BREAKER_*(defaults: timeout 5000ms, error threshold 80%, reset timeout 60000ms, rolling window 30000ms). -
ClickHouse
owner_addressBloom + Skip Projection on Tag Filters: ClickHouse projections cannot carry inline skip indexes, so owner+tag GraphQL queries that routed throughowner_projectionscanned every granule within the owner range. Anowner_addressbloom filter is now defined on the maintransactionstable, and the per-queryoptimize_use_projections = 0guard is extended to tag filters. Owner-only queries still benefit fromowner_projection's sort order; owner+tag queries now fall back to the main table whereid_bloom/tag_names_bloom/tag_values_bloom/owner_address_bloomcan prune granules across all three dimensions. Existing deployments get the index registered via an idempotentALTER TABLE ... ADD INDEX IF NOT EXISTSon the nextclickhouse-importcycle; a manualMATERIALIZE INDEX owner_address_bloomis required to populate the index on existing parts. -
Parquet Export Defaults to Include L1 Transactions and Tags:
ParquetExporter.export()defaults now align with thescripts/parquet-exportCLI wrapper and the auto-verify harness, both of which already included L1 by default. Callers that want L2-only output must now passskipL1Transactions/skipL1Tagsexplicitly.
Fixed
-
ClickHouse
owner_projectionnow usable for tag-filtered owner queries: The projection was previously defined withSELECT *, which in ClickHouse excludesMATERIALIZEDcolumns — sotag_namesandtag_valueswere absent from the projection and the optimizer rejected it for any query with predicates on those columns (which includes all tag-filtered GraphQL queries). The projection body is nowSELECT *, tag_names, tag_values, so the optimizer picksowner_projectionfor owner-scoped queries and reads orders of magnitude fewer granules. Existing deployments need a one-time manual migration (DROP PROJECTION/ADD PROJECTION/MATERIALIZE PROJECTION) — see the inline comment insrc/database/clickhouse/schema.sql. Fresh deployments get the corrected projection from theCREATE TABLEbody with no operator action required. -
GraphQL
Block.timestampNon-Nullable Field Error: Addresses a "Cannot return null for non-nullable field Block.timestamp" error that could surface when resolving blocks with incomplete data. -
GraphQL Data Item Signature Fetch Falls Back to
NOT_FOUND: The data-item path inresolveTxSignaturereturned the fetcher result directly, so anundefinedfromSignatureFetcher.getDataItemSignature(e.g., missing attributes or a stream failure reading from the parent bundle) would trigger a "Cannot return null for non-nullable field" error on theString!signature field. The data-item path now mirrors the transaction path and falls back to `NOT_...
Release 76
[Release 76] - 2026-04-17
This is a recommended release focused on response signing, ClickHouse data lifecycle management, and query-path efficiency. Key highlights include RFC 9421 HTTP Message Signatures for cryptographically verifiable gateway responses, tag-based TTL rules for ClickHouse-exported data so operators can expire indexed rows by tag or uploader, and a major ClickHouse schema consolidation into a single partitioned transactions table with bloom filter skip indexes and native projections. It also adds per-host APEX_ARNS_NAME mapping, Parquet export partition progress in the status API, and a clickhouse-import --flat-dir mode. GraphQL gets two performance improvements — skipping SQLite for heights already covered by ClickHouse and skipping the owner.key fetch when only owner.address is selected — plus a fix for duplicate transaction results from ClickHouse and correctly-populated indexedAt / blockPreviousBlock fields.
Added
-
RFC 9421 HTTP Message Signatures for Gateway Responses: The gateway can now sign responses using RFC 9421 HTTP Message Signatures, allowing clients to cryptographically verify response integrity and origin. Controlled by
HTTPSIG_ENABLED(default: false) with an Ed25519 key auto-generated atHTTPSIG_KEY_FILE(default:data/keys/httpsig.pem).HTTPSIG_BIND_REQUEST(default: true) binds each response to the triggering request via@method;reqand@path;req. An attestation linking the key to the operator wallet is uploaded to Arweave on startup whenHTTPSIG_UPLOAD_ATTESTATION=trueandOBSERVER_WALLETis set. HTTPSIG response metadata is documented in OpenAPI for/ar-io/infoand data endpoints. -
Tag-Based TTL Rules for ClickHouse-Exported Data: Operators can now expire rows in the ClickHouse
transactionstable by tag content or uploader owner address. Rules are declared inconfig/clickhouse-ttl-rules.yaml(copy from the committed.example.yamltemplate) and loaded at the top of everyclickhouse-auto-importcycle into four source tables, with exact-match lookups going through refreshingCOMPLEX_KEY_HASHEDdictionaries and prefix matches falling back to scanned tables. Native TTL enforcement deletes rows whenexpires_atelapses. Supports a top-leveldefault_ttl_secondsfallback and per-rulenever_expire: trueexemptions (precedence: exempt > shortest TTL match > default > NULL). v1 applies only to rows imported after rules are loaded; no backfill. The loader fails open on missing/malformed rules to avoid blocking imports. -
Per-Host
APEX_ARNS_NAMEMapping:APEX_ARNS_NAMEnow accepts a comma-separated list of values positionally mapped toARNS_ROOT_HOSTentries (e.g.,APEX_ARNS_NAME=turbo,ar-iowithARNS_ROOT_HOST=arweave.dev,g8way.io). A single value still applies to all hosts. -
Parquet Export Partition Progress in Status API: The admin status endpoint and the
parquet-exportCLI poll loop now surface the current partition range and completed/total partition counts while a Parquet export is in progress. -
clickhouse-import --flat-dirmode:scripts/clickhouse-importaccepts a flat directory of Parquet files named<table>-minHeight:<min>-maxHeight:<max>-rowCount:<n>.parquet(blocks / transactions / tags all in the same directory), as an alternative to the default<table>/data/height=<min>-<max>/*.parquetHive layout.
Changed
-
ClickHouse schema consolidation: The ClickHouse GQL backend now uses a single
transactionstable with partitioning by height, bloom filter skip indexes onidandtags, and native projections for owner and recipient queries, replacing the previous four-table design (transactions,id_transactions,owner_transactions,target_transactions). Column codecs (Delta + ZSTD) andLowCardinalityoncontent_type/signature_typereduce storage. The GQL query layer useshasAnyfor multi-value tag filters and tuple-comparison cursor pagination. Requires ClickHouse 24.8 or later and a one-time full re-import from Parquet — seedocs/parquet-and-clickhouse-usage.md. -
Skip SQLite for Heights Covered by ClickHouse in GraphQL: Opt-in optimization in
CompositeClickHouseDatabaseraises the SQLite fallback'sminHeightto(clickhouseMax - buffer + 1)and skips the SQLite call entirely when the adjusted range is empty. Controlled byCLICKHOUSE_SQLITE_MIN_HEIGHT_ENABLED(default: false), with a configurable safety buffer (default: 10 heights) and a cached ClickHouse max-height lookup (default TTL: 60s). Degrades to prior behavior on lookup failure. -
GraphQL
owner.keyFetch Skipped When Onlyowner.addressRequested: Splitting theTransaction.ownerresolver into field-levelOwner.addressandOwner.keyresolvers lets GraphQL skip the per-row owner key fetch unlesskeyis explicitly selected. Memoization on theOwnerparent still fetches the key only once when multiple aliased selections or overlapping fragments request it in the same query. -
Default ClickHouse Image Bumped to 26.3: The default ClickHouse container image used by
clickhouse-auto-importis now 26.3. -
Observer Image Updated:
OBSERVER_IMAGE_TAGbumped to include epoch source fixes.
Fixed
-
ClickHouse GQL
indexedAtandblockPreviousBlockfields: These fields were previously always returned asundefinedbecause the base SELECT omitted the corresponding columns. They are now populated. -
Duplicate GraphQL Transaction Results from ClickHouse: The
transactionstable usesReplacingMergeTree(inserted_at), which only deduplicates during background merges. Queries now useFINALso GraphQL returns a single edge per id instead of every un-merged version. -
Tag Headers on Manifest-Resolved Responses: When a manifest path resolves to an inner data item,
X-Arweave-Tag-*headers are now populated from the resolved inner item rather than the manifest transaction. -
Turbo Fallback Narrowed to Module-Not-Found: The optional Turbo upload path now falls back only on module-not-found (instead of swallowing unrelated errors) and requires an explicit trigger header before signing.
Image SHAs
ENVOY_IMAGE_TAG:6934e519fb98a46da4c17bdfa51d66225428b7c0CORE_IMAGE_TAG:e032ac521e43b8c987c0da55064f8eb55055c2ceCLICKHOUSE_AUTO_IMPORT_IMAGE_TAG:fb56b2b0203819c2ea439cdb14bb34229da66dafLITESTREAM_IMAGE_TAG:be121fc0ae24a9eb7cdb2b92d01f047039b5f5e8OBSERVER_IMAGE_TAG:21098d2ab630348d56339a745f020374a699d378
Release 75
This is a recommended release focused on on-demand data item resolution and response header enrichment. Key highlights include tag and verification response headers that expose transaction tags and cryptographic metadata directly in HTTP responses, on-demand data item metadata resolution that resolves unindexed data items by parsing ANS-104 bundle binaries on the fly, HyperBEAM as a root TX offset source for efficient bundle navigation without full downloads, and GraphQL on-demand transaction resolution for querying unindexed data items. It also adds configurable chunk GET retry behavior to reduce worst-case retrieval times and Prometheus metrics for root TX semaphore observability.
Added
-
Tag and Verification Response Headers: Data responses on
/raw/:idand/:idnow includeX-Arweave-Tag-*headers with transaction/data item tags, plus verification headers (X-Arweave-Signature,X-Arweave-Owner,X-Arweave-Owner-Address,X-Arweave-Target,X-Arweave-Anchor,X-Arweave-Signature-Type). Enabled by default (ARWEAVE_TAG_RESPONSE_HEADERS_ENABLED=true). Uses a fast local-only resolution path (LMDB txStore -> LRU cache -> GQL DB) with background indexing for uncached items. Includes a configurable byte budget (ARWEAVE_TAG_RESPONSE_HEADERS_MAX_BYTES, default 8KB) and tag count cap (ARWEAVE_TAG_RESPONSE_HEADERS_MAX, default 100). For L2 data item signatures and owner keys,WRITE_ANS104_DATA_ITEM_DB_SIGNATURES=trueis also required. -
On-Demand Data Item Metadata Resolution: Data items not yet indexed locally are resolved on-demand by discovering the root bundle, parsing the binary header, and extracting signature/owner/tags. Results are cached in an LRU cache and persisted to the database for future requests. Background resolution is capped at 1 concurrent operation (configurable via
TX_METADATA_RESOLVE_CONCURRENCY) with fail-fast semantics. -
HyperBEAM Root TX Offset Source (PE-9043): HyperBEAM can now be used as a root transaction offset source for on-demand data item resolution. Uses offset-guided recursive bundle index navigation to extract complete data item metadata without downloading full bundles. Controlled by
HYPERBEAM_ROOT_TX_ENABLEDandHYPERBEAM_ENDPOINT(default:arweave.net). -
Configurable Chunk GET Retry Behavior (PE-9042): Arweave chunk retrieval retry count and geometry timeout are now configurable, reducing worst-case chunk retrieval time from ~115s to ~15s. New env vars:
ARWEAVE_CHUNK_RETRY_COUNT(default: 5),ARWEAVE_TX_GEOMETRY_TIMEOUT_MS(default: 5000),ARWEAVE_TX_GEOMETRY_TIMEOUT_RETRIES(default: 2). -
GraphQL On-Demand Transaction Resolution: The
transaction(id)GraphQL query can now resolve unindexed data items on-demand by extracting metadata from ANS-104 bundle binaries. Enabled by default (GRAPHQL_ON_DEMAND_RESOLUTION_ENABLED=true). Includes a configurable timeout (GRAPHQL_ON_DEMAND_RESOLUTION_TIMEOUT_MS, default 5s) and concurrency limit (GRAPHQL_ON_DEMAND_RESOLUTION_MAX_CONCURRENT, default 1). Only applies to single-ID lookups; the pluraltransactions(...)query is unaffected. -
SignatureType in GraphQL: The
signatureTypefield is now surfaced in GraphQL transaction responses for data items. -
Root TX Semaphore Prometheus Metrics: New Prometheus metrics for root TX resolution semaphore observability, including acquire/release/timeout counters and queue depth gauge.
Changed
-
Root TX Lookup Order:
ROOT_TX_LOOKUP_ORDERreordered to prefer GraphQL over HyperBEAM and CDB for faster local resolution. -
HyperBEAM Request Timeout: Default HyperBEAM request timeout lowered to 500ms.
Docker Images
| Service | Image |
|---|---|
| core | ghcr.io/ar-io/ar-io-core:6e023ad1dbdfac67fdac1e62449bedfef1bb7fe4 |
| envoy | ghcr.io/ar-io/ar-io-envoy:6934e519fb98a46da4c17bdfa51d66225428b7c0 |
| clickhouse-auto-import | ghcr.io/ar-io/ar-io-clickhouse-auto-import:dec86f85bb9585658e424f393083bf6d69a7c5e1 |
| observer | ghcr.io/ar-io/ar-io-observer:9356a3d5cc2ed9ac406a62c3a01450ae80ddc6c3 |
| litestream | ghcr.io/ar-io/ar-io-litestream:be121fc0ae24a9eb7cdb2b92d01f047039b5f5e8 |
| redis | redis:7 |
| clickhouse | clickhouse/clickhouse-server:25.4 |
| otel-collector | otel/opentelemetry-collector-contrib:0.119.0 |
Release 74
This is a recommended release focused on cache performance, multi-domain ArNS support, and content moderation correctness. Key highlights include background caching for range request cache misses to improve video/media streaming performance, multiple ArNS root hosts for serving ArNS names across multiple domains from a single gateway, contiguous data cache hit/miss Prometheus metrics for improved observability, and configurable cache control for blocked responses. It also corrects HTTP 451 handling for blocked content, simplifies the parquet export pipeline, and adds ClickHouse and block verification to auto-verify.
Added
-
Background Caching for Range Request Cache Misses: When a range request (e.g., byte-range for video seeking) misses the local cache, the gateway now optionally fetches and caches the full item in the background so subsequent requests (range or full) are served locally. Controlled by
BACKGROUND_CACHE_RANGE_MAX_SIZE(default: 0 / disabled) andBACKGROUND_CACHE_RANGE_CONCURRENCY. Includes deduplication, capacity-based drop semantics, and Prometheus metrics for monitoring cache activity -
Multiple ArNS Root Hosts: Operators can now serve ArNS names across multiple domains from a single gateway instance by providing a comma-separated list in
ARNS_ROOT_HOST(e.g.,ARNS_ROOT_HOST=arweave.dev,g8way.io). The first host is used as the "primary" for gateway identity headers. ArNS resolution, apex content, and sandbox redirects work per-matched host with longest-suffix matching (#621) -
ClickHouse Verification in Auto-Verify: Auto-verify is a data validation tool that checks consistency of indexed blockchain data (blocks, transactions, data items) across multiple backends (SQLite, Parquet, ClickHouse). This adds an optional ClickHouse source for verification in addition to the existing SQLite and Parquet sources.
-
Block Verification in Auto-Verify: Verify block data alongside transactions and data items
-
Bundle Data Prefetch in Auto-Verify: During auto-verify runs, raw bundle bytes are now fetched from the local gateway while it is still running, then parsed after shutdown. Previously the bundle-parser source had to fetch from arweave.net after the gateway was stopped, which was significantly slower.
-
Contiguous Data Cache Hit/Miss Metrics: New
contiguous_data_cache_hits_totalandcontiguous_data_cache_misses_totalPrometheus counters inReadThroughDataCache, labeled byrequest_type(rangevsfull). Enables operators to monitor cache performance per request type. -
Accurate Cache Miss vs Not-Found Metrics: Cache miss counter now fires only after a successful upstream fetch (data exists but wasn't cached locally). A new
contiguous_data_not_found_totalcounter tracks requests where data is unavailable in any source, preventing not-found requests from inflating the miss count and skewing the cache hit rate. -
Configurable Cache Control for Blocked (451) Responses: New
CACHE_BLOCKED_MAX_AGEenv var (default: 30 days, matching stable data TTL) controls theCache-Controlmax-age sent with 451 responses. Previously, blocked responses used the short not-found TTL, causing CDNs and proxies to re-request blocked content too frequently. -
Parent Bundle ID in Missing Data Item Errors: Auto-verify
compareItemsnow includes the parent bundle ID inmissing_in_sourcediscrepancy messages for data items, making it easier to identify which bundle a missing item belongs to when debugging bundle-parser failures.
Changed
-
Parquet Export Pipeline Simplification: Eliminated DuckDB intermediate tables from the export pipeline. All core export logic moved from the bash script into
src/workers/parquet-exporter.ts, with the CLI script becoming a thin wrapper around the admin API. The CLI now uses--api-host/--api-portinstead of--core-db/--bundles-db. -
Removed Legacy Auto-Verify CLI Options: Cleaned up deprecated verification flags
Fixed
-
ClickHouse ETL Height Range: Fixed off-by-one errors in height range calculations in
clickhouse-auto-import -
ClickHouse ETL Exit Code Capture: Fixed
$?capturing the exit code of a variable assignment instead of thecurlcommand -
HTTP 451 for Blocked Content: Corrects r73's blocked-content status code from 452 (non-standard) to 451 ("Unavailable For Legal Reasons"), the IANA-registered standard for content blocked due to legal or policy reasons.
-
Trusted Gateway ArNS 451 Handling: The
TrustedGatewayArNSResolvernow accepts HTTP 451 responses from trusted gateways instead of treating them as errors. When a trusted gateway indicates a name is blocked, the local gateway respects that moderation signal and returns 451 to the client rather than falling through to the on-demand resolver. -
Serving Cached Data with Undefined or Zero Content-Length: The read path of
ReadThroughDataCachenow skips cache entries with a missing or zerodataSize, preventing responses without aContent-Lengthheader. The write path already rejected zero-size entries; this closes the corresponding read-side gap. -
Parquet Export and ClickHouse Import Robustness: Parquet-export script now uses
curl -owith temp files instead ofhead/tailparsing to handle multiline JSON API responses correctly. Auto-verify'simportToClickHouseswitches toexecFileSyncwith an args array, preventing shell injection in ClickHouse import invocations. -
Parquet Export Verify-Count Non-Zero Exit:
parquet-export --verify-countnow exits non-zero when row counts don't match, making it useful in CI and automation pipelines. Also validatescurlavailability at startup alongsidepython3. -
High-Severity Dependency Vulnerabilities: Resolved known vulnerabilities in transitive production dependencies via yarn resolutions:
path-to-regexp(ReDoS, via express/express-openapi-validator),h3(request smuggling),picomatch(glob injection),preact(VNode injection),socket.io-parser(unbounded binary attachments),undici(multiple HTTP smuggling/memory issues), and bumpedfast-xml-parserfrom 5.3.6 to 5.5.9. -
JSON Data Files Missing from Production Build:
offset-block-mapping.jsonwas excluded fromdist/because the build copy step only matched.graphql,.sql, and.luafiles. This caused a startup warning and fallback to slower full-range block searches in containers..jsonfiles are now included in the copy step. -
Auto-Verify Prefetch Timing and Empty ClickHouse URL: Removed the
last_fully_indexed_atfilter from the bundle prefetch query — this flag is set asynchronously byBundleRepairWorker, causing prefetch to find 0 bundles even when indexing was complete. Also handlesAUTO_VERIFY_CLICKHOUSE_URL=""(empty string) explicitly to prevent a crash when the variable is set but empty in.env.
Docker Images
| Service | Image |
|---|---|
| core | ghcr.io/ar-io/ar-io-core:9ea1a4cd12e220ea9790c1a457a0133a3dfd5960 |
| envoy | ghcr.io/ar-io/ar-io-envoy:6934e519fb98a46da4c17bdfa51d66225428b7c0 |
| clickhouse-auto-import | ghcr.io/ar-io/ar-io-clickhouse-auto-import:fc32edf92518d28cd3a5bbd759ad92d97b453322 |
| observer | ghcr.io/ar-io/ar-io-observer:9356a3d5cc2ed9ac406a62c3a01450ae80ddc6c3 |
| litestream | ghcr.io/ar-io/ar-io-litestream:be121fc0ae24a9eb7cdb2b92d01f047039b5f5e8 |
| redis | redis:7 |
| clickhouse | clickhouse/clickhouse-server:25.4 |
| otel-collector | otel/opentelemetry-collector-contrib:0.119.0 |
| ao-cu | ghcr.io/permaweb/ao-cu:08436a88233f0247f3eb35979dd55163fd51a153 |
Release 73
Added
-
Unified Cache-Control Headers: Move default Cache-Control from Envoy's catch-all route into Express middleware, eliminating duplicate headers and making data handler cache durations operator-configurable via
DEFAULT_CACHE_CONTROL_MAX_AGE_SECONDS,STABLE_CACHE_CONTROL_MAX_AGE_DAYS, and related env vars (PE-9002) -
Cache-Only Client IPs/CIDRs: New
CACHE_ONLY_CLIENT_IPS_AND_CIDRSenv var to short-circuit data retrieval requests with a 404 if the data is not already cached locally, useful for protecting upstream bandwidth from specific high-volume clients -
Client Disconnect Prometheus Metric: New
client_disconnect_totalcounter metric tracks when clients abort requests before the response completes (PE-9000) -
P2P Contiguous Data Retrieval Improvements: Major overhaul of peer data retrieval to reduce tail latency and improve cache efficiency (PE-9007)
- Hedged requests: Fires a second request to the next candidate peer after a configurable delay (
PEER_HEDGE_DELAY_MS) if no response yet; first success cancels all others, capped atPEER_MAX_HEDGED_REQUESTS - Per-peer concurrency limiter: Fail-fast counter that skips saturated peers instead of queuing, configurable via
PEER_MAX_CONCURRENT_OUTBOUND - Consistent hash ring: Routes each data ID to the same small set of "home" peers for cache locality, with weighted fallback for remaining slots; configured via
PEER_HASH_RING_VIRTUAL_NODESandPEER_HASH_RING_HOME_SET_SIZE - Decoupled candidate pool:
PEER_CANDIDATE_COUNTreplaces the oldmin(peerCount, 3)logic, giving hedging a deeper bench to draw from - Chunk peer selection via hash ring: Chunk requests are also routed through the hash ring by absolute offset for improved peer cache utilization
- Hedged requests: Fires a second request to the next candidate peer after a configurable delay (
-
Request Trace IDs: Every HTTP request gets a unique
requestIdin Winston log entries via AsyncLocalStorage, independent of OTEL. Reads or generatesX-Request-Idheaders and echoes them in responses for end-to-end request correlation (PE-8977)
Changed
- HTTP 452 for Blocked Content: Blocked content now returns HTTP 452 with a descriptive message identifying the blocked ID and the node's content policy, instead of a generic 404 Not Found
Fixed
-
HTTP 499 Only for Actual Client Disconnects: Internal data retrieval timeouts (e.g., upstream gateway timeouts) were being misidentified as client disconnects. Now checks
req.signal.abortedto confirm the client actually disconnected before returning 499 -
/tx_anchorRoute Shadowing: Move/tx_anchorroute before/txin Envoy config to prevent prefix-match shadowing that caused/tx_anchorrequests to be handled by the/txroute -
Security Audit Vulnerabilities: Bump
simple-gitto fix critical RCE viablockUnsafeOperationsPluginbypass; addmulterresolution to fix high severity DoS vulnerabilities inexpress-openapi-validator
Docker Images
| Image | Tag |
|---|---|
ghcr.io/ar-io/ar-io-core |
92defe82acc1e7d2337bdacde1f65300503768ae |
ghcr.io/ar-io/ar-io-envoy |
bedcb761098a2729c49bcfb3f7546151f5a6b632 |
ghcr.io/ar-io/ar-io-clickhouse-auto-import |
4512361f3d6bdc0d8a44dd83eb796fd88804a384 |
ghcr.io/ar-io/ar-io-litestream |
be121fc0ae24a9eb7cdb2b92d01f047039b5f5e8 |
ghcr.io/ar-io/ar-io-observer |
9356a3d5cc2ed9ac406a62c3a01450ae80ddc6c3 |
Release 72
This is a recommended release focused on data retrieval reliability and caching intelligence. Key highlights include a negative data cache that reduces upstream load for consistently missing data, direct byte offset hints to help gateways locate data when internal lookup mechanisms fall short, untrusted data caching with stochastic re-verification, and significant stream reliability improvements that eliminate false timeouts on large transfers. It also adds gateway loop prevention via per-gateway via-chain detection.
Added
-
Negative Data Cache: Two-phase cache that tracks data IDs consistently missing across configurable thresholds and short-circuits future requests with 404 responses, reducing upstream load during outages and for permanently unavailable data
- Includes exponential backoff with fast re-promotion, health gating to prevent false positives during upstream outages, and TTL-based miss tracker eviction
- Controlled via
NEGATIVE_CACHE_ENABLED(default: true),NEGATIVE_CACHE_MAX_SIZE,NEGATIVE_CACHE_TTL_MS,NEGATIVE_CACHE_MISS_THRESHOLD_MS, andNEGATIVE_CACHE_MISS_COUNT_THRESHOLD
-
Direct Byte Offset Hints for Data Item Retrieval: Clients can supply
X-AR-IO-Root-Transaction-Id,X-AR-IO-Root-Path,X-AR-IO-Root-Data-Offset, andX-AR-IO-Root-Data-Sizeheaders to bypass server-side bundle lookups and resolve data items via direct byte offsets- Includes
fetch-with-hintCLI tool for resolving hints via GraphQL
- Includes
-
DATA_CACHED Webhook Event: Emits a webhook when data is cached for the first time, enabling external content moderation sidecars (e.g., phishing scanners)
- Opt-in via
WEBHOOK_EMIT_DATA_CACHED_EVENTS=true(default: false)
- Opt-in via
-
Untrusted Data Caching with Stochastic Re-verification: Caches all upstream data optimistically instead of only when a hash exists locally, with configurable background re-verification rates to ensure integrity
- Controlled via
UNTRUSTED_CACHE_RETRY_RATE(default: 0.1) andTRUSTED_CACHE_RETRY_RATE(default: 0.0) - Evicts data on hash mismatch to maintain integrity
- Controlled via
-
12-Hour Cache-Control Tier: New middle tier for data that is unstable but from a trusted source (e.g., trusted bundlers), providing a three-tier system: stable (30d, immutable) > unstable trusted (12h) > unstable (2h)
-
Chunk Broadcast Improvements: All 5 tip nodes (tip-1 through tip-5) are now included in default preferred chunk POST nodes, with shuffled ordering and a minimum success requirement
- Controlled via
CHUNK_POST_MIN_PREFERRED_SUCCESS_COUNT(default: 2)
- Controlled via
-
OTEL Resource Attributes Passthrough: Operators can set custom OpenTelemetry resource attributes via the standard
OTEL_RESOURCE_ATTRIBUTESenvironment variable, with env var values overriding auto-detected attributes -
Gateway Loop Prevention: Per-gateway via-chain detection skips individual gateways already visited in the request path, with hop count validation against
MAX_DATA_HOPS(3) as defense-in-depth. Client IP, forwarded IPs, and via header are now included as OTEL span attributes for observability.
Changed
- Default
CDB64_REMOTE_RETRIEVAL_ORDERchanged to'chunks'only, removing gateways from the default order since range requests aren't effectively cached on gateways
Fixed
-
Stream Reliability Improvements: Replaced wall-clock stream timeouts with backpressure-aware stall-based timeouts (30s no-data threshold), preventing false kills and truncated responses on large or slow transfers
- Extracted
pipeStreamToResponsehelper for consistent stream pipe and error handling across routes
- Extracted
-
Fixed Axios
CanceledErrornot being normalized toAbortError, causing incorrect upstream disconnection handling -
Fixed streams not being destroyed on unexpected HTTP status codes from peers, preventing socket leaks
-
Added 206 Partial Content acceptance for ranged peer requests
-
Fixed upstream stream not being destroyed on premature client disconnect
-
Fixed
detectLoopInViaChainto lowercase via entries for proper case-insensitive matching
Docker Images
ghcr.io/ar-io/ar-io-envoy:17a2cbdb71e1d1eba1a3c4e29aff96d69feb3246ghcr.io/ar-io/ar-io-core:fb4017499c42a60d81bf5d0624a26b84841cd005ghcr.io/ar-io/ar-io-clickhouse-auto-import:4512361f3d6bdc0d8a44dd83eb796fd88804a384ghcr.io/ar-io/ar-io-observer:9356a3d5cc2ed9ac406a62c3a01450ae80ddc6c3ghcr.io/ar-io/ar-io-litestream:be121fc0ae24a9eb7cdb2b92d01f047039b5f5e8
Release 71
This is a recommended release that adds per-gateway trust configuration for TRUSTED_GATEWAYS_URLS, enabling operators to mark individual gateways as trusted or untrusted for finer-grained data verification control. It also includes peer URL tracking in chunk broadcast responses for improved debuggability, and fixes for upstream gateway content-length validation to prevent serving bogus responses from gateways that return 200 instead of 404.
Added
-
Per-Gateway Trust Flag for
TRUSTED_GATEWAYS_URLS: Extended theTRUSTED_GATEWAYS_URLSconfiguration format to support per-gateway trust levels- Untrusted gateways only cache data when the hash matches a known value, providing defense-in-depth against serving incorrect data
- Default configuration now uses
turbo-gateway.com(trusted) witharweave.netas an untrusted fallback
-
Peer URL in Chunk Broadcast Responses: Chunk broadcast responses now include the peer URL for better debuggability when troubleshooting chunk propagation issues
Changed
- Default
TRUSTED_GATEWAYS_URLSnow usesturbo-gateway.comas the primary trusted gateway witharweave.netas an untrusted fallback
Fixed
-
Upstream Gateway Content-Length Validation: Added validation of content-length in
GatewaysDataSourceto reject responses with missing or zero content-length, preventing upstream gateways from serving bogus HTML landing pages when they return 200 instead of 404. -
Zero-Byte Data Item Handling: Removed size-0 rejection from data handlers to allow zero-byte data items to be served correctly.
Docker Images
ghcr.io/ar-io/ar-io-envoy:17a2cbdb71e1d1eba1a3c4e29aff96d69feb3246ghcr.io/ar-io/ar-io-core:dbdf97db26627c1fd38fd765eebe8db513a66dffghcr.io/ar-io/ar-io-clickhouse-auto-import:4512361f3d6bdc0d8a44dd83eb796fd88804a384ghcr.io/ar-io/ar-io-observer:9356a3d5cc2ed9ac406a62c3a01450ae80ddc6c3ghcr.io/ar-io/ar-io-litestream:be121fc0ae24a9eb7cdb2b92d01f047039b5f5e8
Release 70
This is a recommended release that introduces CDB64 download tooling for fetching remote partitioned indexes with resume support, chunk request concurrency limiting and first-data timeouts for improved data retrieval reliability, and expanded CDB64 root TX index coverage with new AO and without-content-type index sources. It also includes critical fixes for event listener leaks, stream data loss, and request cancellation under high concurrency, along with defense-in-depth loop protection enhancements and a new auto-verify indexing tool for cross-source bundle data validation.
Added
-
CDB64 Download Tool: New CLI tool (
tools/download-cdb64) for fetching remote partitioned CDB64 indexes with production-grade reliability- Downloads partition files from manifest sources (HTTP URLs, Arweave TX IDs, byte-range specifications, local files)
- HTTP Range request resume for interrupted downloads — partial
.tmpfiles are preserved and downloads resume from where they left off - Per-partition retry support with configurable retry count (
--retries/-r, default: 5) - Concurrent downloads with configurable parallelism (
--concurrency/-c, default: 3) - SHA-256 verification of downloaded partitions against manifest checksums
- Generates updated manifest with local file locations on completion
-
Streaming Partitioned CDB64 Writer: New low-memory CDB64 generation mode for large indexes
- Reduces peak memory from O(total_records) to O(largest_partition) via two-phase scatter/build approach
- Phase 1 writes records to per-partition temp files; Phase 2 builds CDB files sequentially
- New
--low-memoryflag added to all CDB64 CLI tools (requires--partitioned) - Progress callbacks show partition-level build status
-
AO and Without-Content-Type CDB64 Index Sources: Expanded default CDB64 root TX index coverage
- New AO data items index (~1.6B records) covering AO-tagged data items up to block height 1,820,000
- New without-content-type index (~1.2B records) covering data items lacking a Content-Type tag up to block height 1,820,000
- Default
CDB64_ROOT_TX_INDEX_SOURCESnow includes all three indexes
-
Chunk Request Concurrency Limiting and First-Data Timeout: New controls for chunk-based data retrieval under load
CHUNK_REQUEST_CONCURRENCY(default: 50): Limits concurrent chunk fetch requests to prevent overwhelming backendsCHUNK_FIRST_DATA_TIMEOUT_MS(default: 10000): Timeout for receiving the first chunk of data; if exceeded, request falls through to alternative data sources. Set to 0 to disable.
-
Root Bundle Gateway Fallback Path: Added
/<id>fallback path for root bundle gateway requests when/raw/<id>fails- Enables bundle retrieval from HyperBEAM endpoints that may not support the
/raw/<id>path - Separate
rootBundleGatewaysDataSourceinstance configured with fallback enabled
- Enables bundle retrieval from HyperBEAM endpoints that may not support the
-
ArNS Resolver Host Override: New
TRUSTED_ARNS_RESOLVER_HOST_HEADERenvironment variable decouples connection target from Host header in ArNS resolver, with__NAME__placeholder substitution for dynamic values -
Defense-in-Depth Loop Protection Improvements (PE-8947): Additional safeguards against request forwarding loops between gateways
- Hop count validation added to
GatewaysDataSource(MAX_DATA_HOPS = 3) - Origin/IP blocking applied to peer forwarding path via
FilteredContiguousDataSource - Startup warning when
TRUSTED_GATEWAYS_URLScontains this gateway's ownARNS_ROOT_HOST, indicating a self-forwarding loop
- Hop count validation added to
-
Auto-Verify Indexing Tool: New tool (
tools/auto-verify) for cross-source bundle data comparison and indexing consistency validation- Indexes configurable block ranges, then compares data items across SQLite, Parquet, GraphQL, and independently-parsed raw bundles
- Verifies field consistency: offset, size, ownerOffset, ownerSize, signatureOffset, signatureSize, rootParentOffset
- Bundle indexing timeout (5 minutes) for graceful handling of slow indexing
- Cache preserved by default for faster iteration across runs
- Detailed discrepancy output shows data item ID, field name, and per-source values
-
Git Worktree Helper: New development tool (
tools/wt) for parallel development using git worktrees- Creates worktrees under
wt/<branch>with symlinked.envandCLAUDE.local.md - Commands:
add,rm,lswith--existingflag for checking out existing branches - Automatically runs
yarn installwith a cleandata/directory per worktree
- Creates worktrees under
Changed
- Default ArNS gateway changed from
ar-io.nettoturbo-gateway.com - Default Arweave gateway in test suites changed from
arweave.nettoturbo-gateway.com - Renamed AO CDB directory from
cdb64-root-tx-index-aotocdb64-root-tx-index-ao-to-height-1820000for naming consistency - Removed unused Cucumber dependency
Fixed
- Stream Data Loss Prevention: Fixed range stream being put into flowing mode prematurely, causing data to be emitted and lost before the consumer could attach
- HTTP Request Cancellation: Threaded AbortController through chunk timeout to properly cancel in-flight HTTP requests instead of only rejecting the promise
- Timer Leaks: Fixed timeout timer leaks in chunk request implementation by hoisting timeout variable for proper cleanup in finally blocks
- Event Listener Leaks: Replaced
AbortSignal.any()withanySignal()from theany-signalpackage and added properClearableSignal.clear()calls in finally blocks across composite ArNS resolver and chunk request paths to prevent listener accumulation under high concurrency - CDB64 Config Order: Fixed CDB64 root TX index source search order to preserve configuration order instead of sorting alphabetically
- Data Item Tag Handling: Content-Type and Content-Encoding tag processing now uses first match instead of last match, aligning with legacy gateway behavior
- Docker Build: Multi-stage Dockerfile now copies
resources/directory into runtime stage so the default CDB64 manifest is accessible inside containers - Cache Directory Cleanup:
.gitkeepfiles properly recreated after cleaning cache directories - CDB64 Test Reliability: Conditional test skipping when native CDB64 module is unavailable; direct module probing prevents async rejection leaks in CI
- Dependency Security: Updated axios (DoS via
__proto__), tar (symlink/overwrite CVEs), qs (arrayLimit bypass DoS), fast-xml-parser (RangeError DoS), and other transitive dependencies with known vulnerabilities
Release 69
This is a recommended release that introduces DNS-based multi-peer discovery via Envoy's Endpoint Discovery Service, enabling automatic Arweave peer detection with health-checked routing and consensus-based failover. It also adds multi-layered HyperBEAM request loop prevention using header, via-chain, and User-Agent detection to block infinite forwarding loops between gateways. Additionally, this release includes comprehensive CDB64 documentation covering operator guides, format specifications, and tooling reference.
Added
-
DNS-Based Multi-Peer Discovery with Envoy EDS: Automatic Arweave peer discovery and health-checked routing via Envoy's Endpoint Discovery Service
- Resolves DNS records (e.g.,
peers.arweave.xyz) to discover Arweave peers automatically - Health-checks peers and classifies them as "full" (complete blockchain data) or "partial" (incomplete) based on sync status
- Routes requests to fully-synced peers first with automatic failover to partial peers
- Consensus-based reference height calculation prevents routing to stale or outlier peers
- New Prometheus metrics for peer discovery, classification, and health check monitoring
- Configurable via
ARWEAVE_PEER_DNS_RECORDS,ARWEAVE_PEER_DNS_PORT,ARWEAVE_PEER_HEALTH_CHECK_INTERVAL_MS, and related environment variables - Enabled by default with
ENABLE_ARWEAVE_PEER_EDS=true; falls back to staticTRUSTED_NODE_HOSTwhen disabled - EDS files validated on startup with corrupt files automatically removed and re-seeded
- Resolves DNS records (e.g.,
-
HyperBEAM Request Loop Prevention: Multi-layered detection of compute-origin requests to prevent infinite forwarding loops between gateways. Local data sources (cache, S3, database) always continue to serve data normally.
- Header-based detection: Requests with configured headers (default:
ao-peer-port) are identified as compute-origin and blocked from remote forwarding. Configurable viaSKIP_FORWARDING_HEADERS. - Via-chain loop detection: New
X-AR-IO-Viaheader tracks the chain of gateway identities across hops. When a gateway detects its own identity in the via chain, it stops forwarding to prevent loops. Gracefully degrades whenARNS_ROOT_HOSTis not configured. - User-Agent detection: Requests with missing or empty User-Agent headers skip remote forwarding by default, catching HTTP clients like Erlang's
gun(used by HyperBEAM) that don't send a User-Agent. Configurable viaSKIP_FORWARDING_EMPTY_USER_AGENT(default:true). Additionally,SKIP_FORWARDING_USER_AGENTSallows specifying User-Agent substrings for case-insensitive matching (e.g.,HyperBEAM).
- Header-based detection: Requests with configured headers (default:
-
CDB64 Documentation: Comprehensive documentation for the CDB64 root transaction index feature
- Operator guide (
docs/cdb64-guide.md) covering configuration, monitoring, custom index sources, and troubleshooting - Format specification (
docs/cdb64-format.md) detailing the CDB64 binary format, key encoding, and location types - Tools reference (
docs/cdb64-tools.md) documenting all 6 CDB64 CLI tools with usage examples - Overview page (
docs/cdb64.md) linking all CDB64 documentation - Documentation index (
docs/INDEX.md) providing a navigable overview of all gateway documentation - CDB64 section added to README for quick orientation
- Glossary entries for CDB64-related terms
- Fixed default values for
CDB64_CACHE_SIZEandCDB64_ROOT_TX_INDEX_SOURCESindocs/envs.md - Build script (
tools/build-cdb64-napi) for compiling the native CDB64 N-API module from source
- Operator guide (
Changed
- Updated observer to increase default chunk observation sample rate to 20%
Docker Images
| Image | SHA |
|---|---|
| ar-io-envoy | 86c53dcbf0bb1533c5d32d44f2db11ab9cfa2629 |
| ar-io-core | 56c7e1c0fe14d8033ddd9fdd57344933b1f1baaa |
| ar-io-clickhouse-auto-import | 4512361f3d6bdc0d8a44dd83eb796fd88804a384 |
| ar-io-litestream | be121fc0ae24a9eb7cdb2b92d01f047039b5f5e8 |
Release 68
Release 68 - 2026-02-04
This is an optional release that introduces A/B testing infrastructure for data sources via the new SamplingContiguousDataSource, enabling operators to safely evaluate alternative retrieval strategies with controlled traffic exposure and built-in metrics. It also includes CDB64 location type renames for improved clarity in manifest schemas, and data retrieval tooling enhancements with content validation options for easier gateway comparison testing.
Added
-
SamplingContiguousDataSource for A/B Testing: New data source wrapper that
probabilistically routes requests through an experimental source (PE-8900)- Enables safe A/B testing of new retrieval strategies with controlled traffic
exposure - Two sampling strategies:
random(per-request) ordeterministic
(consistent per ID using SHA-256 hash) - Configurable sampling rate (0-1) with validation to reject invalid values
- New Prometheus metrics:
sampling_decision_total,sampling_request_total,
sampling_latency_ms - OpenTelemetry span instrumentation for sampled requests
- Enables safe A/B testing of new retrieval strategies with controlled traffic
-
Data Retrieval Tool Enhancements: New options in
tools/test-data-retrieval
for content validation--bytes <n>: Fetch first N bytes using HTTP Range headers for content
comparison--max-size <bytes>: Two-phase retrieval (HEAD then GET) for content under
size threshold- RPS (requests per second) statistics in console and JSON output
- SHA-256 hash computation for content comparison between gateways
Changed
- CDB64 Arweave Location Type Renames: Renamed location types in CDB64
manifests for clarityarweave-tx→arweave-id(field:txId→id)arweave-bundle-item→arweave-byte-range(field:txId→rootTxId,
offset→dataOffsetInRootTx, added optionaldataItemId, removedsize
from location)- Includes script to add
dataItemIdfields by reading ANS-104 headers - Updated bundled manifest with new format
Docker Images
| Image | SHA |
|---|---|
ghcr.io/ar-io/ar-io-envoy |
4755fa0a2deb |
ghcr.io/ar-io/ar-io-core |
86e9adedb44f |
ghcr.io/ar-io/ar-io-clickhouse-auto-import |
4512361f3d6b |
ghcr.io/ar-io/ar-io-litestream |
be121fc0ae24 |