L2 Support for Indexer Agent
Adds the capacity for the Agent to interact with multiple protocol networks (blockchains that host The Graph Protocol) by running a single instance of the indexer-agent
program.
Table of Contents
- Multi-Network Mode
- Example Network Specification Files
- Goerli
- Arbitrum Goerli
- API Changes
- GraphQL API Changes
- Indexer CLI command changes
- The
/network
endpoint
- Database Migrations
- Cost Model feature restrictions in multi-network context:
- Example Network Specification Files
- Automatic Allocation Transfer to L2
Multi-Network Mode
Multinetwork Mode can be enabled by setting the environment variable INDEXER_AGENT_MULTINETWORK_MODE
to "true"
.
While in multinetwork mode, the Indexer Agent will perform all of its usual routines, but for each
specified network.
In that mode, each protocol network is represented by one YAML file under the same directory, which can
be decalred in the command line argument --network-specifications-directory
, which must be a path
the Indexer Agent can access during its startup.
Example Network Specification Files
Goerli
This example network specification YAML file represents all possible configuration fields and their
default values.
networkIdentifier: goerli # could also be named "eipp155:5"
gateway:
url: https://gateway.testnet.thegraph.com
indexerOptions:
address: "0x391042eC4ae8ab799Efdfd82021d059a19c6ED86"
mnemonic: "aunt what review ordinary initial rocket wheel enter private chef tree surface"
url: http://localhost:7600
allocationManagementMode: auto
restakeRewards: true
rebateClaimThreshold: 200
rebateClaimBatchThreshold: 200
rebateClaimMaxBatchSize: 100
poiDisputeMonitoring: false
poiDisputableEpochs: 1
defaultAllocationAmount: 0.1
voucherRedemptionThreshold: 200
voucherRedemptionBatchThreshold: 2000
voucherRedemptionMaxBatchSize: 100
autoAllocationMinBatchSize: 1
allocateOnNetworkSubgraph: false
register: true
transactionMonitoring:
gasPriceMax: 100
gasIncreaseTimeout: 240 # in seconds
gasIncreaseFactor: 1.2
gasPriceMax: 100 # in gwei
baseFeePerGasMax: 100 # in gwei
maxTransactionAttempts: 0 # zero retries indefinitely
subgraphs:
networkSubgraph:
url: https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-goerli
deployment: QmRFMZT2rmdo558S8GWPNYJ61qchSUTEMHirYnm4MRqHEP
epochSubgraph:
url: https://api.thegraph.com/subgraphs/name/graphprotocol/goerli-epoch-block-oracle
networkProvider:
url: "<insert the URL of your Goerli JSON-RPC provider here>"
dai:
# Mind that the cost model feature is only enabled for Ethereum Mainnet (see notes below)
contractAddress: "0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844"
inject: true
Arbitrum Goerli
In turn, this YAML network specification file represents just the required fields.
networkIdentifier: arbitrum-goerli # could also be named "eipp155:421613"
gateway:
url: https://gateway-testnet-arbitrum.network.thegraph.com
indexerOptions:
address: "0x79EB6E112a00A4b99B8ABf0B983159d54A8be316"
mnemonic: "juice zebra sister column fit praise behind trust merit slab place general"
url: http://localhost:7600
allocationManagementMode: oversight
subgraphs:
networkSubgraph:
url: https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum-goerli
deployment: QmW8YxdkQjFb7wHMDo9u4DodLga4YHdByfKsBxCCcUx6cQ
epochSubgraph:
url: https://api.thegraph.com/subgraphs/name/graphprotocol/arb-goerli-epoch-block-oracle
networkProvider:
url: "<insert the URL of your Goerli JSON-RPC provider here>"
API Changes
The Indexer Agent GraphQL API was updated to accept (and in some cases require) a protocolNetwork
parameter to determine which network should be used for queries or mutations.
Likewise,the Indexer CLI was updated to accept the --network
option as the context for most of its
commands.
GraphQL API Changes
# --------------------------------------------------------------------------------
# * inputs
# --------------------------------------------------------------------------------
input AllocationFilter {
protocolNetwork: String # new optional filtering parameter
}
input ActionInput {
protocolNetwork: String! # new required parameter
}
input ActionFilter {
protocolNetwork: String # new optional filtering parameter
}
# New dedicated identifier type
input POIDisputeIdentifier {
allocationID: String!
protocolNetwork: String!
}
input POIDisputeInput {
protocolNetwork: String! # new required parameter
}
input IndexingRuleInput {
protocolNetwork: String! # new required parameter
}
# New dedicated identifier type
input IndexingRuleIdentifier {
identifier: String!
protocolNetwork: String!
}
# --------------------------------------------------------------------------------
# * types
# --------------------------------------------------------------------------------
type Allocation {
protocolNetwork: String! # new non-nullable field
}
type CreateAllocationResult {
protocolNetwork: String! # new non-nullable field
}
type CloseAllocationResult {
protocolNetwork: String! # new non-nullable field
}
type ReallocateAllocationResult {
protocolNetwork: String! # new non-nullable field
}
type Action {
protocolNetwork: String! # new non-nullable field
}
type ActionResult {
protocolNetwork: String! # new non-nullable field
}
type POIDispute {
protocolNetwork: String! # new non-nullable field
}
type IndexingRule {
protocolNetwork: String! # new non-nullable field
}
type IndexerRegistration {
protocolNetwork: String # new non-nullable field
}
type IndexerEndpoint {
protocolNetwork: String! # new optional filtering parameter
}
#--------------------------------------------------------------------------------
# * enums
# --------------------------------------------------------------------------------
enum ActionParams {
protocolNetwork # new enum variant
}
# --------------------------------------------------------------------------------
# * queries
# --------------------------------------------------------------------------------
type Query {
indexingRule(
identifier: IndexingRuleIdentifier! # parameter type changed from String!
): IndexingRule
indexingRules(
protocolNetwork: String # new optional filtering parameter
): [IndexingRule!]!
indexerRegistration(
protocolNetwork: String! # new required parameter
): IndexerRegistration!
indexerAllocations(
protocolNetwork: String! # new required parameter
): [IndexerAllocation]!
indexerEndpoints(
protocolNetwork: String! # new required parameter
): [IndexerEndpoints!]!
dispute(
identifier: POIDisputeIdentifier! # parameter type changed from String!
): POIDispute
disputes(
protocolNetwork: String # new optional filtering parameter
): [POIDispute]!
disputesClosedAfter(
protocolNetwork: String # new optional filtering parameter
): [POIDispute]!
}
# --------------------------------------------------------------------------------
# * mutations
# --------------------------------------------------------------------------------
type Mutation {
deleteIndexingRule(
identifier: IndexingRuleIdentifier! # parameter type changed from String!
): Boolean!
deleteIndexingRules(
identifiers: [IndexingRuleIdentifier!]! # parameter changed from [String!]!
): Boolean!
deleteDisputes(
identifiers: [POIDisputeIdentifier!]! # parameter changed from [String!]!
): Int!
createAllocation(
protocolNetwork: String # new required parameter
): CreateAllocationResult!
closeAllocation(
protocolNetwork: String! # new required parameter
): CloseAllocationResult!
reallocateAllocation(
protocolNetwork: String! # new required parameter
): ReallocateAllocationResult!
}
Indexer CLI command changes
Most indexer-cli
commands now accept or require a network
argument, to bring the protocol network
into the command's context
-
Commands that now accept the
--network
option to filter its results- indexer actions get
- indexer allocations get
- indexer disputes get
- indexer rules get
-
Commands that now require the
--network
option- indexer actions queue
- indexer rules clear
- indexer rules delete
- indexer rules maybe
- indexer rules offchain
- indexer rules set
- indexer rules start
- indexer rules stop
- indexer status
-
Commands that now require a
network
positional argument- indexer allocations close
- indexer allocations create
- indexer allocations reallocate
The /network
endopoint
The /network
endpoint exposed by the Agent now requires an additional path segment to disambiguate
which protocol network it should target.
Assuming the Agent is configured with those networks, all the paths below are valid:
/network/mainnet
/network/eip155:1
/network/arbitrum-one
/network/eip155:42161
/network/goerli
/network/eip155:5
/network/arbitrum-goerli
/network/eip155:421613
Database Migrations
A new database migration will create a new protocolNetwork
colum in the following tables
Actions
IndexingRules
POIDisputes
allocation_receipts
allocation_summaries
transfer_receipts
transfers
vouchers
This will let the Indexer Agent contextualize the target protocol network when operating on these
elements.
To ensure correctness, this migration requires that the Agent starts with only one configured
protocol network or an empty database. In the first case, the migration will assign the single
configured protocol network to all existing data in the tables listed above. After this migration
runs successfully, the Indexer Agent can be started with multiple configured protocol networks.
Put simply: to migrate your database to the new Agent version, just run it using the same configuration
you have been using for the previous version.
Keep in mind that it is very important to back up your Indexer Agent database before running any
migrations. This can be achieved with pg_dump
:
$ pg_dump -U "$USERNAME" -h $"HOST" -p $"PORT" -Fc $"DB_NAME" > db.dump
Please refer to the pg_dump
command manual for more instructions.
Cost Model feature restrictions in multi-network context:
The Cost Model feature can only be enabled for Ethereum Mainnet.
If other networks specify the DAI option group in their specification files, it will be ignored.
Automatic Allocation Transfer to L2
The Agent can be configured to automatically support subgraph transfers from L1 to L2. To enable
this feature, set the enable-auto-migration-support
startup option to true
.
If enabled, the Agent will inspect if any synced and healthy subgraph deployments have been
transferred from L1 (Ethereum) to L2 (Arbitrum One) in the past seven days. If so, the Agent will:
- Queue an
allocate
Action towards the subgraph deployment on L1, during one week. - If the transfer has been completed, queue an
allocate
Action towards the subgraph
deployment on L2, during one week, using the default amount.
Note that the Agent will not automatically close allocations on L1 after a subgraph has been transfered.