diff --git a/website/src/pages/en/graph-horizon/overview.mdx b/website/src/pages/en/graph-horizon/overview.mdx index ab5026c61e26..b626f0686d37 100644 --- a/website/src/pages/en/graph-horizon/overview.mdx +++ b/website/src/pages/en/graph-horizon/overview.mdx @@ -41,7 +41,7 @@ The **`SubgraphService`** is the first and currently only data service implement ### Integrated Payments Protocol -While the current protocol uses TAP (Timeline Aggregation Protocol) for payments, Horizon brings the payments infrastructure directly into the core protocol. The payments protocol in Horizon was designed as a generalized version of TAP v1, allowing integration with TAPv2 (GraphTally) but also any other arbitrary payment collection system. +Horizon brings the payments infrastructure directly into the core protocol. The payments protocol in Horizon was designed as a generalized framework, with [GraphTally](/indexing/tap) (formerly TAP) as the integrated payment collection system. This architecture also supports other arbitrary payment collection systems in the future. ### GraphPayments and PaymentsEscrow diff --git a/website/src/pages/en/graph-horizon/what-changes.mdx b/website/src/pages/en/graph-horizon/what-changes.mdx index cfffea952a4a..40ab1e0db8a7 100644 --- a/website/src/pages/en/graph-horizon/what-changes.mdx +++ b/website/src/pages/en/graph-horizon/what-changes.mdx @@ -42,10 +42,10 @@ Horizon does not change the way indexing rewards work, the rewards formula remai ### Serving queries and the gateway behavior -The indexer stack will support both the current and Horizon gateway infrastructure, which means with the same indexer stack version indexers will be able to serve queries before and after the Horizon upgrade. It’s worth clarifying however the gateway behavior: +The gateway now exclusively uses TAPv2 (GraphTally) receipts. Indexers must run `indexer-service-rs` and `indexer-tap-agent` v2.0.0 or later, which require Graph Horizon to be enabled. -- Before Horizon, the gateway will serve queries using TAPv1 receipts. -- After Horizon, the gateway will _only_ serve queries using TAPv2 (GraphTally) receipts. This means that indexers that have not upgraded their stack to Horizon will stop receiving queries. The gateway infrastructure will continue to accept old TAPv1 receipts and vouchers to ensure those can be redeemed and no fees are lost. +- The gateway only serves queries using TAPv2 (GraphTally) receipts. Indexers that have not upgraded their stack to Horizon will not receive queries. +- Starting with `indexer-service-rs` and `indexer-tap-agent` v2.0.0, legacy TAPv1 receipt support has been removed entirely. All receipt processing uses Horizon exclusively. ## For Delegators diff --git a/website/src/pages/en/indexing/overview.mdx b/website/src/pages/en/indexing/overview.mdx index 01322f5d1747..416dfb4d53a7 100644 --- a/website/src/pages/en/indexing/overview.mdx +++ b/website/src/pages/en/indexing/overview.mdx @@ -17,7 +17,7 @@ The minimum stake for an Indexer is currently set to 100K GRT. ### What are the revenue streams for an Indexer? -**Query fee rebates** - Payments for serving queries on the network. These payments are mediated via state channels between an Indexer and a gateway. Each query request from a gateway contains a payment and the corresponding response a proof of query result validity. +**Query fee rebates** - Payments for serving queries on the network. These payments are mediated via [GraphTally](/indexing/tap) between an Indexer and a gateway. Each query request from a gateway contains a signed receipt and the corresponding response a proof of query result validity. **Indexing rewards** - Generated via a 3% annual protocol wide inflation, the indexing rewards are distributed to Indexers who are indexing Subgraph deployments for the network. @@ -127,13 +127,15 @@ Indexers may differentiate themselves by applying advanced techniques for making At the center of an Indexer's infrastructure is the Graph Node which monitors the indexed networks, extracts and loads data per a Subgraph definition and serves it as a [GraphQL API](/about/#how-the-graph-works). The Graph Node needs to be connected to an endpoint exposing data from each indexed network; an IPFS node for sourcing data; a PostgreSQL database for its store; and Indexer components which facilitate its interactions with the network. -- **PostgreSQL database** - The main store for the Graph Node, this is where Subgraph data is stored. The Indexer service and agent also use the database to store state channel data, cost models, indexing rules, and allocation actions. +- **PostgreSQL database** - The main store for the Graph Node, this is where Subgraph data is stored. The Indexer service, TAP agent, and Indexer agent also use the database to store receipt data, cost models, indexing rules, and allocation actions. - **Data endpoint** - For EVM-compatible networks, Graph Node needs to be connected to an endpoint that exposes an EVM-compatible JSON-RPC API. This may take the form of a single client or it could be a more complex setup that load balances across multiple. It's important to be aware that certain Subgraphs will require particular client capabilities such as archive mode and/or the parity tracing API. - **IPFS node (version less than 5)** - Subgraph deployment metadata is stored on the IPFS network. The Graph Node primarily accesses the IPFS node during Subgraph deployment to fetch the Subgraph manifest and all linked files. Network Indexers do not need to host their own IPFS node, an IPFS node for the network is hosted at https://ipfs.thegraph.com. -- **Indexer service** - Handles all required external communications with the network. Shares cost models and indexing statuses, passes query requests from gateways on to a Graph Node, and manages the query payments via state channels with the gateway. +- **Indexer service ([`indexer-service-rs`](https://github.com/graphprotocol/indexer-rs))** - Handles all required external communications with the network. Shares cost models and indexing statuses, passes query requests from gateways on to a Graph Node, and manages query payments via [GraphTally](/indexing/tap). + +- **TAP agent ([`indexer-tap-agent`](https://github.com/graphprotocol/indexer-rs))** - Aggregates GraphTally receipts into RAVs (Receipt Aggregate Vouchers) and reconciles redemptions. Exactly one instance should run per indexer. - **Indexer agent** - Facilitates the Indexers interactions onchain including registering on the network, managing Subgraph deployments to its Graph Node/s, and managing allocations. @@ -155,12 +157,12 @@ Note: To support agile scaling, it is recommended that query and indexing concer | 8030 | Subgraph indexing status API | /graphql | --index-node-port | - | | 8040 | Prometheus metrics | /metrics | --metrics-port | - | -#### Indexer Service +#### Indexer Service (`indexer-service-rs`) | Port | Purpose | Routes | CLI Argument | Environment Variable | | --- | --- | --- | --- | --- | -| 7600 | GraphQL HTTP server
(for paid Subgraph queries) | /subgraphs/id/...
/status
/channel-messages-inbox | --port | `INDEXER_SERVICE_PORT` | -| 7300 | Prometheus metrics | /metrics | --metrics-port | - | +| 7600 | GraphQL HTTP server
(for paid Subgraph queries) | /subgraphs/id/...
/status
/healthz
/cost
/info | --config | - | +| 7300 | Prometheus metrics | /metrics | - | - | #### Indexer Agent @@ -363,31 +365,29 @@ docker-compose up ### Indexer components -To successfully participate in the network requires almost constant monitoring and interaction, so we've built a suite of Typescript applications for facilitating an Indexers network participation. There are three Indexer components: +To successfully participate in the network requires almost constant monitoring and interaction, so we've built a suite of applications for facilitating an Indexers network participation. There are four Indexer components: - **Indexer agent** - The agent monitors the network and the Indexer's own infrastructure and manages which Subgraph deployments are indexed and allocated towards onchain and how much is allocated towards each. -- **Indexer service** - The only component that needs to be exposed externally, the service passes on Subgraph queries to the graph node, manages state channels for query payments, shares important decision making information to clients like the gateways. +- **[`indexer-service-rs`](https://github.com/graphprotocol/indexer-rs)** - The only component that needs to be exposed externally, the service passes on Subgraph queries to the graph node, validates [GraphTally](/indexing/tap) receipts, and shares important decision making information to clients like the gateways. + +- **[`indexer-tap-agent`](https://github.com/graphprotocol/indexer-rs)** - Aggregates GraphTally receipts into RAVs and manages receipt-to-payment lifecycle. Run exactly one instance per indexer. - **Indexer CLI** - The command line interface for managing the Indexer agent. It allows Indexers to manage cost models, manual allocations, actions queue, and indexing rules. #### Getting started -The Indexer agent and Indexer service should be co-located with your Graph Node infrastructure. There are many ways to set up virtual execution environments for your Indexer components; here we'll explain how to run them on baremetal using NPM packages or source, or via kubernetes and docker on the Google Cloud Kubernetes Engine. If these setup examples do not translate well to your infrastructure there will likely be a community guide to reference, come say hi on [Discord](https://discord.gg/graphprotocol)! Remember to [stake in the protocol](/indexing/overview/#stake-in-the-protocol) before starting up your Indexer components! +The Indexer agent, `indexer-service-rs`, and `indexer-tap-agent` should be co-located with your Graph Node infrastructure. There are many ways to set up virtual execution environments for your Indexer components; here we'll explain how to run them using docker or via kubernetes on the Google Cloud Kubernetes Engine. If these setup examples do not translate well to your infrastructure there will likely be a community guide to reference, come say hi on [Discord](https://discord.gg/graphprotocol)! Remember to [stake in the protocol](/indexing/overview/#stake-in-the-protocol) before starting up your Indexer components! -#### From NPM packages +#### Indexer agent (from NPM) ```sh -npm install -g @graphprotocol/indexer-service npm install -g @graphprotocol/indexer-agent # Indexer CLI is a plugin for Graph CLI, so both need to be installed: npm install -g @graphprotocol/graph-cli npm install -g @graphprotocol/indexer-cli -# Indexer service -graph-indexer-service start ... - # Indexer agent graph-indexer-agent start ... @@ -398,58 +398,28 @@ graph indexer connect http://localhost:18000/ graph indexer ... ``` -#### From source - -```sh -# From Repo root directory -yarn - -# Indexer Service -cd packages/indexer-service -./bin/graph-indexer-service start ... +#### `indexer-service-rs` and `indexer-tap-agent` (Docker) -# Indexer agent -cd packages/indexer-agent -./bin/graph-indexer-service start ... - -# Indexer CLI -cd packages/indexer-cli -./bin/graph-indexer-cli indexer connect http://localhost:18000/ -./bin/graph-indexer-cli indexer ... -``` - -#### Using docker - -- Pull images from the registry +The `indexer-service-rs` and `indexer-tap-agent` are Rust applications distributed as Docker images. See the [GraphTally guide](/indexing/tap) for detailed configuration. ```sh -docker pull ghcr.io/graphprotocol/indexer-service:latest -docker pull ghcr.io/graphprotocol/indexer-agent:latest +docker pull ghcr.io/graphprotocol/indexer-service-rs:latest +docker pull ghcr.io/graphprotocol/indexer-tap-agent:latest ``` -Or build images locally from source +Run both services with a shared TOML configuration file: ```sh -# Indexer service -docker build \ - --build-arg NPM_TOKEN= \ - -f Dockerfile.indexer-service \ - -t indexer-service:latest \ -# Indexer agent -docker build \ - --build-arg NPM_TOKEN= \ - -f Dockerfile.indexer-agent \ - -t indexer-agent:latest \ -``` - -- Run the components +# indexer-service-rs (horizontally scalable) +docker run -p 7600:7600 -v ./config.toml:/config.toml \ + ghcr.io/graphprotocol/indexer-service-rs:latest --config /config.toml -```sh -docker run -p 7600:7600 -it indexer-service:latest ... -docker run -p 18000:8000 -it indexer-agent:latest ... +# indexer-tap-agent (run exactly one instance) +docker run -v ./config.toml:/config.toml \ + ghcr.io/graphprotocol/indexer-tap-agent:latest --config /config.toml ``` -**NOTE**: After starting the containers, the Indexer service should be accessible at [http://localhost:7600](http://localhost:7600) and the Indexer agent should be exposing the Indexer management API at [http://localhost:18000/](http://localhost:18000/). +**NOTE**: After starting the containers, the indexer service should be accessible at [http://localhost:7600](http://localhost:7600) and the Indexer agent should be exposing the Indexer management API at [http://localhost:18000/](http://localhost:18000/). #### Using K8s and Terraform @@ -488,30 +458,16 @@ graph-indexer-agent start \ | pino-pretty ``` -#### Indexer service +#### `indexer-service-rs` and `indexer-tap-agent` + +Both `indexer-service-rs` and `indexer-tap-agent` are configured using a shared TOML file. See the [GraphTally guide](/indexing/tap) for detailed configuration and deployment instructions. ```sh -SERVER_HOST=localhost \ -SERVER_PORT=5432 \ -SERVER_DB_NAME=is_staging \ -SERVER_DB_USER= \ -SERVER_DB_PASSWORD= \ -graph-indexer-service start \ - --ethereum \ - --ethereum-network mainnet \ - --mnemonic \ - --indexer-address \ - --port 7600 \ - --metrics-port 7300 \ - --graph-node-query-endpoint http://localhost:8000/ \ - --graph-node-status-endpoint http://localhost:8030/graphql \ - --postgres-host localhost \ - --postgres-port 5432 \ - --postgres-username \ - --postgres-password \ - --postgres-database is_staging \ - --network-subgraph-endpoint http://query-node-0:8000/subgraphs/id/QmUzRg2HHMpbgf6Q4VHKNDbtBEJnyp5JWCh2gUX9AV6jXv \ - | pino-pretty +# Run indexer-service-rs +indexer-service-rs --config /path/to/config.toml + +# Run indexer-tap-agent (exactly one instance) +indexer-tap-agent --config /path/to/config.toml ``` #### Indexer CLI diff --git a/website/src/pages/en/indexing/tap.mdx b/website/src/pages/en/indexing/tap.mdx index 79113906e023..038910cbda82 100644 --- a/website/src/pages/en/indexing/tap.mdx +++ b/website/src/pages/en/indexing/tap.mdx @@ -44,16 +44,19 @@ RAV redemption is fully automated when running `indexer-tap-agent` and `indexer- - Reverted transactions are resubmitted - Confirmed transactions are marked `final` +### Allocation Reconciliation + +The tap-agent automatically reconciles RAV redemptions using the network subgraph. It queries `paymentsEscrowTransactions` to track which RAVs have been redeemed onchain and detects blockchain reorganizations that may revert redemption transactions. Reconciliation runs every 5 minutes by default (configurable via `tap.allocation_reconciliation_interval_secs`). + ## Blockchain Addresses ### Contracts -| Contract | Arbitrum Mainnet (42161) | Arbitrum Sepolia (421614) | -| ----------------- | -------------------------------------------- | -------------------------------------------- | -| TAP Verifier (V1) | `0x33f9E93266ce0E108fc85DdE2f71dab555A0F05a` | `0xfC24cE7a4428A6B89B52645243662A02BA734ECF` | -| TAP Verifier (V2) | `0x8f69F5C07477Ac46FBc491B1E6D91E2be0111A9e` | `0x382863e7B662027117449bd2c49285582bbBd21B` | -| Subgraph Service | `0xb2Bb92d0DE618878E438b55D5846cfecD9301105` | `0xc24A3dAC5d06d771f657A48B20cE1a671B78f26b` | -| TAP Escrow | `0x8f477709eF277d4A880801D01A140a9CF88bA0d3` | `0x1e4dC4f9F95E102635D8F7ED71c5CdbFa20e2d02` | +| Contract | Arbitrum Mainnet (42161) | Arbitrum Sepolia (421614) | +| ---------------- | -------------------------------------------- | -------------------------------------------- | +| TAP Verifier | `0x8f69F5C07477Ac46FBc491B1E6D91E2be0111A9e` | `0x382863e7B662027117449bd2c49285582bbBd21B` | +| Subgraph Service | `0xb2Bb92d0DE618878E438b55D5846cfecD9301105` | `0xc24A3dAC5d06d771f657A48B20cE1a671B78f26b` | +| TAP Escrow | `0x8f477709eF277d4A880801D01A140a9CF88bA0d3` | `0x1e4dC4f9F95E102635D8F7ED71c5CdbFa20e2d02` | ### Gateway @@ -68,8 +71,10 @@ RAV redemption is fully automated when running `indexer-tap-agent` and `indexer- ### Software Requirements - **indexer-agent**: [Latest version](https://github.com/graphprotocol/indexer/releases) -- **indexer-service-rs**: [Latest release](https://github.com/graphprotocol/indexer-rs/releases?q=indexer-service-rs) -- **indexer-tap-agent**: [Latest release](https://github.com/graphprotocol/indexer-rs/releases?q=indexer-tap-agent) +- **indexer-service-rs** v2.0.0+: [Latest release](https://github.com/graphprotocol/indexer-rs/releases?q=indexer-service-rs) +- **indexer-tap-agent** v2.0.0+: [Latest release](https://github.com/graphprotocol/indexer-rs/releases?q=indexer-tap-agent) + +> **Important**: Starting with v2.0.0, `indexer-service-rs` and `indexer-tap-agent` require Graph Horizon. Legacy V1 receipt support has been removed. Ensure you have the required Horizon contract addresses configured before upgrading. ### Docker Images @@ -83,7 +88,7 @@ docker pull ghcr.io/graphprotocol/indexer-tap-agent:latest Your indexer stack consists of: - **indexer-service-rs**: Handles incoming queries, validates receipts, routes to graph-node. Stateless and horizontally scalable. -- **indexer-tap-agent**: Aggregates receipts into RAVs. Run exactly **one instance**. +- **indexer-tap-agent**: Aggregates receipts into RAVs and reconciles redemptions. Run exactly **one instance**. - **indexer-agent**: Manages allocations and redeems RAVs onchain. All three components share the same PostgreSQL database. @@ -99,10 +104,12 @@ Both `indexer-service-rs` and `indexer-tap-agent` use a shared TOML configuratio indexer_address = "0x1111111111111111111111111111111111111111" operator_mnemonic = "your twelve word mnemonic phrase here ..." -# For key rotation, you can specify multiple mnemonics: +# For key rotation, you can specify multiple mnemonics. +# All configured mnemonics are tried when creating attestation signers, +# allowing allocations created with different operator keys to work. +# The first mnemonic is used as the primary identity on the /info endpoint. # operator_mnemonics = [ -# "current mnemonic phrase here", -# "previous mnemonic if you rotated keys" +# "previous mnemonic phrase here if you rotated keys" # ] [database] @@ -113,25 +120,20 @@ query_url = "http://graph-node:8000" status_url = "http://graph-node:8000/graphql" [subgraphs.network] -# The Graph Network Subgraph (includes escrow data with Graph Horizon) +# The Graph Network Subgraph (includes escrow data for Horizon) # Use query_url for hosted service, or deployment_id for local indexing (recommended) query_url = "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum" # deployment_id = "QmUVskWrz1ZiQZ76AtyhcfFDEH1ELnRpoyEhVL8p6NFTbR" -# Note: With Graph Horizon, escrow data is included in the Network Subgraph. -# The separate [subgraphs.escrow] config is only needed for legacy V1 receipt processing. - [blockchain] chain_id = 42161 -# V1 TAP Verifier (for legacy receipts during migration) -receipts_verifier_address = "0x33f9E93266ce0E108fc85DdE2f71dab555A0F05a" -# V2 Horizon TAP Verifier receipts_verifier_address_v2 = "0x8f69F5C07477Ac46FBc491B1E6D91E2be0111A9e" subgraph_service_address = "0xb2Bb92d0DE618878E438b55D5846cfecD9301105" +# Legacy V1 verifier (deprecated in v2.0.0, can be removed from your config): +# receipts_verifier_address = "0x33f9E93266ce0E108fc85DdE2f71dab555A0F05a" # For testnet: # chain_id = 421614 -# receipts_verifier_address = "0xfC24cE7a4428A6B89B52645243662A02BA734ECF" # receipts_verifier_address_v2 = "0x382863e7B662027117449bd2c49285582bbBd21B" # subgraph_service_address = "0xc24A3dAC5d06d771f657A48B20cE1a671B78f26b" @@ -150,6 +152,23 @@ max_amount_willing_to_lose_grt = "0.1" enabled = true ``` +#### Required Configuration Fields + +The following fields are required for operation: + +| Field | Section | Description | +| ------------------------------ | --------------------- | --------------------------------------------- | +| `indexer_address` | `[indexer]` | Your indexer's Ethereum address | +| `operator_mnemonic` | `[indexer]` | BIP-39 mnemonic for the operator wallet | +| `postgres_url` | `[database]` | PostgreSQL connection URL | +| `query_url` | `[graph_node]` | Graph Node query endpoint | +| `status_url` | `[graph_node]` | Graph Node status endpoint | +| `query_url` or `deployment_id` | `[subgraphs.network]` | Network subgraph endpoint | +| `chain_id` | `[blockchain]` | Network chain ID (42161 for Arbitrum Mainnet) | +| `receipts_verifier_address_v2` | `[blockchain]` | TAP Verifier contract address | +| `subgraph_service_address` | `[blockchain]` | SubgraphService contract address | +| `enabled = true` | `[horizon]` | Horizon mode (required) | + #### Environment Variable Overrides Override any configuration value using environment variables: @@ -167,6 +186,18 @@ export TAP_AGENT__TAP__MAX_AMOUNT_WILLING_TO_LOSE_GRT="0.5" - [Full configuration reference](https://github.com/graphprotocol/indexer-rs/blob/main/crates/config/maximal-config-example.toml) - [Default values](https://github.com/graphprotocol/indexer-rs/blob/main/crates/config/default_values.toml) +### Receipt Validation + +`indexer-service-rs` validates every incoming receipt before storing it. The following checks are performed: + +- **Allocation eligibility**: The receipt targets a valid, active allocation +- **Payer check**: The receipt's payer field matches a known sender +- **Data service check**: The receipt's `data_service` field matches the configured `subgraph_service_address` +- **Service provider check**: The receipt's `service_provider` matches the indexer's address +- **Sender balance check**: The sender has sufficient escrow balance +- **Value check**: The receipt value does not exceed `max_receipt_value_grt` +- **Timestamp check**: The receipt timestamp is within acceptable bounds + ### Logging Set the log level using the `RUST_LOG` environment variable: @@ -181,6 +212,33 @@ export RUST_LOG=indexer_service=debug,indexer_tap_agent=debug ## Monitoring +### Endpoints + +`indexer-service-rs` exposes the following HTTP endpoints: + +| Route | Method | Description | +| --------------------- | ------ | ------------------------------------------------------- | +| `/subgraphs/id/:id` | POST | Main query endpoint for paid queries | +| `/health/:deployment` | GET | Deployment health status from graph-node | +| `/healthz` | GET | Service dependency health check (database + graph-node) | +| `/status` | POST | Indexing status queries | +| `/cost` | GET | Cost model information | +| `/info` | GET | Operator address | + +The `/healthz` endpoint checks connectivity to the PostgreSQL database and graph-node, returning a JSON response: + +```json +{ + "status": "healthy", + "checks": { + "database": { "status": "healthy" }, + "graph_node": { "status": "healthy" } + } +} +``` + +Returns HTTP 200 when all checks pass, or HTTP 503 when any dependency is unhealthy. + ### Metrics All components expose Prometheus metrics on port 7300: @@ -223,117 +281,42 @@ Common issues and solutions: - Check if specific senders are having aggregation issues - Monitor the Grafana dashboard for aggregation patterns -## Horizon (TAP V2) Migration - -Horizon is the next-generation Graph protocol with updated smart contracts and a new receipt format (V2). This section covers how to enable Horizon support in your indexer stack. - -### Critical: Both Services Must Be Configured - -> **Warning**: `indexer-service-rs` and `indexer-tap-agent` have **separate configurations** and **both must have Horizon enabled** for V2 receipts to be processed correctly. -> -> A common misconfiguration is enabling Horizon only on `indexer-service` while leaving `tap-agent` in legacy mode. This results in: -> -> - `indexer-service` accepting V2 receipts and storing them in the database -> - `tap-agent` ignoring all Horizon allocations (showing 0 allocations tracked) -> - **No RAVs created, no redemptions possible** - -### Horizon Configuration Checklist - -#### Step 1: Obtain Horizon Contract Addresses - -You need two new addresses for Horizon (check [The Graph documentation](#blockchain-addresses) for current values): - -| Contract | Purpose | -| ------------------------------ | ----------------------------------------------------- | -| `receipts_verifier_address_v2` | TAP Verifier V2 contract for Horizon receipts | -| `subgraph_service_address` | Subgraph Service contract for allocation verification | - -#### Step 2: Update Configuration File - -Add the Horizon settings to your shared TOML configuration: - -```toml -[blockchain] -chain_id = 42161 -# Legacy V1 verifier (keep for existing receipts) -receipts_verifier_address = "0x33f9E93266ce0E108fc85DdE2f71dab555A0F05a" -# Horizon V2 addresses -receipts_verifier_address_v2 = "0x..." # Get from The Graph docs -subgraph_service_address = "0x..." # Get from The Graph docs - -[horizon] -enabled = true -``` +4. **Service startup fails with missing configuration**: + - Ensure `horizon.enabled = true` is set + - Verify both `receipts_verifier_address_v2` and `subgraph_service_address` are configured + - Check that the network subgraph is accessible -#### Step 3: Configure Environment Variables (if not using config file) +## Upgrading to v2.0.0 -If you use environment variables, you must set them for **both services**: +Version 2.0.0 of `indexer-service-rs` and `indexer-tap-agent` removes support for legacy V1 receipts. All receipt processing now uses Graph Horizon (GraphTally) exclusively. -```bash -# For indexer-service -export INDEXER_SERVICE__HORIZON__ENABLED=true -export INDEXER_SERVICE__BLOCKCHAIN__RECEIPTS_VERIFIER_ADDRESS_V2="0x..." -export INDEXER_SERVICE__BLOCKCHAIN__SUBGRAPH_SERVICE_ADDRESS="0x..." - -# For tap-agent (REQUIRED - don't forget this!) -export TAP_AGENT__HORIZON__ENABLED=true -export TAP_AGENT__BLOCKCHAIN__RECEIPTS_VERIFIER_ADDRESS_V2="0x..." -export TAP_AGENT__BLOCKCHAIN__SUBGRAPH_SERVICE_ADDRESS="0x..." -``` +### What Changed -#### Step 4: Verify Configuration +- **Horizon is required**: The `[horizon].enabled` field must be set to `true`. Configs with `enabled = false` are rejected at startup. +- **V1 receipt handling removed**: The system no longer processes legacy V1 receipts or queries the escrow subgraph for V2 operations. +- **`receipts_verifier_address` (V1) is deprecated**: This field is now optional and unused. You can remove it from your config. +- **`receipts_verifier_address_v2` is required**: This must be set to the Horizon TAP Verifier contract address. +- **`subgraph_service_address` is required**: This must be set to the SubgraphService contract address. +- **Escrow data from network subgraph**: V2 escrow accounts are read from the network subgraph, not a separate escrow subgraph. -After restarting both services, check the logs to confirm Horizon is active: +### Migration Checklist -**indexer-service logs (expected):** +1. **Update your configuration**: + - Add `receipts_verifier_address_v2` and `subgraph_service_address` under `[blockchain]` if not already present + - Ensure `[horizon].enabled = true` + - You can remove `receipts_verifier_address` (the old V1 verifier) from your config + - The `[subgraphs.escrow]` section can be removed unless you serve the escrow subgraph proxy via `serve_escrow_subgraph = true` in the `[service]` section (most indexers do not need this) -``` -INFO indexer_service_rs::service: Horizon mode configured - checking if Horizon contracts are active -INFO indexer_service_rs::service: Horizon contracts detected - using Horizon migration mode -``` - -**tap-agent logs (expected):** - -``` -INFO indexer_tap_agent::agent: Horizon mode configured - checking if Horizon contracts are active -INFO indexer_tap_agent::agent::sender_accounts_manager: horizon_active: true -``` +2. **Ensure all V1 RAVs are redeemed**: Before upgrading, confirm that all pending V1 RAVs have been redeemed onchain. The new version cannot process V1 receipts. -**tap-agent logs (PROBLEM - Horizon not enabled):** +3. **Update Docker images**: -``` -INFO indexer_tap_agent::agent: Horizon not configured - using pure legacy mode -INFO indexer_tap_agent::agent::sender_accounts_manager: horizon_active: false -``` - -If you see "pure legacy mode" in tap-agent but have Horizon allocations, your receipts will not be processed! - -### Horizon Migration Modes - -When Horizon is enabled and contracts are detected: - -- **Hybrid Migration Mode**: The system accepts new V2 receipts while continuing to process existing V1 receipts -- **V2 Receipts Only**: New queries generate V2 receipts (stored in `scalar_tap_receipts_v2` table) -- **Legacy Processing**: Existing V1 receipts continue to be aggregated until allocations close - -### Troubleshooting Horizon - -1. **TAP agent shows 0 allocations but you have Horizon allocations**: - - Check that `TAP_AGENT__HORIZON__ENABLED=true` is set - - Verify `subgraph_service_address` is configured for tap-agent - - Look for "pure legacy mode" in tap-agent logs - -2. **"mismatched" allocations in tap-agent logs**: - - ``` - total: 788, legacy: 0, horizon: 788, mismatched: 788, normalized: 0 + ```bash + docker pull ghcr.io/graphprotocol/indexer-service-rs:latest + docker pull ghcr.io/graphprotocol/indexer-tap-agent:latest ``` - This indicates tap-agent is in legacy mode but all your allocations are Horizon. Enable Horizon on tap-agent. - -3. **Receipts stored but not aggregated**: - - Confirm both services have matching `receipts_verifier_address_v2` values - - Check that `subgraph_service_address` matches between services +4. **Restart both services** with the updated configuration. ## Deployment Options