# Benchmark Reproduction Guide

### Overview

* **Goal**: Continuously stress Gravity's RPC endpoints and measure throughput (TPS) and latency.
* **Repository**: `https://github.com/Galxe/gravity_bench`
* **What the tool does**:
  * Deploys the required ERC20 contracts.
  * Prepares a large pool of accounts/addresses.
  * Concurrently sends transactions to one or more RPC endpoints.

### Prerequisites

1. **A `gravity_node` binary built in release mode** — benchmark results are only meaningful when the node is compiled with optimizations. Refer to [gravity-sdk/readme.md](https://github.com/Galxe/gravity-sdk/blob/main/readme.md) for full build instructions. The recommended command is:

   ```bash
   make BINARY=gravity_node MODE=quick-release
   ```
2. **A running Gravity EVM cluster** (refer to: [Validator Cluster Deployment Guide](https://docs.gravity.xyz/developer-resources/cluster-deployment)):
   * Code release: <https://github.com/Galxe/gravity-sdk/releases/tag/gravity-testnet-v1.0.0>
     * Note: example cluster configurations are available at: <https://github.com/Galxe/gravity-sdk/tree/main/cluster/example>
   * `chain_id`: `1337 (example)`
   * `nodes1`: `http://127.0.0.1:8545 (example Validator1)`
   * `nodes2`: `http://127.0.0.1:8546 (example Validator2)`
   * `nodes3`: `http://127.0.0.1:8547 (example Validator3)`
3. **A funded EOA** for use as **faucet + deployer**:

   * You must provide this account's private key in the config file.
   * The account needs sufficient native token balance to:
     * Fund a large number of test accounts (directly or via cascading faucet mode).
     * Pay gas for contract deployment.

   A test faucet account is pre-funded in genesis.toml, with private key\
   `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80`,\
   corresponding to address `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266`.\
   The following configuration must be present in genesis.toml to give this address a balance:

   ```toml
   [genesis.faucet]
   address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
   private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
   balance = "1000000000000000000000000"   # 1M ETH
   ```

### System Dependencies (Ubuntu)

Install all required build and runtime packages in one step:

```bash
sudo apt update && sudo apt install -y \
  build-essential clang pkg-config libssl-dev git curl \
  libudev-dev libusb-1.0-0-dev \
  python3 python-is-python3 python3-pip python3-venv \
  nodejs npm
```

> `python-is-python3` creates the `python` command alias required by gravity\_bench's internal scripts. `libudev-dev` / `libusb-1.0-0-dev` prevent common build errors when compiling `hidapi`.

### Environment Setup

1. **Clone the repository**

   ```bash
   git clone https://github.com/Galxe/gravity_bench.git
   cd gravity_bench
   ```
2. **Run the initialization script**

The script will:

* Check and install missing tools (Rust, Node.js, Python)
* Create a Python virtual environment
* Install Python and Node dependencies
* Clone the contract repositories required for benchmarking

**Recommended (keep the environment active in the current shell):**

```bash
source setup.sh
```

> ⚠️ On Ubuntu, if you see `Failed to create Python virtual environment`, first run:
>
> ```bash
> sudo apt install python3-venv
> ```
>
> Then re-run `source setup.sh`.

**Alternative (requires manual environment activation):**

```bash
bash setup.sh
# Then manually activate the environment:
source venv/bin/activate
source ~/.cargo/env  # only needed if the script installed Rust
```

### Configuration

1. **Create a local config file**

   ```bash
   cp bench_config.template bench_config.toml
   ```
2. **Edit `bench_config.toml`**

Key fields to review:

* `nodes`: one or more RPC endpoints
* `target_tps`: target benchmark TPS; recommended not to exceed 9k on a 3-node cluster
* `[faucet].private_key`: **private key of the funded faucet/deployer account**
* `[accounts].num_accounts`: number of benchmark accounts; 100k recommended
* `[performance]`: concurrency and pool configuration

**Configuration constraints** — violating these will cause an assertion failure on startup:

* `accounts.num_accounts` ≥ `target_tps`
* `performance.num_senders` ≤ `accounts.num_accounts`

Example (abbreviated):

```toml
# Gravity Bench Configuration File

# Uniswap configuration file path (generated by deployment)
contract_config_path = "deploy.json"

# Target sending rate
target_tps = 9000

# RPC endpoints, replace with your chain_id and addresses
nodes = [
    { rpc_url = "http://127.0.0.1:8545", chain_id = 1337 },
    { rpc_url = "http://127.0.0.1:8546", chain_id = 1337 },
    { rpc_url = "http://127.0.0.1:8547", chain_id = 1337 },
]

num_tokens = 1
enable_swap_token = false

# Address pool type: "random" (default) or "weighted" (hot/normal/long-tail distribution)
address_pool_type = "random"

[faucet]
# Private key (replace with your real key)
private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"

# Faucet Level:
# - 10 enables cascade mode: 1 -> 10 -> 100 (amplification chain)
# - 0 disables cascading
faucet_level = 10

# Wait between faucet distribution levels (increase if you see insufficient funds)
wait_duration_secs = 1

# Target ETH balance per funded account (in wei)
fauce_eth_balance = "1000000000000000000000"

[accounts]
num_accounts = 100000

[performance]
# Number of concurrent transaction sending tasks inside TxnConsumer
num_senders = 600

# Max in-memory pool size inside the consumer
max_pool_size = 100000

# Benchmark duration in seconds (0 = run indefinitely)
duration_secs = 0

# Sampling strategy: integer = sample every N txns, or "full" to check all pending
sampling = 20
```

### Running the Benchmark

#### First Run (includes faucet distribution + contract deployment)

For the first run (or when you want to re-initialize accounts/contracts):

```bash
cargo run --release -- --config bench_config.toml
```

This step will:

* Distribute funds to test accounts using the faucet private key.
* Deploy the required contracts.
* Generate (or update) `deploy.json`, referenced by `contract_config_path`.

#### Subsequent Runs (reuse existing state)

Once contracts are deployed and `deploy.json` exists, use recovery mode:

```bash
cargo run --release -- --config bench_config.toml --recover
```

### Diagnostics

**Verify an RPC endpoint is reachable and get its `chain_id`:**

```bash
curl -s http://127.0.0.1:8545 \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'
# expect 0x539 for chainId 1337
```

**Check a faucet account balance:**

```bash
curl -s http://127.0.0.1:8545 \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","latest"]}'
```

### Troubleshooting

| Symptom                                                       | Fix                                                                                                                    |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Build error: `libudev.pc` / `hidapi` / `pkg-config` not found | `sudo apt install -y libudev-dev libusb-1.0-0-dev pkg-config`                                                          |
| `python: command not found`                                   | `sudo apt install -y python-is-python3`                                                                                |
| `ModuleNotFoundError: No module named 'web3'`                 | Ensure you're in the `gravity_bench` directory and run `source setup.sh` again                                         |
| `SolcError` or missing Uniswap/OpenZeppelin contracts         | Remove `contracts/` and `node_modules/` then re-run `source setup.sh`                                                  |
| `insufficient funds for gas * price + value`                  | Increase `faucet.wait_duration_secs` in `bench_config.toml`; for a local cluster, restart all nodes to reset state     |
| `assertion failed: accounts.num_accounts >= target_tps`       | Increase `accounts.num_accounts` to be ≥ `target_tps`                                                                  |
| `Connection refused` / wrong network                          | Verify `rpc_url` is correct and the cluster is running; confirm `chain_id` matches the value returned by `eth_chainId` |

### Visualization

For Grafana / Prometheus deployment and dashboard import, refer to:

* Grafana / Prometheus deployment guide coming soon.
