diff --git a/docs/base-chain/network-information/block-building.mdx b/docs/base-chain/network-information/block-building.mdx index 99ec7866b..6c1d7d2f9 100644 --- a/docs/base-chain/network-information/block-building.mdx +++ b/docs/base-chain/network-information/block-building.mdx @@ -13,8 +13,8 @@ The Base networks are currently configured in the following ways: | Network | Current Configuration | Upcoming Deployments | |--------------|-----------------------------|------------------------| -| Base Mainnet | [Flashblocks](#flashblocks) + [Per-Transaction Gas Max](#per-transaction-gas-maximum) | | -| Base Sepolia | [Flashblocks](#flashblocks) + [Per-Transaction Gas Max](#per-transaction-gas-maximum) | | +| Base Mainnet | [Flashblocks](#flashblocks) + [Per-Transaction Gas Max](#per-transaction-gas-maximum) | [Resource Metering](#resource-metering) | +| Base Sepolia | [Flashblocks](#flashblocks) + [Per-Transaction Gas Max](#per-transaction-gas-maximum) | [Resource Metering](#resource-metering) | See the [Configuration Changelog](/base-chain/network-information/configuration-changelog) for a history of changes to block building and other network parameters. @@ -48,6 +48,12 @@ Fusaka's [EIP 7825](https://eips.ethereum.org/EIPS/eip-7825) **will** change the Bundler operators for smart contract wallets must configure their systems to limit the bundle size to fit within this cap. +### Resource metering + +In addition to existing gas and DA limits, Base measures the **execution time** and **state root time** of each transaction. The block builder uses these measurements to enforce time-based resource limits that gas alone cannot express — for example, a single precompile call can consume hundreds of milliseconds of CPU while using a fraction of the gas limit. + +When resources are constrained, transactions are included in priority fee order — higher-paying transactions are included first. You can query the recommended priority fee for your transaction using the `base_meteredPriorityFeePerGas` RPC method. See [Resource Metering](/base-chain/network-information/resource-metering) for details. + ### Vanilla Blocks are built every 2s by [op-geth](https://github.com/ethereum-optimism/op-geth). Transactions within those blocks are ordered by diff --git a/docs/base-chain/network-information/resource-metering.mdx b/docs/base-chain/network-information/resource-metering.mdx new file mode 100644 index 000000000..7eecc3e82 --- /dev/null +++ b/docs/base-chain/network-information/resource-metering.mdx @@ -0,0 +1,221 @@ +--- +title: Resource Metering +description: Learn how Base measures transaction resource usage and how to set priority fees for reliable block inclusion. +--- + +## Overview + +Blocks and flashblocks are already constrained by **gas** and **data availability (DA)** limits. Resource metering adds two new dimensions: **execution time** and **state root time** — wall-clock measurements of how long each transaction takes to execute and how long its state root computation takes. These new dimensions let the builder enforce time-based limits that gas alone cannot express. + +The `base_meteredPriorityFeePerGas` RPC method estimates the priority fee needed for inclusion across all four resource dimensions, not just gas. This lets you set fees that account for execution time and DA pressure, not just block fullness. + +Resource metering affects you in two ways: + +1. **Transactions that consume excessive resources may be skipped for inclusion.** If your transaction uses a disproportionate amount of execution time relative to its gas usage, it may be skipped even if its gas-based priority fee would normally be sufficient. +2. **You can query the recommended priority fee for your transaction.** The `base_meteredPriorityFeePerGas` RPC method simulates your transaction and returns the priority fee needed to get included based on recent block congestion across all resource types. + +## Impact on bundlers + +ERC-4337 bundlers are particularly affected by resource metering. Previously, fitting within the block's gas limit was the main constraint for getting a bundle included. Resource metering adds new dimensions: not only does the gas have to fit, but the execution time and state root time must also fit within per-block limits. This makes large, multi-operation bundles harder to include than before. + +Bundler operators can mitigate this by: + +- **Sending single-transaction bundles** to reduce per-bundle resource consumption. +- **Metering transactions before including them in bundles** to identify and exclude UserOperations that consume disproportionate resources. +- **Using `base_meteredPriorityFeePerGas`** to set the priority fee high enough for the bundle to be included based on actual resource usage. + +## Get a recommended priority fee + +The `base_meteredPriorityFeePerGas` RPC method simulates a bundle of transactions and returns a recommended priority fee based on recent block congestion. It evaluates all resource types independently and returns the highest fee across them. + +### Request + +Send a JSON-RPC request with a single `bundle` object: + +```json title="Example request" +{ + "jsonrpc": "2.0", + "id": 1, + "method": "base_meteredPriorityFeePerGas", + "params": [ + { + "txs": ["0x02f86c..."], + "blockNumber": "0x0" + } + ] +} +``` + +#### Bundle parameters + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `txs` | `Bytes[]` | Yes | RLP-encoded signed transactions (EIP-2718 envelopes) | +| `blockNumber` | `quantity` | Yes | Target block number (hex). Use `0x0` for the current block. | +| `flashblockNumberMin` | `quantity` | No | Earliest flashblock index for inclusion | +| `flashblockNumberMax` | `quantity` | No | Latest flashblock index for inclusion | +| `minTimestamp` | `quantity` | No | Earliest block timestamp for inclusion | +| `maxTimestamp` | `quantity` | No | Latest block timestamp for inclusion | +| `revertingTxHashes` | `TxHash[]` | No | Transaction hashes allowed to revert without failing the bundle | +| `replacementUuid` | `string` | No | UUID for replacing a previously submitted bundle | +| `droppingTxHashes` | `TxHash[]` | No | Transaction hashes to drop from the pool | + +### Response + +The response includes the priority fee recommendation alongside full bundle simulation results. + +#### Top-level fields + +| Field | Type | Description | +|-------|------|-------------| +| `priorityFee` | `quantity` | Recommended priority fee per gas (hex). This is the maximum across all resource types. | +| `blocksSampled` | `integer` | Number of recent blocks used for the estimate. `0` means no historical data was available. | +| `resourceEstimates` | `ResourceEstimate[]` | Per-resource fee breakdown | +| `totalGasUsed` | `integer` | Total gas consumed by all transactions | +| `totalExecutionTimeUs` | `integer` | Total EVM execution time in microseconds | +| `stateRootTimeUs` | `integer` | Time to compute the state root in microseconds | +| `stateBlockNumber` | `integer` | Block number used for simulation state | +| `stateFlashblockIndex` | `integer` | Flashblock index used for simulation state (omitted if not applicable) | +| `results` | `TransactionResult[]` | Per-transaction simulation results | +| `bundleGasPrice` | `quantity` | Effective gas price of the bundle | +| `bundleHash` | `hash` | Hash of the bundle | +| `coinbaseDiff` | `quantity` | Total change in sequencer balance | +| `ethSentToCoinbase` | `quantity` | ETH explicitly sent to the sequencer | +| `gasFees` | `quantity` | Total gas fees paid by the bundle | + +#### Resource estimates + +Each entry in `resourceEstimates` describes the fee threshold for a single resource type. + +| Field | Type | Description | +|-------|------|-------------| +| `resource` | `string` | Resource name: `"gasUsed"`, `"executionTime"`, `"stateRootTime"`, or `"dataAvailability"` | +| `thresholdPriorityFee` | `quantity` | Minimum fee to displace enough lower-paying transactions to free capacity for the bundle | +| `recommendedPriorityFee` | `quantity` | Fee with a safety margin above the threshold | +| `cumulativeUsage` | `quantity` | Total resource usage of transactions that would remain included alongside the bundle | +| `thresholdTxCount` | `integer` | Number of higher-paying transactions that would be included alongside the bundle | +| `totalTransactions` | `integer` | Total transactions considered in the estimate | + +#### Transaction results + +Each entry in `results` describes the simulation outcome for one transaction. + +| Field | Type | Description | +|-------|------|-------------| +| `txHash` | `hash` | Transaction hash | +| `fromAddress` | `address` | Sender address | +| `toAddress` | `address` | Recipient address (`null` for contract creation) | +| `gasUsed` | `integer` | Gas consumed | +| `gasPrice` | `quantity` | Effective gas price | +| `gasFees` | `quantity` | Gas fees paid | +| `coinbaseDiff` | `quantity` | Change in sequencer balance from this transaction | +| `ethSentToCoinbase` | `quantity` | ETH explicitly sent to the sequencer | +| `value` | `quantity` | ETH value transferred | +| `executionTimeUs` | `integer` | Execution time in microseconds | + +### Example response + +```json title="Example response" lines expandable +{ + "priorityFee": "0x5f5e100", + "blocksSampled": 12, + "resourceEstimates": [ + { + "resource": "gasUsed", + "thresholdPriorityFee": "0x3b9aca00", + "recommendedPriorityFee": "0x5f5e100", + "cumulativeUsage": "0x1e8480", + "thresholdTxCount": 5, + "totalTransactions": 10 + }, + { + "resource": "executionTime", + "thresholdPriorityFee": "0x2540be400", + "recommendedPriorityFee": "0x2540be400", + "cumulativeUsage": "0xf4240", + "thresholdTxCount": 8, + "totalTransactions": 10 + }, + { + "resource": "dataAvailability", + "thresholdPriorityFee": "0x1", + "recommendedPriorityFee": "0x1", + "cumulativeUsage": "0x2710", + "thresholdTxCount": 10, + "totalTransactions": 10 + } + ], + "bundleGasPrice": "0x3b9aca00", + "bundleHash": "0xabc123...", + "coinbaseDiff": "0x4a817c800", + "ethSentToCoinbase": "0x0", + "gasFees": "0x4a817c800", + "results": [ + { + "txHash": "0xdef456...", + "fromAddress": "0x1111111111111111111111111111111111111111", + "toAddress": "0x2222222222222222222222222222222222222222", + "gasUsed": 21000, + "gasPrice": "0x3b9aca00", + "gasFees": "0x4a817c800", + "coinbaseDiff": "0x4a817c800", + "ethSentToCoinbase": "0x0", + "value": "0x0", + "executionTimeUs": 150 + } + ], + "stateBlockNumber": 12345, + "stateFlashblockIndex": 3, + "totalGasUsed": 21000, + "totalExecutionTimeUs": 150, + "stateRootTimeUs": 80 +} +``` + +## Interpreting the response + +The `priorityFee` field is the recommended value for your transaction's `maxPriorityFeePerGas`. It reflects the highest recommended fee across all resource types, so setting your priority fee to at least this value gives your transaction the best chance of inclusion. + +To understand which resource is driving the fee, inspect the `resourceEstimates` array. The resource with the highest `recommendedPriorityFee` is the binding constraint on your bundle's inclusion. + +| Scenario | `priorityFee` | `blocksSampled` | What it means | +|----------|---------------|-----------------|---------------| +| Normal congestion | `> 0` | `> 0` | Set your `maxPriorityFeePerGas` to at least this value. | +| Uncongested | Low value | `> 0` | Blocks have spare capacity. The returned fee is a floor value. | +| No historical data | `0x0` | `0` | The metering system does not have enough data yet. The bundle simulation results are still valid. | + +## How the estimate works + +The estimation runs in three stages: + + + +Your bundle is executed against the latest pending state (including any in-progress flashblocks). This produces the bundle's resource consumption: gas used, execution time, state root time, and DA bytes. + + +For each recent block (default: 12 blocks), the estimator evaluates each flashblock using the core algorithm: + +- Transactions are sorted by priority fee, highest first. +- For each resource, the algorithm walks down the sorted list, accumulating resource usage. +- It stops when adding the next transaction would leave less remaining capacity than your bundle needs. +- The last included transaction's fee becomes the **threshold** — the minimum fee your bundle would need to displace it. +- If all transactions fit with room to spare, the resource is uncongested and a default floor fee is returned. + +Resources have different budget behaviors that affect which transactions are evaluated: + +- **Execution time** resets each flashblock — each flashblock is evaluated independently against the full per-flashblock budget. The worst (highest fee) flashblock becomes the block-level summary. +- **Gas, state root time, and DA bytes** accumulate across the block — the whole-block budget is divided into cumulative per-flashblock deadlines. Each flashblock is evaluated against a growing prefix of all transactions up to that point. The block-end estimate becomes the summary. + + +For each resource, the **median** recommended fee across all sampled blocks is computed. The final `priorityFee` is the **maximum** across all resource types. + + + +## Errors + +| Error | Cause | +|-------|-------| +| `Priority fee estimation not configured` | The node does not have resource metering enabled. | +| `bundle ... demand (...) exceeds capacity limit (...)` | Your bundle's resource consumption exceeds the block's capacity for that resource. The bundle cannot fit in a single block. | +| `Failed to parse bundle` | One or more transactions in `txs` could not be decoded as valid RLP-encoded EIP-2718 envelopes. | +| `Bundle metering failed` | The simulation failed (for example, insufficient balance or invalid nonce). | diff --git a/docs/docs.json b/docs/docs.json index 8f8998bd9..4e7fcfc63 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -95,6 +95,7 @@ "base-chain/network-information/ecosystem-contracts", "base-chain/network-information/network-fees", "base-chain/network-information/block-building", + "base-chain/network-information/resource-metering", "base-chain/network-information/transaction-finality", "base-chain/network-information/diffs-ethereum-base", "base-chain/network-information/troubleshooting-transactions",