Methodology

How the proposed ZERO_VALUE_TRANSFER and VALUE_TRANSFER values on the dashboard are derived — from raw benchmark runtimes through model fitting to the worst-case gas selection.

EIP-2780 background

Today every transaction pays a flat 21 000 gas base cost, whether or not it moves ether — a value transfer and a zero-value transfer cost exactly the same. EIP-2780 asks whether that single price still reflects the real work. Rather than fit one blended model, this dashboard measures the end-to-end cost of each kind of transfer directly and reports three values:

These constants were set long ago and may no longer reflect the real execution cost on modern clients. This analysis measures the actual runtime of each transfer kind and re-prices it against a fixed throughput anchor.

The receiver cases

The benchmark test test_ether_transfers_onchain_receivers sends ether to several kinds of receiver. Each is a separate case_id because the client's work differs by receiver type. The dashboard shows a short readable label for each; the raw case_id below stays the canonical key in data/results.json. Contract receivers (all but the last three) execute on-chain code; the 24 KiB variants pad the account to the code-size limit used for this repricing benchmark.

Which cases are charted. Every case above is fit and reported in full on the detail page and the model fit page. Two are held out of the Dashboard's charts: Contract (jumpdest) and Contract (diff_to_contract) are excluded from the Dashboard's charts, its Summary goal table and its worst-case highlight, and Contract is excluded from the Trends page as well — so the Trends page still charts Contract (jumpdest) while the Dashboard does not.

Deriving opcount (the “opcode trick”)

The model needs the number of value-transfer transactions packed into each benchmark block (opcount). The harness does not yet emit that count directly, so it is reconstructed — from a per-transaction opcode in the execution trace where one exists, and otherwise from the block gas limit and the transaction's EIP-2780 cost. This is a temporary technique — once the harness emits a per-block transaction count, that field should replace it.

The NNLS model

For each (client, case_id) group we split the runs by transfer_amount (the 0/1 indicator for whether the transfer moves ether) and fit two independent non-negative least squares (NNLS) models, each with the simple design matrix [1, opcount]:

Fitting the two regimes separately lets each have its own intercept and its own slope, rather than forcing a shared base with a single additive value surcharge. Non-negativity is enforced because gas costs cannot be negative. Inference uses bootstrap resampling (1000 iterations) to produce percentile-based 95% confidence intervals and p-values, since the NNLS constraint breaks the usual closed-form ordinary-least-squares standard errors.

Reading the p-values. These are not conventional two-sided null-hypothesis p-values. To match the non-negativity constraint, each p-value is the fraction of the 1000 bootstrap resamples in which the coefficient collapses to zero — a one-sided boundary test. The bootstrap distribution is centered on the fitted estimate, so a coefficient sitting well above zero is reproduced as positive in every resample and the p-value reads 0 (the resolution floor is 1/1000 = 0.001). A value of 1 means NNLS pinned the coefficient to exactly zero. Because opcount is a strong, clearly non-zero driver in both regimes, almost every p-value here is 0 — that is the expected outcome, the inverse of the usual p-value intuition. The p-value cannot distinguish a barely-positive coefficient from a large one; use the confidence intervals for that.

The 100 Mgas/s anchor and worst-case selection

Each runtime coefficient (in milliseconds) is converted to gas at a fixed throughput anchor of 100 Mgas/s:

new_gas = ceil(anchor_rate × runtime_ms / 1e3)

The same conversion (with ceil) is applied to the confidence-interval bounds. For each parameter the worst case is the (client, case) with the largest proposed gas (idxmax on new_gas_rounded) — the most conservative re-pricing that still keeps every client within the anchor. Worst cases whose driving model has R² ≤ 0.5, or whose coefficient p-value > 0.05 (not statistically significant), are flagged as caveats on the dashboard.

Marginal value cost (TX_VALUE_COST)

The first two parameters price each transfer kind end-to-end. The third isolates what moving value actually costs: TX_VALUE_COST = VALUE_TRANSFER − ZERO_VALUE_TRANSFER. This is the analogue of the old VALUE_GAS surcharge, but it is now a derived difference of two independent fits rather than a single fitted coefficient.

Because the two slopes come from separate fits on disjoint data, their uncertainties add rather than partially cancel (there is no shared bootstrap covariance to exploit). We propagate the 95% interval by interval arithmetic on the difference — [with_low − without_high, with_high − without_low] — and clamp the estimate and both bounds at zero: a value transfer modeled as cheaper than a plain one is noise, not a negative gas cost. The difference is flagged with a p-value caveat if either underlying slope is not statistically significant, and its R² is the worse of the two regime fits.

A note on VALUE_TRANSFER. Earlier versions of this dashboard derived VALUE_TRANSFER as TX_BASE + VALUE_GAS summed within one combined fit. It is now fit directly as the opcount slope on the value-transfer runs — the same name, but a measured end-to-end cost rather than a sum.

Reproducing this analysis

End to end, from raw data to the deployed site:

  1. Obtain a Benchmarkoor API token and place it in secrets.json as {"BENCHMARKOOR_TOKEN": "bmk_..."} (gitignored).
  2. Run make fetch — pulls the pinned benchmark suite via benchmarkoor-fetch into data/raw/.
  3. Run make analyze — runs the NNLS pipeline and writes data/results.json.
  4. Run make site — renders this static site into docs/.

Or simply make fetch && make analyze && make site. The committed data/results.json is the auditable record; everything on these pages is rendered from it at build time.