Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c90177c
skeleton test setup
kmchicoine Oct 15, 2025
9ac2960
add basic tests and rpc client
kmchicoine Oct 15, 2025
59e7931
add client
kmchicoine Oct 15, 2025
3ba620d
full e2e tests, with local node
kmchicoine Oct 24, 2025
a262b34
Ignore test that requires node running
kmchicoine Oct 24, 2025
cdad812
Mark full node tests with env flag
kmchicoine Oct 27, 2025
9f65698
Merge remote-tracking branch 'origin/master' into kaley/e2e-testing
kmchicoine Oct 27, 2025
1f9fe4d
Finish merge
kmchicoine Oct 27, 2025
ae9641f
readme + fmt
kmchicoine Oct 28, 2025
8272ed9
Merge remote-tracking branch 'origin/master' into kaley/e2e-testing
kmchicoine Oct 28, 2025
e78c225
yarn update
kmchicoine Oct 28, 2025
56ef9a0
Update tests for clean fail
kmchicoine Oct 28, 2025
d254ec2
fmt
kmchicoine Oct 28, 2025
b5b4502
Add mock provider to avoid need to run node for e2e tests
kmchicoine Oct 30, 2025
15cada8
Cargo
kmchicoine Oct 30, 2025
f0cc6a9
Merge remote-tracking branch 'origin/master' into kaley/e2e-testing
kmchicoine Oct 30, 2025
4d74529
lint + clippy
kmchicoine Oct 30, 2025
d7b82a2
Update env var flag and readme
kmchicoine Oct 31, 2025
6541a73
Merge remote-tracking branch 'origin/master' into kaley/e2e-testing
kmchicoine Nov 3, 2025
8ec09b6
Merge remote-tracking branch 'origin/master' into kaley/e2e-testing
kmchicoine Nov 6, 2025
d34f5b5
run tests with full services
kmchicoine Nov 6, 2025
126e4e5
update integration tests filename
kmchicoine Nov 6, 2025
3a9cf7b
Merge remote-tracking branch 'origin/master' into kaley/e2e-testing
kmchicoine Nov 7, 2025
b87f88d
Merge remote-tracking branch 'origin/master' into kaley/e2e-testing
kmchicoine Nov 10, 2025
1a23736
create runnable bin for load testing
kmchicoine Nov 15, 2025
c2bc241
Restructure for runnable binary
kmchicoine Nov 30, 2025
55da6cf
Merge remote-tracking branch 'origin/master' into kaley/e2e-testing
kmchicoine Nov 30, 2025
4d58ead
Separate load testing from integration testing
kmchicoine Nov 30, 2025
20a3d9b
refine load testing
kmchicoine Dec 18, 2025
03618d6
Merge remote-tracking branch 'origin' into kaley/load-tests
kmchicoine Dec 19, 2025
59485ab
Fix toml
kmchicoine Dec 19, 2025
14cdfe0
Merge branch 'master' into kaley/load-tests
kmchicoine Dec 22, 2025
f5a389d
Cargo.toml update
kmchicoine Dec 22, 2025
35e13f1
Load test cleanup
kmchicoine Dec 22, 2025
79bc854
fix readme
kmchicoine Dec 22, 2025
069a696
METRICS.md fix + fmt
kmchicoine Dec 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 208 additions & 36 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ homepage = "https://github.com/base/tips"
repository = "https://github.com/base/tips"

[workspace]
members = ["crates/audit", "crates/ingress-rpc", "crates/core", "crates/account-abstraction-core"]
members = ["crates/audit", "crates/ingress-rpc", "crates/core", "crates/account-abstraction-core", "crates/system-tests"]
resolver = "2"

[workspace.dependencies]
tips-audit = { path = "crates/audit" }
tips-core = { path = "crates/core" }
tips-system-tests = { path = "crates/system-tests" }
account-abstraction-core = { path = "crates/account-abstraction-core" }

# Reth
Expand All @@ -27,8 +28,10 @@ alloy-primitives = { version = "1.4.1", default-features = false, features = [
] }
alloy-consensus = { version = "1.0.41" }
alloy-provider = { version = "1.0.41" }
alloy-serde = "1.0.41"
alloy-rpc-types = "1.1.2"
alloy-signer = { version = "1.0.41" }
alloy-network = { version = "1.0.41" }
alloy-serde = "1.0.41"
alloy-sol-types = { version = "1.4.1", default-features = false }

# op-alloy
Expand Down
7 changes: 7 additions & 0 deletions crates/system-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ hex = "0.4.3"
jsonrpsee = { workspace = true }
op-revm = { workspace = true }

# Load test dependencies
clap = { version = "4.5", features = ["derive", "env"] }
indicatif = "0.17"
rand = "0.8"
rand_chacha = "0.3"
dashmap = "6.0"

[dev-dependencies]
tokio = { workspace = true, features = ["test-util"] }
testcontainers = { workspace = true }
Expand Down
133 changes: 133 additions & 0 deletions crates/system-tests/METRICS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# TIPS Load Testing

Multi-wallet concurrent load testing tool for measuring TIPS performance.

## Quick Start

```bash
# 1. Build
cargo build --release --bin load-test

# 2. Setup wallets
./target/release/load-test setup \
--master-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d \
--output wallets.json

# 3. Run load test
./target/release/load-test load --wallets wallets.json
```

---

## Configuration Options

### Setup Command

Create and fund test wallets from a master wallet. Test wallets are saved to allow test reproducibility and avoid the need to create new wallets for every test run.

**Usage:**
```bash
load-test setup --master-key <KEY> --output <FILE> [OPTIONS]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be ./target/release/load-test ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yep, good catch!

```

**Options:**

| Flag | Description | Default | Example |
|------|-------------|---------|---------|
| `--master-key` | Private key of funded wallet (required) | - | `0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d` |
| `--output` | Save wallets to JSON file (required) | - | `wallets.json` |
| `--sequencer` | L2 sequencer RPC URL | `http://localhost:8547` | `http://localhost:8547` |
| `--num-wallets` | Number of wallets to create | `10` | `100` |
| `--fund-amount` | ETH to fund each wallet | `0.1` | `0.5` |

**Environment Variables:**
- `MASTER_KEY` - Alternative to `--master-key` flag
- `SEQUENCER_URL` - Alternative to `--sequencer` flag

### Load Command

Run load test with funded wallets. Use the `--seed` flag to set the RNG seed for test reproducibility.

**Usage:**
```bash
load-test load --wallets <FILE> [OPTIONS]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here

```

**Options:**

| Flag | Description | Default | Example |
|------|-------------|---------|---------|
| `--wallets` | Path to wallets JSON file (required) | - | `wallets.json` |
| `--target` | TIPS ingress RPC URL | `http://localhost:8080` | `http://localhost:8080` |
| `--sequencer` | L2 sequencer RPC URL | `http://localhost:8547` | `http://localhost:8547` |
| `--rate` | Target transaction rate (tx/s) | `100` | `500` |
| `--duration` | Test duration in seconds | `60` | `100` |
| `--tx-timeout` | Timeout for tx inclusion (seconds) | `60` | `120` |
| `--seed` | Random seed for reproducibility | (none) | `42` |
| `--output` | Save metrics to JSON file | (none) | `metrics.json` |

**Environment Variables:**
- `INGRESS_URL` - Alternative to `--target` flag
- `SEQUENCER_URL` - Alternative to `--sequencer` flag

---
---

## Metrics Explained

### Output Example

```
Load Test Results
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Configuration:
Target: http://localhost:8080
Sequencer: http://localhost:8547
Wallets: 100
Target Rate: 100 tx/s
Comment on lines +86 to +87
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qq: is it correct to assume that the target TPS is evenly distributed across the number of wallets?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. Could make this configurable as well if needed

Duration: 60s
TX Timeout: 60s

Throughput:
Sent: 100.0 tx/s (6000 total)
Included: 98.5 tx/s (5910 total)
Success Rate: 98.5%

Transaction Results:
Included: 5910 (98.5%)
Reverted: 10 (0.2%)
Timed Out: 70 (1.2%)
Send Errors: 10 (0.1%)
```

### Metrics Definitions

**Throughput:**
- `Sent Rate` - Transactions sent to TIPS per second
- `Included Rate` - Transactions included in blocks per second
- `Success Rate` - Percentage of sent transactions that were included

**Transaction Results:**
- `Included` - Successfully included in a block with status == true
- `Reverted` - Included in a block but transaction reverted (status == false)
- `Timed Out` - Not included within timeout period
- `Send Errors` - Failed to send to TIPS RPC

---

## Architecture

```
Sender Tasks (1 per wallet) Receipt Poller
│ │
▼ ▼
Send to TIPS ──► Tracker ◄── Poll sequencer every 2s
(retry 3x) (pending) │
│ │ ├─ status=true → included
│ │ ├─ status=false → reverted
│ │ └─ timeout → timed_out
▼ ▼
rate/N tx/s Calculate Results → Print Summary
```

---
13 changes: 13 additions & 0 deletions crates/system-tests/src/bin/load-test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use anyhow::Result;
use clap::Parser;
use tips_system_tests::load_test::{config, load, setup};

#[tokio::main]
async fn main() -> Result<()> {
let cli = config::Cli::parse();

match cli.command {
config::Commands::Setup(args) => setup::run(args).await,
config::Commands::Load(args) => load::run(args).await,
}
}
1 change: 1 addition & 0 deletions crates/system-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod client;
pub mod fixtures;
pub mod load_test;
76 changes: 76 additions & 0 deletions crates/system-tests/src/load_test/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use clap::{Parser, Subcommand};
use std::path::PathBuf;

#[derive(Parser)]
#[command(name = "load-test")]
#[command(about = "Load testing tool for TIPS ingress service", long_about = None)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}

#[derive(Subcommand)]
pub enum Commands {
/// Setup: Fund N wallets from a master wallet
Setup(SetupArgs),
/// Load: Run load test with funded wallets
Load(LoadArgs),
}

#[derive(Parser)]
pub struct SetupArgs {
/// Master wallet private key (must have funds)
#[arg(long, env = "MASTER_KEY")]
pub master_key: String,

/// Sequencer RPC URL
#[arg(long, env = "SEQUENCER_URL", default_value = "http://localhost:8547")]
pub sequencer: String,

/// Number of wallets to create and fund
#[arg(long, default_value = "10")]
pub num_wallets: usize,

/// Amount of ETH to fund each wallet
#[arg(long, default_value = "0.1")]
pub fund_amount: f64,

/// Output file for wallet data (required)
#[arg(long)]
pub output: PathBuf,
}

#[derive(Parser)]
pub struct LoadArgs {
/// TIPS ingress RPC URL
#[arg(long, env = "INGRESS_URL", default_value = "http://localhost:8080")]
pub target: String,

/// Sequencer RPC URL (for nonce fetching and receipt polling)
#[arg(long, env = "SEQUENCER_URL", default_value = "http://localhost:8547")]
pub sequencer: String,

/// Path to wallets JSON file (required)
#[arg(long)]
pub wallets: PathBuf,

/// Target transaction rate (transactions per second)
#[arg(long, default_value = "100")]
pub rate: u64,

/// Test duration in seconds
#[arg(long, default_value = "60")]
pub duration: u64,

/// Timeout for transaction inclusion (seconds)
#[arg(long, default_value = "60")]
pub tx_timeout: u64,

/// Random seed for reproducibility
#[arg(long)]
pub seed: Option<u64>,

/// Output file for metrics (JSON)
#[arg(long)]
pub output: Option<PathBuf>,
}
Loading
Loading