ETHEREUM_POLLING_INTERVAL, default 1000 ms).
Common setups:
- Contracts you deploy on the Virtual Environment (development, CI): follow the setup below.
- Staging or demo environments with production history: index a contract that already exists on the parent network.
- Parent-network activity after the fork: use Network Mirror Mode.
- A subgraph on a public network: run Graph Node on Tenderly Node RPC.
DemoToken, a minimal ERC-20 that emits Transfer(address indexed from, address indexed to, uint256 value), deployed on a Virtual Environment forked from Ethereum mainnet.
Before you begin
- Node.js 20.18.1 or later (required by Graph CLI) and npm
- Docker with Docker Compose
- A Virtual Environment and its Public RPC URL, listed in the Integrate Virtual RPC card on the Virtual Environment’s Home tab (see the dashboard reference)
- A contract deployed on the Virtual Environment (see Deploy and verify contracts), with:
- its address
- its ABI as a JSON file
- the block number of its deployment transaction:
Set up Graph Node and the subgraph
1
Install the Graph CLI
2
Scaffold the subgraph from your contract
graph init creates the demo-token directory with subgraph.yaml, schema.graphql, an event mapping in src/demo-token.ts, and a docker-compose.yml that runs Graph Node, IPFS, and Postgres.In subgraph.yaml, change indexerHints.prune from auto to never. Graph Node needs the full entity history to roll back reverted blocks.subgraph.yaml
3
Point Graph Node at the Virtual Environment
In the generated Leave the
docker-compose.yml, edit the environment of the graph-node service:- Set
ethereumto<network>:<Public RPC URL>. The network name before the first colon must matchnetworkinsubgraph.yaml. - Add
ETHEREUM_REORG_THRESHOLD: "1"so Graph Node can roll back reverted blocks. - Add
GRAPH_NODE_GENESIS_VALIDATION_ENABLED: "true"so Graph Node refuses an RPC URL from a different Virtual Environment instead of stalling.
docker-compose.yml (graph-node service)
ipfs and postgres services as generated. Graph Node only reads chain data, so use the Public RPC rather than the Admin RPC.4
Start Graph Node
Starting GraphQL HTTP server at: http://localhost:8000.5
Create and deploy the subgraph
graph deploy builds the subgraph, uploads it to IPFS, and prints the query URL:package.json runs the same commands as npm run create-local and npm run deploy-local. Run graph codegen again after you edit schema.graphql or the ABI.6
Query the subgraph
Check indexing status
Query the indexing status API on port8030:
latestBlock is the last block the subgraph processed and chainHeadBlock is the Virtual Environment’s latest block. Compare the two instead of relying on health. In every failure case on this page, the subgraph keeps reporting healthy while latestBlock stops advancing.
To see the requests Graph Node sends, open the JSON-RPC Calls tab of the Virtual Environment. Set the Status filter to Failed to find methods the Virtual Environment rejects, such as trace_filter from call handlers. Expand a row to see the request parameters and the error response.
Run the subgraph with gnd instead of Docker
gnd (Graph Node Dev) runs Graph Node as a native binary, needs no local IPFS node, and deploys the subgraph from its build directory without graph create or graph deploy. It stores entities in Postgres; the postgres service from the generated docker-compose.yml works.
graph node install installs gnd to ~/.local/bin; add that directory to your PATH. gnd dev serves the subgraph at http://localhost:8000/subgraphs/name/subgraph-0. Add --watch to redeploy whenever the build directory changes.
How does Graph Node handle a Virtual Environment revert?
Graph Node treats a revert as a chain reorganization. Once the Virtual Environment’s latest block number passes the last block the subgraph indexed, Graph Node rolls back the entities from the removed blocks and indexes the replacement blocks. Until then, Graph Node ignores the shorter chain (the log showsProvider went backwards - ignoring this latest block) and keeps serving entities from the reverted blocks. After a revert from the dashboard or with evm_revert (see Revert Virtual Environment state), mine past the old latest block: send transactions, click Mine in the dashboard, or call evm_mine over the Admin RPC.
The rollback depends on the two settings from the setup:
Index a contract that already exists on the parent network
To include a contract’s history from before the fork, setstartBlock to a block before the fork block. Graph Node reads those blocks from the parent network through the Virtual Environment RPC, then continues with the Virtual Environment’s blocks, so the subgraph contains both the parent network’s events and the events from your Virtual Environment transactions.
Graph Node scans every block from startBlock onward through the RPC and sizes each eth_getLogs range to the contract’s event density, so a busy contract is scanned a few blocks per request. Backfilling 1,000 blocks of USDC history (about 97,000 Transfer events) took about 7 minutes with the Docker setup on this page. Keep startBlock close to the fork block unless you need the full history.
Contract calls in mappings (ethereum.call, for example Token.bind(address).balanceOf(holder)) work on both sides of the fork. Graph Node sends eth_call at the event’s block hash, and the Virtual Environment answers calls for pre-fork blocks with the parent network’s state.
Admin RPC cheatcodes that write state directly, such as tenderly_setBalance and tenderly_setErc20Balance, emit no events, so event handlers don’t record them. To fund wallets with ERC-20 tokens in a way the subgraph records, use tenderly_addErc20Balance, which emits a synthetic Transfer event for each funded wallet. Graph Node indexes it like any other Transfer.
Which Virtual Environment modes index parent-network events?
Only Network Mirror Mode adds the parent network’s new blocks, with their logs, to a Virtual Environment. In the other modes, a subgraph sees only the events from your own transactions after the fork.Switch to a different Virtual Environment
Reset Graph Node’s data before you point it at another Virtual Environment. Graph Node stores indexed blocks per network name and, by default, doesn’t check whether the RPC behind that name changed. With the old database, the subgraph points at blocks that the new Virtual Environment doesn’t have. Graph Node retriesEthereum node did not find block <hash> and keeps serving the old entities while reporting synced: true.
ethereum in docker-compose.yml and the contract address and startBlock in subgraph.yaml, and run docker compose up -d, graph create, and graph deploy again. Keep network set to the parent network’s name (mainnet, not a custom name like virtual_mainnet), so the same subgraph.yaml works against any Virtual Environment forked from that network and against the network itself.
With GRAPH_NODE_GENESIS_VALIDATION_ENABLED: "true", Graph Node detects the switch when the two Virtual Environments have different chain IDs and refuses the new RPC with Genesis hash validation failed on provider 'mainnet-rpc-0': net version mismatch on chain 'mainnet'; expected '73574', found '73575'. Virtual Environments forked from the same network share its genesis hash, so a switch between two with the same chain ID passes validation.
Index with event handlers
Index the events your contract emits witheventHandlers. Call handlers (callHandlers) and block handlers with a call filter read traces through the trace_filter RPC method, which Virtual Environment RPCs don’t serve. A subgraph that uses them stays at startBlock - 1, and Graph Node logs Trying again after trace_filter RPC call ... failed with Access forbidden by access rules, try Admin RPC URL from the Public RPC or not supported from the Admin RPC. On public networks, call handlers work with Graph Node on Node RPC.
Troubleshooting
Related
- Deploy and verify contracts on a Virtual Environment
- Revert Virtual Environment state with snapshots or the dashboard
- Network Mirror Mode and State Sync
- Graph Node on Tenderly Node RPC for subgraphs on public networks
- Admin RPC reference for
evm_snapshot,evm_revert, and balance cheatcodes