Project Structure
The Chainbench codebase is organized into several key modules:Core Components
User Classes
Chainbench uses Locust’s User concept to simulate blockchain clients making RPC requests. The user class hierarchy provides protocol-specific implementations:Base User Classes
Base User Classes
- HttpUser: Base class for HTTP-based interactions
- JrpcHttpUser: Extends HttpUser with JSON-RPC support
- Handles JSON-RPC request/response formatting
- Validates JSON-RPC responses
- Supports batch requests
- Manages error code exclusions
Protocol-Specific Users
Protocol-Specific Users
- EvmUser: EVM-compatible chains (Ethereum, BSC, Polygon, etc.)
- Implements all standard Ethereum JSON-RPC methods
- Supports debug and trace methods (tagged)
- Includes ERC-20 token interactions
- SolanaUser: Solana blockchain
- Implements Solana JSON-RPC methods
- Handles Solana-specific data structures
- EthBeaconUser: Ethereum Consensus Layer (Beacon Chain)
- Implements Beacon Chain API methods
- StarkNetUser: StarkNet L2
- Implements StarkNet-specific methods
User Class Methods
Each user class defines methods that correspond to RPC calls. Methods are organized into two types:- RPC Call Methods: Return
RpcCallobjects (e.g.,eth_block_number()) - Task Methods: Execute the RPC calls (e.g.,
eth_block_number_task())
Test Data System
The test data system is one of Chainbench’s key features, enabling realistic load testing with actual blockchain data.Data Collection
Data Collection
Test data is collected before benchmarks begin:
- Fetches blocks from the target node (or a reference node)
- Extracts transactions, accounts, and hashes
- Stores data in memory for fast random access
- Supports different data sizes (XS, S, M, L, XL)
Data Structures
Data Structures
BlockchainData: Generic container for blockchain data
- Stores blocks, block numbers, and block range
- Manages data size limits
- Provides JSON serialization
- EvmBlock: Contains transactions, accounts, hashes
- SolanaBlock: Solana-specific block data
- StarkNetBlock: StarkNet-specific block data
Data Sizes
Data Sizes
Chainbench supports different data collection sizes:
Specify size with the
| Size | Blocks Collected |
|---|---|
| XS | 10 blocks |
| S | 100 blocks |
| M | 1,000 blocks |
| L | 10,000 blocks |
| XL | 100,000 blocks |
--size flag:Test Data Features
For development, always start with
--size XS to minimize initialization time and memory usage.- Custom range:
--start-blockand--end-block - Latest blocks:
--use-latest-blocks(useful for nodes with limited history) - Network defaults: Each network has a default starting block
get_random_block(): Returns a random block from collected dataget_random_tx_hash(): Returns a random transaction hashget_random_account(): Returns a random account addressget_random_block_number(): Returns a random block number
--ref-url to collect test data from a different node than the target:
Load Profiles
Profiles define which RPC methods to test and their relative weights. They are Python files that specify a user class with weighted RPC calls.Profile Structure
Profile Components
Profile Components
- wait_time: Locust wait time function (controls pacing)
- rpc_calls: Dictionary mapping methods to weights
- tasks: Expanded task list for Locust
- Higher weights = more frequent execution
Built-in Profiles
Built-in Profiles
Chainbench includes several pre-built profiles:Generic EVM:
evm.light: Common read operationsevm.heavy: Complex and expensive operationsevm.get_logs: Focused on log queriesevm.debug_trace: Debug and trace methodsevm.all: All available methods
ethereum.general: Ethereum mainnet focusethereum.consensus: Beacon chain methodssolana.general: Solana-specific operations- And many more for BSC, Polygon, Arbitrum, etc.
Creating Custom Profiles
When creating custom profiles:- Place them in
chainbench/profile/<network>/ - Follow existing profile structure
- Include docstrings explaining the profile purpose
- Test with
--size XSfirst - Validate against multiple node types when applicable
Locust Integration
Chainbench leverages Locust’s distributed load testing capabilities:Master-Worker Architecture
- 1 master process (coordinates testing and aggregates results)
- 8 worker processes (execute the actual load testing)
- 100 virtual users (distributed across workers)
How It Works
How It Works
- Master Process: Spawned first, coordinates workers
- Worker Processes: Connect to master, execute tasks
- User Distribution: Users evenly distributed across workers
- Result Aggregation: Master collects and aggregates metrics
- Monitors: Optional monitoring processes run in parallel
Task Tagging System
Chainbench uses Locust’s tagging to categorize methods:--debug-trace-methods: Enable debug/trace tagged methods--exclude-tags: Exclude specific tags- Default: debug and trace methods are excluded
debug: Debug namespace methodstrace: Trace namespace methodssingle: Single method testing modebatch: Batch request modebatch_single: Batch requests of same method
Batch Requests
Chainbench supports JSON-RPC batch requests for improved efficiency:Batch Request Modes
Batch Request Modes
- Regular batch (
--batch): Random mix of weighted methods - Single method batch (
--batchwith method): Same method repeated - Batch size (
--batch-size): Number of requests per batch (default: 10)
Load Shapes
Load shapes control how users are spawned over time:- step: Gradually increase load in steps
- spike: Sudden spike in traffic
chainbench/shapes/ and use Locust’s LoadTestShape class.
Method Discovery
The discovery tool tests which RPC methods are available on a node:- Which methods are implemented
- Which methods return errors
- Node client compatibility
Extension Points
To extend Chainbench:- New Protocol: Create a new user class in
user/protocol/ - New Test Data: Extend
TestDataintest_data/ - New Profile: Add profile file to
profile/ - New Shape: Add shape class to
shapes/ - New Monitor: Add monitor function to
util/monitor.py
All extensions should follow existing patterns and maintain compatibility with Locust’s architecture.