HIP-1249: Precise Smart Contract Throttling
Author | Richard Bair |
---|---|
Working Group | Richard Bair, Luke Lee |
Discussions-To | https://github.com/hiero-ledger/hiero-improvement-proposals/pull/1249 |
Status | Last Call ⓘ |
Last Call Period Ends ⓘ | Wed, 13 Aug 2025 07:00:00 +0000 |
Type | Standards Track ⓘ |
Category | Core ⓘ |
Created | 2025-06-30 |
Updated | 2025-08-04 |
Replaces | 185 |
Table of Contents
Abstract
This proposal introduces a new throttling mechanism for smart contracts on the Hiero network to replace the current gas-per-second limit. By shifting from gas-based throttling to an operations-per-second (ops/sec) model, the network can support significantly higher throughput for smart contract execution—potentially an order of magnitude more than the current 15 million gas/sec default—while maintaining security and compatibility with Ethereum tools. Gas will continue to be used for user billing, but throttling will rely on a separate, measured cost for each EVM opcode, precompile, and system contract to better reflect actual computational demands.
Motivation
Smart contracts on Hiero run within an Ethereum Virtual Machine (EVM) environment, where each low-level operation ( opcode) consumes a fixed or calculated amount of “gas.” This gas serves two purposes: it limits how much work a contract can do in a single execution, and it determines the cost to the user. Hiero adopts the same gas values as Ethereum to ensure compatibility with popular development tools like Forge and Reth.
However, gas is only a rough estimate of the real time and resources needed for an operation. Tests on Hiero show wide variation: some opcodes allow as little as 35-40 million gas/sec, while others, like those accessing the efficient Merkle database (SLOAD and SSTORE), permit nearly a billion gas/sec. Because the network must protect against worst-case scenarios—such as an attacker crafting a contract that exploits slower opcodes—the current throttle is set conservatively at 15 million gas/sec (half of the measured 30 million gas/sec minimum for safety).
This limit underutilizes the network’s potential. Real-world applications, like a port of Uniswap tested on Hiero, achieve over 150 million gas/sec. Ethereum itself allows variable gas per block (introduced in EIP-1559), providing more flexibility than Hiero’s fixed limits.
This proposal keeps gas for billing but introduces a separate “ops cost” for throttling. Each opcode’s ops cost is derived from real performance measurements, plus a safety margin. This allows the network to approach its full capacity for typical workloads, boosting overall performance without compromising safety.
Rationale
Solutions must preserve Ethereum compatibility and network security while increasing performance. Changing gas calculations would break tools like Forge, which simulate using Reth. Wall-clock timing is non-deterministic and unsuitable for consensus.
Ops-based throttling decouples billing (gas) from limits (ops), using deterministic, pre-measured costs. Future enhancements could include dynamic ops costs, but static configuration suffices initially, similar to other Hiero throttles.
Specification
Overview
- Remove the existing gas/sec throttle from both frontend (ingest) and backend (consensus) layers.
- Introduce a new ops/sec throttle exclusively on the backend (consensus) layer.
- Provide network-specific configuration for the ops cost of each EVM opcode and precompile, based on hardware benchmarks.
- For each system contract, calculate and introduce the ops cost based on hardware benchmarks.
- During smart contract execution:
- Calculate gas as before for user billing.
- Separately track ops units for throttling.
- Bill users based on Ethereum-equivalent gas used, eliminating the prior 80% minimum charge rule (which required billing at least 80% of the transaction’s gas limit).
- Retain per-transaction gas limits (e.g., default 15 million gas/tx) to prevent unbounded individual transactions.
No changes are required to the Hiero API (HAPI) specifications.
Throttles in Detail
The gas/sec throttle is fully removed. In its place, an ops/sec throttle applies only at consensus (backend). This avoids pre-execution checks, as smart contract costs depend on runtime state and are expensive to simulate upfront.
Hiero’s hashgraph consensus orders events before revealing transactions, unlike Ethereum’s block construction where transactions are selected to fit gas limits. Thus, Hiero cannot mimic Ethereum’s mempool behavior exactly: excess transactions fail at execution rather than waiting.
Under this proposal:
- Frontend ingest allows smart contract calls up to the network’s TPS limit, without gas-based throttling.
- Each transaction specifies a gas limit (must not exceed network maximum).
- At execution:
- Ops units are deducted from the throttle bucket based on executed opcodes.
- If the bucket is exhausted, remaining transactions fail with THROTTLED_AT_CONSENSUS and incur only the intrinsic gas fee (covering network costs).
This maintains the current behavior where over-submitted transactions may fail and incur fees, but improves overall capacity.
Performance Considerations
Tracking both gas and ops units adds minor overhead to EVM execution. Implementations should optimize this, such as by using efficient lookups for ops costs.
Tracking ops for precompiles and system calls adds negligible overhead, as costs are computed via simple lookups or formulas during execution. Benchmarks should minimize this in implementation.
Gas-Limit and Billing
Remove the 80% minimum charge, aligning closer to Ethereum. Users pay exactly for gas used, up to their specified limit. All gas handling, including refunds, work exactly as they do in Ethereum (for example, see EIP-3529).
Execution Outcomes
When processing a transaction:
- If ops/sec throttle is exhausted before starting: Charge intrinsic gas fee; fail with out-of-block-space error (do not even start the EVM).
- If throttle allows start and transaction completes: Charge user for gas used; deduct ops from throttle.
- If throttle exhausts mid-execution: Charge intrinsic gas fee only; fail with out-of-block-space error (no partial billing).
- If gas limit exhausts before ops throttle: Fail with out-of-gas; charge full gas used; deduct ops for work done.
Configuration
The ops/sec throttle configuration will be supplied as properties in the network, as part of file 0.0.121. Each throttle is defined as:
contracts.evm.opcost.[opcode]
with a value measured in nanoseconds (existing).contracts.evm.opcost.[precompile|contract].[address].[function]
with a value or formula in nanoseconds. For example:- Fixed:
contracts.evm.opcost.precompile.0x01.ecrecover = 5000
(ns for ECRECOVER). - Variable: Use parametric properties, e.g.,
contracts.evm.opcost.contract.0x167.transfer.base
= 10000 andcontracts.evm.opcost.contract.0x167.transfer.per_token
= 500 (for HTS transfer).
- Fixed:
Networks benchmark each precompile function and system call on representative hardware:
- Run isolated tests (e.g., loop calling the function with varied inputs).
- Record average or worst-case execution time in ns.
- Add a safety margin (e.g., 20-50%).
- For variable costs, derive formulas from benchmarks (e.g., linear regression on input size).
- Select the maximum value across hardware configs for conservatism.
Precompiles and System Contract Calls
Precompiles and system contracts must contribute to the ops/sec throttle to prevent overload from compute-intensive operations not covered by other throttles.
- Measurement: Treat as “super opcodes”—benchmark execution time offline, as with opcodes.
- Application: When a contract invokes a precompile or system call:
- Compute gas as before for billing.
- Separately compute ops units based on configured values/formulas and inputs (e.g., data length, token count).
- Deduct from the ops throttle bucket.
- Variability: For dynamic costs (e.g., HTS mint based on amount), use input-based formulas to ensure determinism.
- Safety: This closes loops like repeated pure-compute calls (e.g., hashing). Operations tied to HAPI throttles ( e.g., account creation) gain layered protection but are still ops-throttled for compute.
If a precompile/system call exhausts ops mid-transaction, handle as in Execution Outcomes.
Backwards Compatibility
This change is backward-compatible for developers:
- Gas calculations remain identical.
- Transactions with existing gas limits work as before, potentially with lower costs (no 80% minimum).
- Failed transactions due to throttling behave similarly, though with higher overall network capacity.
Networks must update configurations and test thoroughly. No protocol or API changes affect existing contracts or tools.
Security Implications
Networks must accurately benchmark opcode costs on representative hardware, using the highest measured time plus a margin to account for variability. This mirrors existing throttle configurations.
To mitigate denial-of-service:
- Set TPS limits for contract calls to handle post-throttle-exhaustion traffic without overload.
- For underfunded transactions: Use the minimum of specified gas limit and
transactionFee
converted to gas. If insufficient, charge up to the user’stransactionFee
. - Batch transactions: Handle partial failures similarly, charging for completed steps.
These measures prevent attackers from consuming throttle without cost. System contracts are included in ops throttling to avoid unaccounted overhead.
Include precompiles and system calls in benchmarks to cover all execution paths. For variable ops, formulas should use worst-case assumptions where inputs could vary. Networks must validate configs against attack scenarios, such as tight loops on compute-heavy precompiles (e.g., cryptography). Combined with TPS limits and per-service throttles, this ensures no single contract can overload nodes.
How to Teach This
Educate developers on key changes:
- Simplified Billing: No more 80% minimum charge—pay only for gas used. This reduces costs for overestimated limits and eases gas estimation.
- Throttle Failures: Transactions may still fail due to exhausted ops/sec (error: THROTTLED_AT_CONSENSUS), even if valid. Advise retry logic and monitoring network load.
- Performance Gains: Highlight potential for faster, higher-throughput applications without code changes.
- Precompile/System Call Costs: Explain that these now factor into throttling for better performance limits. Developers using HTS or crypto functions should note potential failures if ops exhaust, but no code changes needed—retry as with other throttles.
Provide updated documentation, examples, and tools for estimating ops costs in testing environments.
Citation
Please cite this document as: