Skip to content

API reference

The top-level evm_gasfit package re-exports the small public surface. Everything else is internal.

evm_gasfit

evm-gasfit: estimate worst-case EVM gas costs from runtime measurements.

GasFit

GasFit(config: Config)

High-level driver wrapping the pipeline stages.

Attributes:

Name Type Description
config Config

The validated configuration loaded from YAML.

runtimes_df DataFrame | None

The raw runtimes frame loaded from CSV.

opcounts dict[str, dict[str, float]] | None

The parsed opcounts mapping loaded from JSON.

fixtures_df DataFrame | None

The merged per-fixture frame consumed by every stage.

estimate_output EstimateOutput | None

The output of :meth:estimate_models.

glue_estimate_output GlueEstimateOutput | None

The output of :meth:estimate_glue, or None.

proposal_output ProposalOutput | None

The output of :meth:build_proposal.

Source code in src/evm_gasfit/api.py
def __init__(self, config: Config) -> None:
    self.config: Config = config
    self.config_path: Path | None = None
    self.runtimes_path: Path | None = None
    self.opcounts_path: Path | None = None
    self.run_started_at: datetime = datetime.now(timezone.utc).replace(
        microsecond=0
    )
    self.runtimes_df: pd.DataFrame | None = None
    self.opcounts: dict[str, dict[str, float]] | None = None
    self.fixtures_df: pd.DataFrame | None = None
    self.fixture_match_result: FixtureMatchResult | None = None
    self.estimate_output: EstimateOutput | None = None
    self.glue_estimate_output: GlueEstimateOutput | None = None
    self.proposal_output: ProposalOutput | None = None
    self._warnings: list[str] = []
    self._warning_handler = _WarningCaptureHandler(self._warnings)
    _log.addHandler(self._warning_handler)

from_config classmethod

from_config(path: Path) -> 'GasFit'

Load and validate the YAML config at path and return a fresh driver.

Source code in src/evm_gasfit/api.py
@classmethod
def from_config(cls, path: Path) -> "GasFit":
    """Load and validate the YAML config at ``path`` and return a fresh driver."""
    path = Path(path)
    pre_warnings: list[str] = []
    pre_handler = _WarningCaptureHandler(pre_warnings)
    _log.addHandler(pre_handler)
    try:
        config = load_config(path)
    finally:
        _log.removeHandler(pre_handler)
    fit = cls(config)
    fit._warnings[:0] = pre_warnings
    fit.config_path = path
    return fit

load_runtimes

load_runtimes(path: Path) -> None

Load the runtimes CSV at path, restricted to config.clients.

Source code in src/evm_gasfit/api.py
def load_runtimes(self, path: Path) -> None:
    """Load the runtimes CSV at ``path``, restricted to ``config.clients``."""
    path = Path(path)
    df = load_runtimes(path)
    configured = list(self.config.clients)
    configured_set = set(configured)
    present = set(df["client_name"].astype(str))
    missing = sorted(configured_set - present)
    if missing:
        _log.warning(
            "missing-client: %d configured client(s) absent from runtimes CSV: %s",
            len(missing),
            ", ".join(repr(c) for c in missing),
        )
    self.runtimes_df = df[
        df["client_name"].astype(str).isin(configured_set)
    ].reset_index(drop=True)
    self.runtimes_path = path

load_opcounts

load_opcounts(path: Path) -> None

Load the opcounts JSON at path.

Source code in src/evm_gasfit/api.py
def load_opcounts(self, path: Path) -> None:
    """Load the opcounts JSON at ``path``."""
    path = Path(path)
    self.opcounts = load_opcounts(path)
    self.opcounts_path = path

estimate_models

estimate_models() -> DataFrame

Fit each ModelSpec and populate :attr:estimate_output.

Source code in src/evm_gasfit/api.py
def estimate_models(self) -> pd.DataFrame:
    """Fit each ``ModelSpec`` and populate :attr:`estimate_output`."""
    fixtures_df = self._ensure_fixtures()
    self.estimate_output = estimate_models(self.config, fixtures_df)
    return self.estimate_output.results_df

estimate_glue

estimate_glue() -> DataFrame

Fit the priced glue opcodes and populate :attr:glue_estimate_output.

Source code in src/evm_gasfit/api.py
def estimate_glue(self) -> pd.DataFrame:
    """Fit the priced glue opcodes and populate :attr:`glue_estimate_output`."""
    fixtures_df = self._ensure_fixtures()
    self.glue_estimate_output = estimate_glue(self.config, fixtures_df)
    return self.glue_estimate_output.results_df

build_proposal

build_proposal() -> DataFrame

Aggregate and apply derived params; populate :attr:proposal_output.

Source code in src/evm_gasfit/api.py
def build_proposal(self) -> pd.DataFrame:
    """Aggregate and apply derived params; populate :attr:`proposal_output`."""
    if self.estimate_output is None:
        self.estimate_models()
    assert self.estimate_output is not None
    fixtures_df = self._ensure_fixtures()
    self.proposal_output = build_proposal(
        self.config,
        self.estimate_output.results_df,
        self.glue_estimate_output,
        fixtures_df,
    )
    return self.proposal_output.new_gas_df

write_reports

write_reports(out_dir: Path) -> None

Write every CSV + markdown artifact (and figs, if plots enabled).

Source code in src/evm_gasfit/api.py
def write_reports(self, out_dir: Path) -> None:
    """Write every CSV + markdown artifact (and figs, if plots enabled)."""
    if self.proposal_output is None:
        self.build_proposal()
    assert self.estimate_output is not None
    assert self.proposal_output is not None

    out_dir = Path(out_dir)
    out_dir.mkdir(parents=True, exist_ok=True)

    # CSVs first so plot/markdown writers can co-locate figs.
    self.estimate_output.results_df.to_csv(
        out_dir / "results.csv", index=False, lineterminator="\n"
    )
    self.proposal_output.new_gas_df.to_csv(
        out_dir / "new_gas.csv", index=False, lineterminator="\n"
    )
    self.proposal_output.new_gas_all_df.to_csv(
        out_dir / "new_gas_all_params.csv", index=False, lineterminator="\n"
    )

    glue_enabled = (
        self.config.glue_adjustment.enabled
        and self.glue_estimate_output is not None
    )
    if glue_enabled:
        assert self.glue_estimate_output is not None
        self.glue_estimate_output.results_df.to_csv(
            out_dir / "glue_results.csv", index=False, lineterminator="\n"
        )
        self.proposal_output.glue_opcodes_by_test_df.to_csv(
            out_dir / "glue_opcodes_by_test.csv",
            index=False,
            lineterminator="\n",
        )

    write_runtime_report(
        out_dir,
        self.estimate_output.results_df,
        self.estimate_output.fits,
        self.config,
    )
    if glue_enabled:
        assert self.glue_estimate_output is not None
        write_glue_report(
            out_dir,
            self.glue_estimate_output.results_df,
            self.glue_estimate_output.fits,
            self.config,
        )
    write_proposal_report(out_dir, self.proposal_output, self.config)
    self._write_meta(out_dir)

GasCosts dataclass

GasCosts(values: dict[str, int] = dict(), fork: str = '', source: str = '', _field_names: frozenset[str] = frozenset())

A flat, mutable mapping of fork gas-param field names to integer costs.

The instance is dict-backed so callers can patch individual fields after construction (used by gas_costs.overrides in the YAML config) without mutating module-level state. field_names returns the original fork field set, captured at construction time so later additions (e.g. derived params) do not pollute the "raw fork fields" universe.

Attributes:

Name Type Description
values dict[str, int]

The underlying name -> cost table. Prefer the mapping API (gc[name], name in gc) over reaching for this directly.

fork str

The fork name this table belongs to, normalized to lowercase.

source str

Either "execution-specs" or "fallback" — useful for reproducibility tracking.

field_names property

field_names: frozenset[str]

The raw fork-field names captured at construction time.

load_config

load_config(path: Path) -> Config

Load and validate the YAML config at path.

Parameters:

Name Type Description Default
path Path

Filesystem path to the YAML config file.

required

Returns:

Type Description
Config

The validated Config with all computed-at-load-time fields set.

Raises:

Type Description
ConfigError

When the file is missing, the YAML is malformed, or any Pydantic / cross-field validation rule fails.

Source code in src/evm_gasfit/config.py
def load_config(path: Path) -> Config:
    """Load and validate the YAML config at ``path``.

    Args:
        path: Filesystem path to the YAML config file.

    Returns:
        The validated ``Config`` with all computed-at-load-time fields set.

    Raises:
        ConfigError: When the file is missing, the YAML is malformed, or any
            Pydantic / cross-field validation rule fails.
    """
    if not path.exists():
        raise ConfigError(f"config file not found: {path}")
    try:
        raw = yaml.safe_load(path.read_text())
    except yaml.YAMLError as exc:
        raise ConfigError(f"config {path} is not valid YAML: {exc}") from exc
    if not isinstance(raw, dict):
        raise ConfigError(f"config {path} must be a YAML mapping at the top level")
    try:
        return Config.model_validate(raw)
    except ConfigError:
        raise
    except ValidationError as exc:
        # Unwrap a ConfigError raised inside a validator (Pydantic wraps it).
        for err in exc.errors():
            cause = (
                err.get("ctx", {}).get("error")
                if isinstance(err.get("ctx"), dict)
                else None
            )
            if isinstance(cause, ConfigError):
                raise cause from exc
        details = "; ".join(
            f"{'.'.join(str(p) for p in err['loc'])}: {err['msg']}"
            for err in exc.errors()
        )
        raise ConfigError(f"invalid config {path}: {details}") from exc