Block gas limit, numbers and time
With the release of Arbitrum Orbit, Arbitrum chains can now be L2s that settle to Ethereum (or one of their testnets), or L3s that settle to one of the Arbitrum L2 chains. For simplicity, in this page we speak in terms of Arbitrum One (L2) and Ethereum (L1), but the same logic can be applied to any chain and its parent chain.
As in Ethereum, Arbitrum clients submit transactions, and the system executes those transactions at some later time. In Arbitrum, clients submit transactions by posting messages to the Ethereum chain, either through the sequencer or via the chain's delayed inbox.
Once in the chain's core inbox contract, transactions are processed in order. Generally, some time will elapse between when a message is put into the inbox (and timestamped) and when the contract processes the message and carries out the transaction requested by the message.
Additionally, since the calldata of Arbitrum transactions (or the DAC certificate on AnyTrustchains) is posted to Ethereum, the gas paid when executing them includes an L1 component to cover the costs of the batch poster.
This page describes what this mechanism means for the block gas limit, block numbers, and the time assumptions of the transactions submitted to Arbitrum.
Block gas limit
When submitting a transaction to Arbitrum, users are charged for both the execution cost on Arbitrum and the cost of posting its calldata to Ethereum. This dual cost structure is managed by adjusting the transaction's gas limit to reflect these two dimensions, resulting in a higher gas limit value than what would be seen for pure execution.
The gas limit of an Arbitrum block is set as the sum of all transaction gas limits, including the costs related to L1 data posting. To accommodate potential variations in L1 costs, Arbitrum assigns an artificially large gas limit (1,125,899,906,842,624) for each block. However, the effective execution gas limit is capped at 32 million. This means that while the visible gas limit might appear very high, the actual execution costs are constrained within this limit. Understanding this distinction helps clarify why querying a block might show an inflated gas limit that doesn’t match the effective execution costs.
For a more detailed breakdown of the gas model, refer to this article on Arbitrum's 2-dimensional fee structure.
Block numbers: Arbitrum vs. Ethereum
Arbitrum blocks are assigned their own L2 block numbers, distinct from Ethereum's block numbers.
A single Ethereum block could include multiple Arbitrum blocks within it; however, an Arbitrum block cannot span across multiple Ethereum blocks. Thus, any given Arbitrum transaction is associated with exactly one Ethereum block and one Arbitrum block.
Ethereum block numbers within Arbitrum
Accessing block numbers within an Arbitrum smart contract (i.e., block.number
in Solidity) will return a value close to (but not necessarily exactly) the L1 block number at which the sequencer received the transaction.
// some Arbitrum contract:
block.number // => returns L1 block number ("ish")
As a general rule, any timing assumptions a contract makes about block numbers and timestamps should be considered generally reliable in the longer term (i.e., on the order of at least several hours) but unreliable in the shorter term (minutes). (It so happens these are generally the same assumptions one should operate under when using block numbers directly on Ethereum!)
Arbitrum block numbers
Arbitrum blocks have their own block numbers, starting at 0 at the Arbitrum genesis block and updating sequentially.
ArbOS and the sequencer are responsible for delineating when one Arbitrum block ends and the next one begins. However, block creation depends entirely on chain usage, meaning that blocks are only produced when there are transactions to sequence. In active chains, one can expect to see Arbitrum blocks produced at a relatively steady rate. In more quiet chains, block production might be sporadic depending on the rate at which transactions are received.
A client that queries an Arbitrum node's RPC interface (for, e.g., transaction receipts) will receive the transaction's Arbitrum block number as the standard block number field. The L1 block number will also be included in the added l1BlockNumber field
.
const txnReceipt = await arbitrumProvider.getTransactionReceipt('0x...');
/**
txnReceipt.blockNumber => Arbitrum block number
txnReceipt.l1BlockNumber => L1 block number ("ish")
*/
The Arbitrum block number can also be retrieved within an Arbitrum contract via ArbSys precompile:
ArbSys(100).arbBlockNumber() // returns Arbitrum block number