Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .env.devnet
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ CONTRA_SIGVERIFY_QUEUE_SIZE=10000000
CONTRA_SIGVERIFY_WORKERS=32
CONTRA_WRITE_MAX_CONNECTIONS=1000000
CONTRA_READ_MAX_CONNECTIONS=100000
CONTRA_PG_MAX_CONNECTIONS=32
CONTRA_MAX_TX_PER_BATCH=64
CONTRA_BATCH_DEADLINE_MS=10
CONTRA_BATCH_CHANNEL_CAPACITY=16
CONTRA_MAX_SVM_WORKERS=8
CONTRA_ADMIN_KEYS=admin_pubkey

# Gateway
Expand Down
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ CONTRA_SIGVERIFY_QUEUE_SIZE=10000000
CONTRA_SIGVERIFY_WORKERS=32
CONTRA_WRITE_MAX_CONNECTIONS=1000000
CONTRA_READ_MAX_CONNECTIONS=100000
# Postgres pool size per node (default 32, capped at 256).
CONTRA_PG_MAX_CONNECTIONS=32
CONTRA_MAX_TX_PER_BATCH=64
# Sequencer batch-flush deadline (ms).
CONTRA_BATCH_DEADLINE_MS=10
# Sequencer→executor batch channel capacity.
CONTRA_BATCH_CHANNEL_CAPACITY=16
# Executor parallel SVM worker cap.
CONTRA_MAX_SVM_WORKERS=8
CONTRA_ADMIN_KEYS=admin_pubkey

# Gateway
Expand Down
8 changes: 8 additions & 0 deletions .env.local
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ CONTRA_SIGVERIFY_QUEUE_SIZE=10000000
CONTRA_SIGVERIFY_WORKERS=32
CONTRA_WRITE_MAX_CONNECTIONS=1000000
CONTRA_READ_MAX_CONNECTIONS=100000
CONTRA_PG_MAX_CONNECTIONS=32
CONTRA_MAX_TX_PER_BATCH=64
CONTRA_BATCH_DEADLINE_MS=10
CONTRA_BATCH_CHANNEL_CAPACITY=16
CONTRA_MAX_SVM_WORKERS=8
CONTRA_ADMIN_KEYS=your_admin_public_key # Public key of keypairs/admin.json

# Gateway
Expand All @@ -32,6 +36,10 @@ GATEWAY_URL=http://gateway:8899
# Local validator RPC
LOCAL_VALIDATOR_RPC_URL=http://validator:8899

# Auth service
AUTH_PORT=8903
JWT_SECRET=

# Grafana
GF_ADMIN_PASSWORD=admin

Expand Down
33 changes: 16 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ package.edition = "2021"
[workspace.dependencies]
anyhow = "1.0.100"
argon2 = "0.5"
async-channel = "2"
base64 = "0.21"
bincode = "1.3.3"
borsh = "1.5.5"
Expand Down Expand Up @@ -117,7 +118,6 @@ testcontainers = "0.25"
testcontainers-modules = { version = "0.13", features = ["postgres", "redis"] }
thiserror = "2.0.17"
tokio = { version = "=1.47.1", features = ["full"] }
tokio-mpmc = "0.2.4"
tokio-util = { version = "0.7", features = ["full"] }
tracing = "0.1.41"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
Expand Down
16 changes: 13 additions & 3 deletions bench-tps/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ POSTGRES_REPLICATION_PASSWORD=repl_password
CONTRA_WRITE_PORT=8899
CONTRA_SIGVERIFY_QUEUE_SIZE=1000
CONTRA_SIGVERIFY_WORKERS=4
CONTRA_WRITE_MAX_CONNECTIONS=100
CONTRA_WRITE_MAX_CONNECTIONS=2048
# Postgres pool size per node (default 32, capped at 256).
CONTRA_PG_MAX_CONNECTIONS=32
CONTRA_MAX_TX_PER_BATCH=256
# Sequencer batch-flush deadline (ms).
CONTRA_BATCH_DEADLINE_MS=10
# Executor parallel SVM worker cap.
CONTRA_MAX_SVM_WORKERS=8

# Space-separated list of base58 admin public keys the node will accept.
# At least one key is required for the bench setup phase (mint init, ATA, mint-to).
Expand Down Expand Up @@ -90,10 +96,14 @@ BENCH_ADMIN_KEYPAIR=
BENCH_DURATION=60

# Concurrent sender threads per flow
BENCH_THREADS=3
BENCH_THREADS=16

# Transactions per batch produced by the generator; each batch is sent
# concurrently by one sender task via join_all. Tune independently of BENCH_THREADS.
BENCH_BATCH_SIZE=200

# Milliseconds each sender thread sleeps between batches; 0 = maximum throughput
BENCH_SENDER_SLEEP_MS=5
BENCH_SENDER_SLEEP_MS=0

# Raw token units minted to each account's ATA during setup; 1 unit consumed per tx
BENCH_INITIAL_BALANCE=1000000
Expand Down
16 changes: 13 additions & 3 deletions bench-tps/.env.sample.devnet
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ POSTGRES_REPLICATION_PASSWORD=repl_password
CONTRA_WRITE_PORT=8899
CONTRA_SIGVERIFY_QUEUE_SIZE=1000
CONTRA_SIGVERIFY_WORKERS=4
CONTRA_WRITE_MAX_CONNECTIONS=100
CONTRA_WRITE_MAX_CONNECTIONS=2048
# Postgres pool size per node (default 32, capped at 256).
CONTRA_PG_MAX_CONNECTIONS=32
CONTRA_MAX_TX_PER_BATCH=256
# Sequencer batch-flush deadline (ms).
CONTRA_BATCH_DEADLINE_MS=10
# Executor parallel SVM worker cap.
CONTRA_MAX_SVM_WORKERS=8

# Space-separated list of base58 admin public keys the node will accept.
# At least one key is required for the bench setup phase (mint init, ATA, mint-to).
Expand Down Expand Up @@ -106,10 +112,14 @@ BENCH_ADMIN_KEYPAIR=
BENCH_DURATION=60

# Concurrent sender threads per flow
BENCH_THREADS=3
BENCH_THREADS=16

# Transactions per batch produced by the generator; each batch is sent
# concurrently by one sender task via join_all. Tune independently of BENCH_THREADS.
BENCH_BATCH_SIZE=200

# Milliseconds each sender thread sleeps between batches; 0 = maximum throughput
BENCH_SENDER_SLEEP_MS=5
BENCH_SENDER_SLEEP_MS=0

# Raw token units minted to each account's ATA during setup; 1 unit consumed per tx
BENCH_INITIAL_BALANCE=1000000
Expand Down
1 change: 1 addition & 0 deletions bench-tps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ path = "src/main.rs"

[dependencies]
anyhow = "1.0"
async-channel = { workspace = true }
clap = { workspace = true }
contra-core = { workspace = true }
contra-metrics = { workspace = true }
Expand Down
14 changes: 14 additions & 0 deletions bench-tps/scripts/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ BENCH_ENV="${BENCH_DIR}/.env"
# script refreshes them to reload scrape config and
# dashboards (safe; does not delete data volumes).
#
# --no-teardown Skip `docker compose down` at exit. Containers keep
# running after the bench finishes (or is interrupted)
# so logs and metrics can be collected for offline
# analysis. Stop them manually afterwards with
# `docker compose -f <repo>/docker-compose.yml down`.
#
# --contra-threads N Pin Contra service containers to the first N CPU cores
# and the bench binary to the remaining cores. When
# omitted the default 75% / 25% split is used.
Expand All @@ -67,6 +73,7 @@ BENCH_ENV="${BENCH_DIR}/.env"
REBUILD=0
CLEAN=1 # default: always wipe volumes because validator resets each run
REFRESH_METRICS=1
TEARDOWN=1 # default: tear down containers on exit
CONTRA_THREADS="" # explicit core count for services (optional)
BENCH_ARGS=()
SKIP_NEXT=0
Expand All @@ -80,6 +87,7 @@ for arg in "$@"; do
--rebuild) REBUILD=1 ;;
--no-clean) CLEAN=0 ;;
--no-refresh-metrics) REFRESH_METRICS=0 ;;
--no-teardown) TEARDOWN=0 ;;
--contra-threads) SKIP_NEXT=1 ;; # value is the next token
*) BENCH_ARGS+=("${arg}") ;;
esac
Expand Down Expand Up @@ -673,6 +681,12 @@ cleanup() {
[ "${_CLEANUP_DONE}" -eq 1 ] && return
_CLEANUP_DONE=1
echo ""
if [ "${TEARDOWN}" -eq 0 ]; then
echo "Skipping teardown (--no-teardown). Containers are still running."
echo " Inspect logs: docker logs <container>"
echo " Stop later: docker compose -f ${REPO_ROOT}/docker-compose.yml down"
return
fi
echo "Tearing down all services..."
"${COMPOSE[@]}" down 2>/dev/null || true
echo "Done."
Expand Down
23 changes: 16 additions & 7 deletions bench-tps/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,30 @@ pub struct TransferArgs {
/// Each account gets its own keypair, ATA, and initial token balance.
/// Must be >= `--threads` to avoid multiple senders sharing a keypair
/// (which would cause nonce conflicts).
#[arg(long, default_value_t = 50, env = "BENCH_ACCOUNTS")]
#[arg(long, default_value_t = 200, env = "BENCH_ACCOUNTS")]
pub accounts: usize,

/// Duration of the load phase in seconds.
#[arg(long, default_value_t = 60, env = "BENCH_DURATION")]
pub duration: u64,

/// Number of concurrent sender threads.
/// Number of concurrent sender tasks.
///
/// Each sender thread runs a blocking loop: pop batch → send each tx →
/// sleep `--sender-sleep-ms` → repeat. More threads = higher throughput
/// up to the point where the node or network becomes the bottleneck.
#[arg(long, default_value_t = 4, env = "BENCH_THREADS")]
/// Each sender task runs an async loop: pop batch → send all txs
/// concurrently via `join_all` → sleep `--sender-sleep-ms` → repeat.
/// More tasks = higher throughput up to the point where the node or
/// network becomes the bottleneck.
#[arg(long, default_value_t = 16, env = "BENCH_THREADS")]
pub threads: usize,

/// Number of transactions per batch produced by the generator.
///
/// Each batch is sent concurrently by a single sender task using
/// `join_all`, so larger batches increase per-task parallelism.
/// Decoupled from `--threads` to allow independent tuning.
#[arg(long, default_value_t = 200, env = "BENCH_BATCH_SIZE")]
pub batch_size: usize,

/// Number of distinct receiver accounts.
///
/// Accounts are split into a sender pool (first half) and a receiver pool
Expand Down Expand Up @@ -115,7 +124,7 @@ pub struct TransferArgs {
///
/// Use this to throttle the send rate without reducing `--threads`.
/// A value of 0 disables the sleep entirely (maximum throughput mode).
#[arg(long, default_value_t = 5, env = "BENCH_SENDER_SLEEP_MS")]
#[arg(long, default_value_t = 0, env = "BENCH_SENDER_SLEEP_MS")]
pub sender_sleep_ms: u64,

/// Tracing log level. One of: error, warn, info, debug, trace.
Expand Down
Loading
Loading