Race to the Blocks: Benchmarking Blockchain Indexer Sync Speeds
Introduction
This blog article presents the findings from benchmarking tests conducted at Envio to assess the syncing performance of various web3 indexing solutions. At Envio, our goal is to develop a high-performance blockchain indexing solution, and we believe that validating this goal through a rigorous data-driven approach is essential. Sync speed simply put, is how long it takes for an indexer to catch up to the head of the blockchain using a historical block as a starting point.
Why is indexing speed important?
Indexing speed is important because it inherently creates a friction to deploy, debug and iterate on newer versions of the indexer. The longer the total sync time, the longer it takes to innovate and resolve issues on existing deployments.
In summary, we indexed the Uniswap V3 ETH-USDC pool contract on Ethereum Mainnet, starting from its deployment block. This specific smart contract was chosen due to its high event density, providing an ideal testbed for evaluating indexing performance in a high event-density context.
You can review the smart contract on Etherscan.
Methodology
To ensure that the sync speeds from different indexers were as comparable as possible, we ensured that the configurations of all indexers for different solutions were identical. This included:
- Indexing from the same start block for all indexers (12,376,729 - the deployment block for the contract) until the end block at the time of experimentation (18,342,024), with an approximate total of 5,395,050 raw events indexed (0.9044 events per block).
- Employing the same schema (outlined below).
- Specifying identical event handling logic (explained further).
Schema screenshot
The schema used for all indexers during benchmarking was defined as follows:
type Swap {
id: Bytes!
sender: Bytes! # address
recipient: Bytes! # address
amount0: BigInt! # int256
amount1: BigInt! # int256
sqrtPriceX96: BigInt! # uint160
liquidity: BigInt! # uint128
tick: Int! # int24
blockNumber: BigInt!
blockTimestamp: BigInt!
transactionHash: Bytes!
}
Event handler logic
For this initial iteration, the event handling logic was kept straightforward and lightweight. Indexers would listen to the Swap
event emitted by the smart contract and append the details of each swap to the Swap
entity table defined in the schema.
Indexers Used
We employed 6 separate indexer solutions for this benchmarking test:
- Envio
- v0.0.20
- v0.0.19
- Subsquid
- Subgraph on theGraph hosted solution
- Ponder
- Subtreams-powered Subgraph on theGraph hosted solution
Benchmark Repositories
To ensure transparency and reproducibility, we've made the code for each indexer implementation publicly available:
- Envio: uniV3-swaps
- Ponder: univ3-ponder
- Subsquid: univ3-sqd
- Subtreams-powered Subgraph: univ3-substreams
We encourage the community to review, test, and provide feedback on these implementations. These benchmarks are also somewhat old now [edit 10 months later], we will be updating them soon with the latest versions of each indexer and on a more complicated scenario.