BENCHMARKS / ARC TESTNET
Load tests, with receipts.
4 scenarios run on 2026-09-17 against the public D20DAO keeper on Arc Testnet: 470 paid requests opened through a benchmark consumer contract. Every figure below comes from committed result files and links to its transactions. These are observations of one keeper on a testnet, not an SLA.
- Served within 60 s
- 470 / 470 all scenarios; 0 refunds, 0 expired
- Burst of 200
- 6.90 fulfillments/s over 29 s, 13 fulfillment transactions
- Isolated request, p50
- 2 s 4 blocks; sequential-20
- Largest batch
- 16 requests in one fulfillment transaction
Scenarios compared
Completion is chain time from the request block to the fulfillment block, in seconds and in blocks (p50 / p95 / p99 / max). Throughput is a serving rate only for bursts; in the other scenarios it follows the arrival rate. Duration runs from the first request block to the last fulfillment block.
| Scenario | Requests | Success in 60 s | Completion, s | Blocks | Fulfillment batches | Throughput | Gas per request | Duration |
|---|---|---|---|---|---|---|---|---|
| Sequential baseline | 20 requests, one at a time20 × 1 in 20 blocks | 100%20 of 20 | 2 / 3 / 3 / 3 | 4 / 6 / 6 / 6 | 20 transactionsmean 1.0, max 1 | 0.34/slimited by arrivals | 296,868+ 296,981 fulfillment | 61 s66 s wall clock |
| Burst of 50 | 50 requests at once1 × 50 in 1 block | 100%50 of 50 | 10 / 12 / 12 / 12 | 18 / 23 / 23 / 23 | 4 transactionsmean 12.5, max 16 | 7.14/s50 over 7 s | 195,809+ 262,141 fulfillment | 12 s16 s wall clock |
| Burst of 200 | 200 requests at once4 × 50 in 2 blocks | 100%200 of 200 | 21 / 33 / 35 / 35 | 41 / 65 / 70 / 70 | 13 transactionsmean 15.4, max 16 | 6.90/s200 over 29 s | 195,404+ 260,834 fulfillment | 35 s39 s wall clock |
| Sustained 5 requests/s | 5 requests/s for 40 s40 × 5 in 40 blocks | 100%200 of 200 | 5 / 7 / 8 / 8 | 10 / 14 / 14 / 14 | 24 transactionsmean 8.3, max 15 | 4.88/slimited by arrivals | 230,591+ 235,122 fulfillment | 45 s48 s wall clock |
SEQUENTIAL-20 / 2026-09-17 02:13 UTC
Sequential baseline
Baseline: 20 requests, one per transaction; the next request is sent only after the previous one is fulfilled or expired.
Load and concurrency
- Requests
- 20 opened of 20 planned
- Request transactions
- 20 transactions of 1, in 20 blocks; at most 1 in one block
- Request span
- 119 blocks, 59 s
Outcome
- Success in 60 s
- 100% (20 of 20)
- Callbacks delivered
- 20 (consumer counted 20)
- Refunds / expired
- 0 / 0
Completion
- Chain seconds
- p50 2, p95 3, p99 3, max 3
- Blocks
- p50 4, p95 6, p99 6, max 6
- Wall clock
- broadcast to observed fulfillment: p50 2.9 s, p95 3.9 s, max 3.9 s
- Epoch publication
- 0 of 20 requests waited for their epoch packet to be published
Batching and throughput
- Fulfillment transactions
- 20; 0 other applications' requests shared them
- Members per transaction
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- Throughput
- 0.34/s, limited by arrivals (20 over 59 s, 20 fulfillment transactions)
- Duration
- 61 s from first request to last fulfillment; 66 s wall clock
Gas and cost
- Request gas
- 296,868 per request (p50), at 25.0 gwei
- Fulfillment gas
- 296,981 per served request, 324,300 max per transaction
- User cost
- 0.0800 USDC fee + 0.0074 USDC gas per request
- Keeper
- 0.0400 USDC fee share, 0.0083 USDC gas per served request
Arc block conditions
- Blocks
- 126 (62,500,922 to 62,501,047), mean interval 0.50 s
- Base fee
- 20 / 20 / 20 gwei (min / median / max)
- Gas used ratio
- mean 3.3%, max 10.6% of a 30,000,000 gas limit
BURST-50 / 2026-09-17 02:17 UTC
Burst of 50
50 requests opened by one transaction, so all share one block.
Load and concurrency
- Requests
- 50 opened of 50 planned
- Request transactions
- 1 transaction of 50, in 1 block; at most 50 in one block
- Request span
- 1 block, 0 s
Outcome
- Success in 60 s
- 100% (50 of 50)
- Callbacks delivered
- 50 (consumer counted 50)
- Refunds / expired
- 0 / 0
Completion
- Chain seconds
- p50 10, p95 12, p99 12, max 12
- Blocks
- p50 18, p95 23, p99 23, max 23
- Wall clock
- broadcast to observed fulfillment: p50 10.6 s, p95 12.7 s, max 12.7 s
- Epoch publication
- 50 of 50 requests waited for their epoch packet to be published
Batching and throughput
- Fulfillment transactions
- 4; 0 other applications' requests shared them
- Members per transaction
- 8
- 16
- 16
- 10
- Throughput
- 7.14/s (50 over 7 s, 4 fulfillment transactions)
- Duration
- 12 s from first request to last fulfillment; 16 s wall clock
Gas and cost
- Request gas
- 195,809 per request (p50), at 25.0 gwei
- Fulfillment gas
- 262,141 per served request, 4,166,740 max per transaction
- User cost
- 0.0800 USDC fee + 0.0049 USDC gas per request
- Keeper
- 0.0400 USDC fee share, 0.0078 USDC gas per served request
Arc block conditions
- Blocks
- 27 (62,501,300 to 62,501,326), mean interval 0.50 s
- Base fee
- 20 / 20 / 20 gwei (min / median / max)
- Gas used ratio
- mean 8.1%, max 34.3% of a 30,000,000 gas limit
BURST-200 / 2026-09-17 02:19 UTC
Burst of 200
200 requests opened by four 50-request transactions broadcast together; about 11M gas each, so they need at least two 30M-gas blocks.
Load and concurrency
- Requests
- 200 opened of 200 planned
- Request transactions
- 4 transactions of 50, in 2 blocks; at most 100 in one block
- Request span
- 2 blocks, 0 s
Outcome
- Success in 60 s
- 100% (200 of 200)
- Callbacks delivered
- 200 (consumer counted 200)
- Refunds / expired
- 0 / 0
Completion
- Chain seconds
- p50 21, p95 33, p99 35, max 35
- Blocks
- p50 41, p95 65, p99 70, max 70
- Wall clock
- broadcast to observed fulfillment: p50 22.3 s, p95 34.5 s, max 36.5 s
- Epoch publication
- 200 of 200 requests waited for their epoch packet to be published
Batching and throughput
- Fulfillment transactions
- 13; 0 other applications' requests shared them
- Members per transaction
- 16
- 16
- 16
- 16
- 16
- 16
- 16
- 16
- 16
- 16
- 16
- 16
- 8
- Throughput
- 6.90/s (200 over 29 s, 13 fulfillment transactions)
- Duration
- 35 s from first request to last fulfillment; 39 s wall clock
Gas and cost
- Request gas
- 195,404 per request (p50), at 25.0 gwei
- Fulfillment gas
- 260,834 per served request, 4,245,702 max per transaction
- User cost
- 0.0800 USDC fee + 0.0049 USDC gas per request
- Keeper
- 0.0400 USDC fee share, 0.0075 USDC gas per served request
Arc block conditions
- Blocks
- 73 (62,501,574 to 62,501,646), mean interval 0.50 s
- Base fee
- 20 / 20 / 20 gwei (min / median / max)
- Gas used ratio
- mean 8.0%, max 69.7% of a 30,000,000 gas limit
SUSTAINED-5RPS-40S / 2026-09-17 02:22 UTC
Sustained 5 requests/s
Sustained arrivals: one 5-request transaction every second for 40 seconds (200 requests). 40 s instead of 60 s keeps the whole suite under 500 paid requests.
Load and concurrency
- Requests
- 200 opened of 200 planned
- Request transactions
- 40 transactions of 5, in 40 blocks; at most 5 in one block
- Request span
- 79 blocks, 39 s
Outcome
- Success in 60 s
- 100% (200 of 200)
- Callbacks delivered
- 200 (consumer counted 200)
- Refunds / expired
- 0 / 0
Completion
- Chain seconds
- p50 5, p95 7, p99 8, max 8
- Blocks
- p50 10, p95 14, p99 14, max 14
- Wall clock
- broadcast to observed fulfillment: p50 6.0 s, p95 7.8 s, max 8.4 s
- Epoch publication
- 15 of 200 requests waited for their epoch packet to be published
Batching and throughput
- Fulfillment transactions
- 24; 0 other applications' requests shared them
- Members per transaction
- 8
- 7
- 5
- 5
- 5
- 5
- 1
- 9
- 5
- 5
- 5
- 5
- 5
- 10
- 10
- 10
- 15
- 15
- 10
- 15
- 15
- 10
- 15
- 5
- Throughput
- 4.88/s, limited by arrivals (200 over 41 s, 24 fulfillment transactions)
- Duration
- 45 s from first request to last fulfillment; 48 s wall clock
Gas and cost
- Request gas
- 230,591 per request (p50), at 25.0 gwei
- Fulfillment gas
- 235,122 per served request, 3,446,919 max per transaction
- User cost
- 0.0800 USDC fee + 0.0057 USDC gas per request
- Keeper
- 0.0400 USDC fee share, 0.0063 USDC gas per served request
Arc block conditions
- Blocks
- 92 (62,501,898 to 62,501,989), mean interval 0.52 s
- Base fee
- 20 / 20 / 20 gwei (min / median / max)
- Gas used ratio
- mean 7.5%, max 25.7% of a 30,000,000 gas limit
Keeper under test
Hardware and settings as declared by the operator for these runs; they cannot be checked from chain data. Every fulfillment transaction came from 0x61659d9A9A85dA07C36e7d1B35CF0d96CF199Cac, the keeper address in the public deployment manifest.
- Host
- Hetzner vServer, AMD EPYC-Rome, 4 vCPU, 7.6 GiB RAM, 75 GB disk
- System
- Ubuntu 24.04.4 LTS, Docker 29.8.1; keeper image from commit d15b4a0
- Settings
- POLL_MS 250, TICK_TIMEOUT_SECONDS 20, FULFILL_BATCH_MAX 16, MAX_GAS 6,000,000, MAX_FEE_PER_GAS 100 gwei, FEE_COVERAGE_BPS 10000
- Transactions
- one nonce lane: one fulfillment transaction at a time
- RPC
- https://rpc.testnet.arc.io, https://rpc.blockdaemon.testnet.arc.io, https://rpc.drpc.testnet.arc.io
Contracts and software
- Coordinator proxy
- 0xd20DA0FF9087d053f0291524Eac12abA1ADBd945
- Implementation
- 0xd20da0c375cefcda65703699a4090237057e9b68 (ERC-1967 slot, matched the manifest before and after every run)
- Pricing
- minimum fee 0.08 USDC, multiplier 5, overhead 300,000 gas, keeper share 50%
- Load consumer
- 0x7cFf09B81D013f1cbBd216607879BF529760b1B3 (solc 0.8.28, cancun)
- Benchmark software
- @d20dao/vrf-sdk@0.3.3, ethers 6.17.0, Node 24.19.0
- Script commit
- 4dd5f79693ad5b9faee9912b21c97ed5feeb7165, clean working tree
- Results commit
- 8e727a822305388c03d7ffc55f9a0ce9e148ed21
- Observation RPC
- https://rpc.blockdaemon.testnet.arc.io
Methodology
- A benchmark wallet owns LoadConsumer, a small MIT contract that extends the SDK's D20VRFConsumer. One open() call pays quoteFee(100,000) inside the transaction for each request, opens up to 100 raw requests against the public coordinator proxy and records every authenticated callback. Arc Testnet keeps only about 16 pending transactions per sender, so concurrent load has to come from many requests per transaction.
- The Node script (run with Node 24.19.0, ethers 6.17.0 and @d20dao/vrf-sdk@0.3.3) reads the coordinator proxy from the public deployment manifest, checks the implementation in the ERC-1967 slot against it, quotes with quoteRequestFee and broadcasts the request transactions for each scenario.
- Completion latency is the fulfillment block timestamp minus the request block timestamp, and the same in block numbers. Success means RandomnessFulfilled was accepted at or before the request's deadline (request time plus 60 s); callback delivery, refunds and expiry come from getRequest after settlement.
- Batch sizes are the members of each fulfillRandomnessBatch transaction that served a request of the run, including other applications' requests when the keeper combined them. Throughput is a run's fulfilled requests divided by the seconds between its first and last fulfillment block; only a burst measures serving rate, because every request is open from the start. The first transaction's requests count although its block opens the window, so short windows overstate the rate slightly.
- Block conditions cover every block from the chain head at the start of a run to the last block holding one of its requests or fulfillments. Percentiles use the nearest-rank method. Wall-clock times are measured by the benchmark machine polling a public RPC every 500 ms.
Limitations
- One keeper process with one transaction lane served every request, on Arc Testnet. The numbers do not describe Arc Mainnet, other hardware or other keeper settings.
- The testnet keeper also serves other applications, and both the keeper and the benchmark use public RPC endpoints with unknown load and rate limits.
- Arc block timestamps have whole-second resolution, so latencies in seconds carry up to a second of rounding; block counts are finer at about two blocks per second.
- Requests are raw words with 100,000 callback gas and a small storage-writing callback. Samples of 20 to 200 requests from single runs make tail percentiles indicative only.
- These are observations, not an SLA. The protocol's only timing rule is that a request not fulfilled within 60 seconds becomes refundable.
Reproduce
The repository README explains each field, funding and the safety limits. Use a dedicated Arc Testnet wallet; these four runs spent 40.1 test USDC in fees and gas.
git clone https://github.com/d20dao/benchmarks
cd benchmarks && npm ci && npm run compile -- --check
export BENCH_PRIVATE_KEY_FILE=/secure/path/arc-testnet.key
npm run deploy -- --force
npm run suite
npm run summary