Skip to content

cartesi-rollups-cli hardcodes a 30M gas limit, breaking transactions on networks with a lower per-tx gas cap #786

Description

@vfusco

Summary

When sending transactions, the CLI/ethutil package hardcodes the gas limit to 30_000_000 instead of letting go-ethereum estimate it. On networks (testnets / L2s) that enforce a maximum gas-per-transaction below 30M, the node rejects the transaction during pre-flight validation with exceeds max transaction gas limit, so it never reaches a block. The fix is to default to gas estimation and expose an optional override flag.

Current behavior

pkg/ethutil/ethutil.go defines a fixed constant:

// Gas limit when sending transactions.
const GasLimit = 30_000_000

Every write path (AddInput, AddInputAsync, ExecuteOutput) forwards this constant, and pkg/ethutil/transaction.go writes it unconditionally onto the transaction options:

// _prepareTransaction
txOpts.GasLimit = gasLimit   // always 30_000_000
txOpts.GasPrice = gasPrice

Because go-ethereum's bind package only runs gas estimation when TransactOpts.GasLimit == 0, setting a non-zero value here disables estimation entirely and forces the fixed 30M onto every transaction. 30_000_000 happens to be Ethereum mainnet's block gas limit, which is fine on Anvil/Foundry but too high for networks that cap per-transaction gas below that.

Relevant code:

  • pkg/ethutil/ethutil.go#L23-L24 (the constant)
  • pkg/ethutil/transaction.go#L46-L68 (_prepareTransaction setting the limit)

Steps to reproduce

Against a testnet/L2 whose per-transaction gas cap is below 30M:

$ cartesi-rollups-cli execute tester 12 --yes
Error: failed to send transaction: exceeds max transaction gas limit

$ cartesi-rollups-cli send tester 0x68656c6c6f --hex --yes
Error: failed to send transaction: exceeds max transaction gas limit

Both commands fail identically: executeExecuteOutput, sendAddInput, both routed through sendTransaction with the same hardcoded GasLimit.

Root cause

The hardcoded GasLimit = 30_000_000 exceeds the maximum gas allowed per transaction on the target network. The node rejects it at the RPC/txpool validation step (before execution), so this is not a revert, an out-of-gas, or an insufficient-funds error — it's the network refusing a transaction whose declared gas limit is too high.

Proposed fix

  1. Default to estimation. Stop setting a fixed gas limit; leave TransactOpts.GasLimit = 0 so go-ethereum's bind runs eth_estimateGas (simulating against pending state) and picks an appropriate limit per transaction and per network. Concretely, drop the txOpts.GasLimit = gasLimit assignment (or set it to 0) in _prepareTransaction for the default path.
  2. Add an optional override. Expose a --gas-limit flag (and/or an env var) on the relevant CLI commands. When provided and > 0, set TransactOpts.GasLimit to that value (skipping estimation); when omitted, fall through to estimation. This preserves the ability to force a fixed limit when needed.

Additional considerations

  • Enabling estimation slightly changes the error surface: a transaction that would always revert now fails earlier at the eth_estimateGas step instead of after submission. This is generally an improvement (bad transactions are caught before broadcast), but worth noting for anyone parsing error strings.
  • Optionally apply a small safety margin on top of the estimate (e.g. estimate × 1.1) to absorb minor state changes between estimation and inclusion. go-ethereum already allows a tiny overestimate, so this is a refinement rather than a requirement.
  • AddInputAsync already carries a note about serializing nonce assignment; switching to estimation adds one extra RPC round-trip (eth_estimateGas) per call, which is fine for normal use but worth keeping in mind for the load-testing path.

Acceptance criteria

  • Transactions sent by the CLI succeed on networks whose per-transaction gas cap is below 30M (no more exceeds max transaction gas limit).
  • Gas limit is estimated by default when no override is provided.
  • A --gas-limit flag (and/or env var) allows forcing a fixed limit.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions