{"id":18357312,"url":"https://github.com/nethermindeth/gas-benchmarks","last_synced_at":"2026-04-29T16:09:26.740Z","repository":{"id":226442189,"uuid":"761754395","full_name":"NethermindEth/gas-benchmarks","owner":"NethermindEth","description":"Gas benchmark research repository","archived":false,"fork":false,"pushed_at":"2026-04-06T22:28:15.000Z","size":1918470,"stargazers_count":21,"open_issues_count":12,"forks_count":18,"subscribers_count":7,"default_branch":"main","last_synced_at":"2026-04-07T00:27:08.789Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NethermindEth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-02-22T12:34:37.000Z","updated_at":"2026-04-06T22:28:29.000Z","dependencies_parsed_at":"2024-04-15T07:36:14.804Z","dependency_job_id":"8cb76a8c-d417-4906-922c-039756b07e75","html_url":"https://github.com/NethermindEth/gas-benchmarks","commit_stats":null,"previous_names":["nethermindeth/gas-benchmarks"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/NethermindEth/gas-benchmarks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2Fgas-benchmarks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2Fgas-benchmarks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2Fgas-benchmarks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2Fgas-benchmarks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NethermindEth","download_url":"https://codeload.github.com/NethermindEth/gas-benchmarks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2Fgas-benchmarks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31511784,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T03:10:19.677Z","status":"ssl_error","status_checked_at":"2026-04-07T03:10:13.982Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T22:13:24.299Z","updated_at":"2026-04-07T12:01:16.667Z","avatar_url":"https://github.com/NethermindEth.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Gas Benchmarks\n\nThis repository contains scripts to run benchmarks across multiple clients.\nFollow the instructions below to run the benchmarks locally.\n\n## Prerequisites\n\nMake sure you have the following installed on your system:\n\n- Python 3.10\n- Docker\n- Docker Compose\n- .NET 8.0.x\n- `make` (for running make commands)\n- `git lfs`, `zip` (additional tools)\n\n## Setup\n\n1. **Clone the repository:**\n\n```sh\ngit clone https://github.com/nethermindeth/gas-benchmarks.git\ncd gas-benchmarks\n```\n\n2. **Install Python dependencies:**\n\n```sh\npip install -r requirements.txt\n```\n\n2.1.**Install additional tools:**\n\n```sh\ngit lfs install\ngit lfs pull\nsudo apt install zip\n```\n\n3. **Prepare Kute dependencies (specific to Nethermind):**\n\n```sh\nmake prepare_tools\n```\n\n4. **Create a results directory:**\n\n```sh\nmkdir -p results\n```\n\n## Running the Benchmarks\n\n### Script: Run all\n\nFor running the whole pipeline, you can use the `run.sh` script.\n\n```sh\nbash run.sh -t \"testsPath\" -w \"warmupFilePath\" -c \"client1,client2\" -r runNumber -i \"image1,image2\"\n```\n\nExample run:\n```shell\nrun.sh -t \"eest_tests/\" -w \"warmup-tests\" -c \"nethermind,geth,reth\" -r 8\n```\n\nFlags:\n- `--t` it's used to define the path where the tests are located.\n- `--w` it's used to define the path where the warmup file is located.\n- `--c` it's used to define the clients that you want to run the benchmarks. Separate the clients with a comma.\n- `--r` it's used to define the number of iterations that you want to run the benchmarks. It's a numeric value.\n- `--i` it's used to define the images that you want to use to run the benchmarks. Separate the images with a comma, and match the clients. Use `default` if you want to ignore the values.\n\nNow you're ready to run the benchmarks locally!\n\n## Populating the PostgreSQL Database with Benchmark Data\n\nAfter running benchmarks and generating report files, you can populate a PostgreSQL database with the results for further analysis. This process involves two main scripts: `generate_postgres_schema.py` to set up the database table, and `fill_postgres_db.py` to load the data.\n\n### 1. Setting up the Database Schema\n\nThe `generate_postgres_schema.py` script creates the necessary table in your PostgreSQL database to store the benchmark data.\n\n**Usage:**\n\n```sh\npython generate_postgres_schema.py \\\n    --db-host \u003cyour_db_host\u003e \\\n    --db-port \u003cyour_db_port\u003e \\\n    --db-user \u003cyour_db_user\u003e \\\n    --db-name \u003cyour_db_name\u003e \\\n    --table-name \u003ctarget_table_name\u003e \\\n    --log-level \u003cDEBUG|INFO|WARNING|ERROR|CRITICAL\u003e\n```\n\n-   You will be prompted to enter the password for the specified database user.\n-   `--table-name`: Defaults to `benchmark_data`.\n-   `--log-level`: Defaults to `INFO`.\n\n**Example:**\n\n```sh\npython generate_postgres_schema.py \\\n    --db-host localhost \\\n    --db-port 5432 \\\n    --db-user myuser \\\n    --db-name benchmarks \\\n    --table-name gas_benchmark_results\n```\n\nThis will create a table named `gas_benchmark_results` (if it doesn't already exist) in the `benchmarks` database.\n\n### 2. Populating the Database with Benchmark Data\n\nOnce the schema is set up, use `fill_postgres_db.py` to parse the benchmark report files (generated by `run.sh` or other means) and insert the data into the PostgreSQL table.\n\n**Usage:**\n\n```sh\npython fill_postgres_db.py \\\n    --reports-dir \u003cpath_to_reports_directory\u003e \\\n    --db-host \u003cyour_db_host\u003e \\\n    --db-port \u003cyour_db_port\u003e \\\n    --db-user \u003cyour_db_user\u003e \\\n    --db-password \u003cyour_db_password\u003e \\\n    --db-name \u003cyour_db_name\u003e \\\n    --table-name \u003ctarget_table_name\u003e \\\n    --log-level \u003cDEBUG|INFO|WARNING|ERROR|CRITICAL\u003e\n```\n\n-   `--reports-dir`: Path to the directory containing the benchmark output files (e.g., `output_*.csv`, `raw_results_*.csv`, and `index.html` or `computer_specs.txt`).\n-   `--db-password`: The password for the database user.\n-   `--table-name`: Should match the table name used with `generate_postgres_schema.py`. Defaults to `benchmark_data`.\n-   `--log-level`: Defaults to `INFO`.\n\n**Example:**\n\n```sh\npython fill_postgres_db.py \\\n    --reports-dir ./results/my_benchmark_run_01 \\\n    --db-host localhost \\\n    --db-port 5432 \\\n    --db-user myuser \\\n    --db-password \"securepassword123\" \\\n    --db-name benchmarks \\\n    --table-name gas_benchmark_results\n```\n\nThis script will scan the specified reports directory, parse the client benchmark data and computer specifications, and insert individual run records into the `gas_benchmark_results` table.\n\n## Continuous Metrics Posting\n\nA new script `run_and_post_metrics.sh` is available to run the benchmarks and post metrics continuously in an infinite loop.\nThis script updates the local repository with `git pull`, runs the benchmark tests, populates the PostgreSQL database, and cleans up the reports directory.\n\n**Usage:**\n\n```sh\n./run_and_post_metrics.sh --table-name gas_limit_benchmarks --db-user nethermind --db-host perfnet.core.nethermind.dev --db-password \"MyPass\" [--warmup warmup/warmup-1000bl-16wi-24tx.txt]\n```\n\n**Parameters:**\n\n- `--table-name`: The database table name where benchmark data will be inserted.\n- `--db-user`: The database user.\n- `--db-host`: The database host.\n- `--db-password`: The database password.\n- `--warmup`: (Optional) The warmup file to use. Defaults to `warmup/warmup-1000bl-16wi-24tx.txt`.\n\n**Examples:**\n\nUsing the default warmup file:\n```sh\n./run_and_post_metrics.sh --table-name gas_limit_benchmarks --db-user nethermind --db-host perfnet.core.nethermind.dev --db-password \"MyPass\"\n```\n\nUsing a custom warmup file and run in background:\n```sh\nnohup ./run_and_post_metrics.sh --table-name gas_limit_benchmarks --db-user nethermind --db-host perfnet.core.nethermind.dev --db-password \"MyPass\" --warmup \"warmup/custom_warmup.txt\" \u0026\n```\n\nPrevent creating of `nohup.txt` (to save disk space):\n```sh\nnohup ./run_and_post_metrics.sh --table-name gas_limit_benchmarks --db-user nethermind --db-host perfnet.core.nethermind.dev --db-password \"MyPass\" --warmup \"warmup/custom_warmup.txt\" \u003e /dev/null 2\u003e\u00261 \u0026\n```\n\n## Integration with EELS\n\n### Run the tests generated by the EELS framework\n\nBy default, gas-benchmarks replays Execution Layer Spec (EELS) payloads with the Kute runner.\n\nYou can use the [EELS repository](https://github.com/ethereum/execution-specs/tree/main/tests/benchmark) to produce new benchmark definitions and run them with the following steps:\n\n1. Place a genesis file inside `scripts/genesisfiles/YOUR_CLIENT`, for example:\n    - `scripts/genesisfiles/geth/chainspec.json`\n    - `scripts/genesisfiles/geth/zkevmgenesis.json`\n2. Capture EELS tests (writes payload files into `eest_tests/` by default):\n\n```\npython3 capture_eest_tests.py -o eest_tests -x 1M,worst_bytecode\n```\n\n- The capture script downloads the latest `benchmark@v*` release from the `execution-specs` repository. Ensure your new tests are included in a published benchmark release (or pass `--release-tag benchmark@vX.Y.Z`) before attempting to capture them.\n\n3. Generate warmup payloads that match the captured tests:\n\n```sh\npython3 make_warmup_tests.py -s eest_tests/ -d warmup-tests -g scripts/genesisfiles/geth/zkevmgenesis.json\n```\n\n4. Execute the tests: perform step 4 from \"Running the Benchmarks\" using `eest_tests/` as the test path and the warmup file generated in step 3:\n\n```\nbash run.sh -t \"eest_tests/\" -w \"warmup-tests\" -c \"client1,client2\" -r runNumber -i \"image1,image2\"\n```\n\nAll documentation now references `eest_tests/` as the canonical dataset; legacy `tests/` or `tests-vm/` folders are no longer shipped.\n\nTo author new EELS benchmarks, follow the guidance in the `execution-specs` repository under `tests/benchmark/`.\n\n### Execute the tests directly from the EELS repository\n\n1. Clone the EELS repository:\n\n```\ngit clone https://github.com/ethereum/execution-specs.git\ncd execution-specs\n```\n\n2. Create a virtual environment and install the dependencies:\n\n```\nuv sync --all-extras\n```\n\n3. Use [execute remote](https://github.com/ethereum/execution-specs/blob/main/docs/running_tests/execute/remote.md) to run the tests:\n\n```\nuv run execute remote -v --fork=Prague --rpc-seed-key=ACCOUNT --rpc-chain-id=1 --rpc-endpoint=http://127.0.0.1:8545 tests -- -m benchmark -n 1\n```\n\nNote: you will need an account with some ETH (native tokens) to run the tests. Specify the private key using `--rpc-seed-key`. Also, `--rpc-endpoint` should point to the node you want to test against (it may be a remote node).\n\n### EELS stateful tests generator\n\nThe EELS stateful generator creates deterministic, reproducible execution payloads by running Execution Layer Spec tests against a local Nethermind node through a proxy. It consists of two cooperating tools:\n\n- **`eest_stateful_generator.py`** - Main orchestrator that boots a Nethermind node from snapshot, runs EELS through a proxy, and captures payloads\n- **`mitm_addon.py`** - mitmproxy addon that intercepts transactions and produces engine payloads grouped by test metadata\n\nBasic usage:\n```\npython eest_stateful_generator.py \\\n    --chain mainnet \\\n    --fork Prague \\\n    --rpc-seed-key YOUR_PRIVATE_KEY \\\n    --rpc-address YOUR_ADDRESS \\\n    --test-path tests\n```\n\nThe tool writes `mitm_config.json` automatically (edit it if you need to tweak defaults). A generated example looks like:\n```\n{\n  \"rpc_direct\": \"http://127.0.0.1:8545\",\n  \"engine_url\": \"http://127.0.0.1:8551\",\n  \"jwt_hex_path\": \"engine-jwt/jwt.hex\",\n  \"finalized_block\": \"0x...\"\n}\n```\n\n**Key notes:**\n\n- The generator automatically handles node setup, health checks, JWT authentication, and cleanup.\n- It uses OverlayFS for ephemeral node state (no mutation of base snapshot, the snapshot can be downloaded once and reused)\n- Requires custom Nethermind image: `nethermindeth/nethermind:gp-hacked`\n- Produces deterministic engine payloads without triggering reorgs\n\n**Additional options:**\n\n- `--chain`: Target network (mainnet, sepolia, holesky, goerli or ethereum (perfnet))\n- `--no-snapshot`: Skip snapshot download\n- `--keep`: Preserve containers and logs after completion\n- `--refresh-snapshot`: Force re-download of snapshot\n\nImportant: This feature is still in development (See [PR description](https://github.com/NethermindEth/gas-benchmarks/pull/57)). The script writes `mitm_config.json` automatically; edit it only if you need to customize the generated values.\n\n#### Opcode Tracing\n\nThe generator supports opcode tracing to capture which opcodes are executed during each test. This is useful for analyzing gas consumption patterns and test coverage.\n\n**Generate opcode trace JSON:**\n\n```sh\npython eest_stateful_generator.py \\\n     --data-dir scripts/nethermind/execution-data \\\n     --genesis-path scripts/genesisfiles/nethermind/zkevmgenesis.json \\\n     --nethermind-image nethermindeth/nethermind:gp-hacked \\\n     --fork Prague \\\n     --rpc-seed-key SOMEKEY \\\n     --rpc-address SOMEADDRESS \\\n     --payload-dir repricings_compute \\\n     --eest-repo https://github.com/spencer-tb/execution-specs \\\n     --eest-branch feat/fixed-opcode-count-updates \\\n     --gas-bump-count 0 \\\n     --trace-json \\\n     --trace-json-output results.json\n```\n\n**Options:**\n\n- `--trace-json`: Enable opcode tracing and generate JSON output mapping tests to opcode counts.\n- `--trace-json-output`: Output path for the opcode trace results JSON.\n\n**Output format:**\n\nThe generated JSON file contains a mapping of test names to their opcode execution counts:\n\n```json\n{\n  \"test_arithmetic.py__test_arithmetic[fork_Prague-benchmark_test-opcode_ADD-opcount_1.0K]\": {\n    \"ADD\": 1000,\n    \"PUSH1\": 28,\n    \"JUMPDEST\": 8,\n    \"STOP\": 1,\n    ...\n  },\n  ...\n}\n```\n\n### Populating Test Metadata Database\n\nAfter generating opcode trace results, you can populate a PostgreSQL database with the test metadata for Grafana visualization.\n\n**Usage:**\n\n```sh\npython fill_tests_metadata_db.py \\\n    --json-file results.json \\\n    --db-host \u003cyour_db_host\u003e \\\n    --db-port \u003cyour_db_port\u003e \\\n    --db-user \u003cyour_db_user\u003e \\\n    --db-password \u003cyour_db_password\u003e \\\n    --db-name \u003cyour_db_name\u003e \\\n    --table-name \u003ctarget_table_name\u003e\n```\n\n**Parameters:**\n\n- `--json-file`: Path to the JSON file containing opcode metrics (e.g., `results.json`).\n- `--db-host`: PostgreSQL database host.\n- `--db-port`: PostgreSQL database port (default: 5432).\n- `--db-user`: PostgreSQL database user.\n- `--db-password`: PostgreSQL database password.\n- `--db-name`: PostgreSQL database name.\n- `--table-name`: Name of the table to store metrics (default: `test_metadata`).\n- `--clear-existing`: Optional flag to truncate existing data before importing.\n- `--log-level`: Set logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL).\n\n**Example:**\n\n```sh\npython fill_tests_metadata_db.py \\\n    --json-file results_fixed.json \\\n    --db-host localhost \\\n    --db-port 5432 \\\n    --db-user myuser \\\n    --db-password \"securepassword123\" \\\n    --db-name benchmarks \\\n    --table-name gas_limit_benchmarks_test_metadata\n```\n\n**Database Schema:**\n\nThe script creates a table with the following structure:\n\n```sql\nCREATE TABLE test_metadata (\n    id SERIAL PRIMARY KEY,\n    test_name TEXT UNIQUE NOT NULL,\n    opcodes JSONB NOT NULL,\n    created_at TIMESTAMP DEFAULT NOW(),\n    updated_at TIMESTAMP DEFAULT NOW()\n)\n```\n\n**Update Behavior:**\n\nWhen running the script multiple times:\n\n- Tests that exist in the database and the new JSON file will have their `opcodes` updated and `updated_at` timestamp refreshed.\n- Tests that exist in the database but not in the new JSON file remain unchanged.\n- New tests are inserted with both `created_at` and `updated_at` set to the current time.\n\n**Grafana Queries:**\n\nExample queries for visualizing opcode data in Grafana:\n\n```sql\n-- Get all opcodes for a specific test\nSELECT test_name, key as opcode, value::int as count\nFROM gas_limit_benchmarks_test_metadata, jsonb_each_text(opcodes)\nWHERE test_name LIKE '%SELFBALANCE%';\n\n-- Top opcodes by total usage across all tests\nSELECT key as opcode, SUM(value::int) as total_count\nFROM gas_limit_benchmarks_test_metadata, jsonb_each_text(opcodes)\nGROUP BY key\nORDER BY total_count DESC\nLIMIT 20;\n\n-- Compare specific opcodes across tests\nSELECT test_name,\n       opcodes-\u003e\u003e'ADD' as \"ADD\",\n       opcodes-\u003e\u003e'MUL' as \"MUL\",\n       opcodes-\u003e\u003e'SLOAD' as \"SLOAD\"\nFROM gas_limit_benchmarks_test_metadata\nWHERE opcodes ? 'ADD'\nORDER BY (opcodes-\u003e\u003e'ADD')::int DESC;\n```\n\nContributing: see [CONTRIBUTING.md](CONTRIBUTING.md)\n\n## Reusable GitHub Action: `gas-benchmark-action`\n\nYou can trigger gas-benchmarks from another repository using the composite action defined in this repo at `.github/actions/gas-benchmark-action/action.yml`.\n\n### Usage from an external repository\n\nCreate a workflow in your repository, for example `.github/workflows/gas-benchmarks.yml`:\n\n```yaml\nname: Run gas benchmarks\n\non:\n  workflow_dispatch:\n    inputs:\n      runs:\n        description: Number of benchmark runs\n        required: false\n        default: 1\n\njobs:\n  gas-benchmarks:\n    runs-on: ubuntu-latest # default runner; override to change VM\n\n    steps:\n      # 1. Checkout the repository with LFS enabled\n      - name: Checkout gas-benchmarks repository\n        uses: actions/checkout@v4\n        with:\n          repository: NethermindEth/gas-benchmarks\n          ref: main # or specific branch/tag\n          lfs: true # Critical for downloading genesis files correctly\n\n      # 2. Run the local action from the checkout path\n      - name: Run gas-benchmarks composite action\n        uses: ./.github/actions/gas-benchmark-action\n        with:\n          # Benchmark configuration (all optional, with sensible defaults)\n          testPath: eest_tests\n          genesisFile: zkevmgenesis.json\n          warmupFile: warmup/warmup-1000bl-16wi-24tx.txt\n          clients: nethermind,geth,reth,besu,erigon,nimbus,ethrex\n          runs: ${{ github.event.inputs.runs }}\n          opcodeWarmupCount: '1'\n          filter: ''\n          images: '{\"nethermind\":\"default\",\"geth\":\"default\",\"reth\":\"default\",\"erigon\":\"default\",\"besu\":\"default\",\"nimbus\":\"default\",\"ethrex\":\"default\"}'\n\n          # PostgreSQL target (no DB is provisioned by this workflow)\n          # Leave empty to disable database posting\n          postgresHost: perfnet.core.nethermind.dev\n          postgresPort: '5432'\n          postgresDbName: monitoring\n          postgresTable: gas_benchmarks_ci\n\n          # DB credentials passed from your repository secrets\n          postgresUser: ${{ secrets.PERFNET_DB_USER }}\n          postgresPassword: ${{ secrets.PERFNET_DB_PASSWORD }}\n```\n\n### Inputs\n\n- **testPath** (string, default `eest_tests`): Path to benchmark tests relative to the `gas-benchmarks` repo.\n- **genesisFile** (string, default `zkevmgenesis.json`): Genesis file name resolved under `scripts/genesisfiles/\u003cclient\u003e/`.\n- **warmupFile** (string, default `warmup/warmup-1000bl-16wi-24tx.txt`): Warmup payload file; set to empty string to disable warmup.\n- **clients** (string, default `nethermind,geth,reth,besu,erigon,nimbus,ethrex`): Comma-separated client list.\n- **runs** (string, default `'1'`): Number of benchmark iterations.\n- **opcodeWarmupCount** (string, default `'1'`): Per-scenario opcode warmup loops.\n- **filter** (string, default empty): Comma-separated case-insensitive substrings; only matching scenarios are executed.\n- **images** (string, default JSON map of `default` tags): JSON map of client → image tag, same format as `multi-parallel.yml`.\n- **txtReport** (string, default `'false'`): When set to `'true'`, also generates a TXT report via `report_txt.py`.\n- **postgresHost** (string, optional, default empty): When non-empty, enables posting metrics to PostgreSQL.\n- **postgresPort** (string, default `5432`): PostgreSQL port.\n- **postgresDbName** (string, optional, default empty): PostgreSQL database name.\n- **postgresTable** (string, optional, default empty): Target table name in the database.\n\n### Secrets\n\n- **postgresUser** (optional, default empty): PostgreSQL username, passed as a GitHub Actions secret.\n- **postgresPassword** (optional, default empty): PostgreSQL password, passed as a GitHub Actions secret.\n\n### Behavior and prerequisites\n\n- **Single run per trigger**: The reusable workflow runs a single benchmark job per invocation (no parallel matrix), but can execute multiple clients in one `run.sh` call.\n- **Preconditions**: The workflow clones `NethermindEth/gas-benchmarks`, installs Python dependencies from `requirements.txt`, runs `make prepare_tools`, and then calls `run.sh` with the provided inputs.\n- **PostgreSQL (optional)**: If `postgresHost` is left empty, no database writes are attempted and only artifacts are produced. If any PostgreSQL-related input is provided, the action validates that `postgresHost`, `postgresDbName`, `postgresTable`, `postgresUser`, and `postgresPassword` are all non-empty before calling `fill_postgres_db.py`; otherwise, it fails fast with a clear error.\n- **Artifacts**: The `reports/`, `reports.zip`, and `results/` directories are uploaded as a single `gas-benchmarks-outputs` artifact for further inspection in the caller repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnethermindeth%2Fgas-benchmarks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnethermindeth%2Fgas-benchmarks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnethermindeth%2Fgas-benchmarks/lists"}