# Use the Docs with AI Source: https://docs.optimism.io/ai-docs Read the Optimism docs as an agent with llms.txt and per-page markdown, connect the hosted MCP server, and start from curated prompts. These docs are built to be read by AI assistants and agents, not just browsers. Every page is available as plain markdown, the whole site publishes a machine-readable index, and a hosted MCP server exposes search over the content. This page covers the three ways to put them to work: [reading the docs as an agent](#read-the-docs-as-an-agent), [connecting the hosted MCP server](#connect-the-hosted-mcp-server), and [starting from curated prompts](#prompt-starters). ## Read the Docs as an Agent ### The Documentation Index: llms.txt The site publishes an [llms.txt](https://llmstxt.org/) index at: ```text theme={null} https://docs.optimism.io/llms.txt ``` It is a plain-markdown listing of the site's pages with their URLs. Point an assistant at it to discover what exists before fetching individual pages. This is the recommended entry point for any agent working with these docs. ### Per-Page Markdown Every page is served as raw markdown at its own URL with `.md` appended. For example, the [Node Operator Overview](/node-operators/overview) page is available as: ```text theme={null} https://docs.optimism.io/node-operators/overview.md ``` Fetching the `.md` form skips the HTML shell, navigation, and scripts, so an assistant gets exactly the content of the page in a fraction of the tokens. Prefer it over the HTML URL whenever your tooling fetches pages programmatically. ### The Contextual Menu Every page in these docs has a contextual menu (next to the page title) with assistant-ready actions: * **Copy page**: copies the page as markdown, ready to paste into any chat. * **Open in ChatGPT**: opens a ChatGPT conversation preloaded with the page. * **Open in Claude**: opens a Claude conversation preloaded with the page. * **Copy MCP server URL**: copies the [hosted MCP server](#connect-the-hosted-mcp-server) address for your client configuration. Use it when you are reading a page and want to hand it to an assistant without constructing URLs by hand. ### Tips for Agents Reading These Docs * Start from `llms.txt` to map the site, then fetch only the `.md` pages you need. * These docs describe how to *use* the OP Stack. The normative protocol definition lives in the [OP Stack specifications](https://specs.optimism.io) - when a docs page and the specs disagree, the specs win. * Configuration flags and versions change between releases. Confirm load-bearing values against the linked source or release notes before acting on them. ## Connect the Hosted MCP Server The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) is an open standard for connecting AI assistants to external tools and data sources. These docs are hosted on Mintlify, which [automatically generates and hosts an MCP server](https://www.mintlify.com/docs/ai/model-context-protocol) for the site. The server exposes a search tool over the documentation, so a connected assistant (Claude Code, Claude Desktop, Cursor, and others) can look up current OP Stack content instead of relying on stale training data. ### Option 1: The Hosted MCP Server (Recommended) The docs MCP server is available over HTTP at: ```text theme={null} https://docs.optimism.io/mcp ``` For Claude Code, run: ```bash theme={null} claude mcp add --transport http optimism-docs https://docs.optimism.io/mcp ``` For Cursor, Claude Desktop, and other clients that use a JSON configuration, add the server URL: ```json theme={null} { "mcpServers": { "optimism-docs": { "url": "https://docs.optimism.io/mcp" } } } ``` You can also connect from any page of these docs: the contextual menu (next to the page title) includes an option to copy the MCP server details for your client. Ask your assistant: ```text theme={null} Using the optimism-docs MCP server, find the page about running a node from source and summarize its hardware requirements. ``` A correctly wired assistant calls the server's search tool, locates [Building and Running an OP Stack Node From Source](/node-operators/tutorials/run-node-from-source), and answers from the live page. ### Option 2: Direct Fetching (No MCP Server Required) If your assistant can fetch web pages but does not support MCP, no setup is needed. The site's [machine-readable surfaces](#read-the-docs-as-an-agent) - the `llms.txt` index and per-page markdown - work with any assistant that can fetch URLs. Give it the index and the URL convention: ```text theme={null} The Optimism docs publish a machine-readable index at https://docs.optimism.io/llms.txt. Any page is available as raw markdown by appending .md to its URL. Use the index to find relevant pages, then fetch their .md versions. ``` Add that to your assistant's project instructions (for example `CLAUDE.md`, `.cursorrules`, or a system prompt) and it will resolve OP Stack questions against the live docs. If your tooling only reaches the network through MCP and cannot use the hosted server, the reference [fetch server](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch) (`uvx mcp-server-fetch`) plus the instruction block above achieves the same result. If the hosted MCP endpoint is not responding, [open an issue](https://github.com/ethereum-optimism/optimism/issues) so we can investigate. ## Prompt Starters Copy-paste prompts for common OP Stack tasks, ready for any AI assistant that can fetch URLs. Each prompt names its intended persona, grounds the assistant in specific docs pages (fetched as [per-page markdown](#per-page-markdown)), and tells it what to produce. Replace the bracketed placeholders with your own details before sending. If your assistant cannot fetch URLs, open the linked pages and use the contextual menu's **Copy page** action to paste them in instead. ### Audit My Batcher Configuration for Cost **Persona:** chain operator Data availability is usually a chain's largest onchain operating cost, and the batcher configuration controls it. Grounding pages: [Configure the Batcher](/chain-operators/guides/configuration/batcher) and [Transaction Fees 101](/chain-operators/guides/management/transaction-fees-101). ```text theme={null} Read https://docs.optimism.io/chain-operators/guides/configuration/batcher.md and https://docs.optimism.io/chain-operators/guides/management/transaction-fees-101.md Here is my current op-batcher configuration: [paste your flags or env vars]. My chain posts roughly [N] transactions per day and targets [blobs / calldata]. Audit the configuration for data-availability cost: identify settings that increase posting cost, explain the trade-off each one controls (cost vs. latency vs. safety), and propose a revised configuration with reasoning. Flag any flag you are not sure still exists so I can check it against op-batcher --help for my release. ``` ### Walk Me Through the Deposit Flow **Persona:** app developer Understand what actually happens between an L1 deposit call and the transaction appearing on L2 before you build on it. Grounding pages: [Deposit Flow](/op-stack/bridging/deposit-flow) and [Deposit Transactions](/app-developers/tutorials/bridging/deposit-transactions). ```text theme={null} Read https://docs.optimism.io/op-stack/bridging/deposit-flow.md and https://docs.optimism.io/app-developers/tutorials/bridging/deposit-transactions.md Walk me through the full lifecycle of a deposit from L1 to L2: which contract I call, what events are emitted, how the L2 transaction is derived, and what latency and failure modes to expect. Then show me the minimal code to trigger a deposit from my app. I am building [describe your app]. ``` ### Plan a Fault-Proof Challenger Deployment **Persona:** chain operator Every permissionless fault-proof chain needs an honest challenger watching its dispute games. Grounding pages: [OP-Challenger Explainer](/op-stack/fault-proofs/challenger) and [How to Configure Challenger for Your Chain](/chain-operators/guides/configuration/op-challenger-config-guide). ```text theme={null} Read https://docs.optimism.io/op-stack/fault-proofs/challenger.md and https://docs.optimism.io/chain-operators/guides/configuration/op-challenger-config-guide.md I operate an OP Stack chain with fault proofs enabled on [network]. Produce a deployment plan for op-challenger: the role it plays, the resources and keys it needs, the bond funding it requires, the configuration I must set, and the monitoring I should attach. List open questions I need to answer about my own chain before deploying. ``` ### Bridge ETH From L1 in My App **Persona:** app developer Move ETH between Ethereum and an OP Stack chain programmatically. Grounding page: [Submitting Transactions From L1](/app-developers/tutorials/bridging/cross-dom-bridge-eth). ```text theme={null} Read https://docs.optimism.io/app-developers/tutorials/bridging/cross-dom-bridge-eth.md Using the approach in this tutorial, write the code for my app to bridge ETH from [L1 network] to [L2 network] and report deposit status to the user. My stack is [TypeScript framework / environment]. Point out where testnet and mainnet configuration differ, and what the user experience should show while the deposit is in flight. ``` ### Explain My Transaction's Fee Breakdown **Persona:** app developer OP Stack transactions pay an execution fee and a data-availability fee; estimating only one of them causes bugs. Grounding page: [Transaction Fees on OP Mainnet](/op-stack/transactions/fees). ```text theme={null} Read https://docs.optimism.io/op-stack/transactions/fees.md Explain every component of the fee my transaction pays on an OP Stack chain, how each is calculated, and which ones fluctuate with L1 gas prices. Then show me how to estimate the total fee for a transaction correctly in my app, and the common estimation mistakes to avoid. Here is my current estimation code: [paste code, optional]. ``` ### Debug a Stuck Withdrawal **Persona:** app developer Withdrawals are multi-step and time-delayed by design; most "stuck" withdrawals are actually mid-flight. Grounding pages: [Withdrawal Flow](/op-stack/bridging/withdrawal-flow) and [Transaction Finality](/op-stack/transactions/transaction-finality). ```text theme={null} Read https://docs.optimism.io/op-stack/bridging/withdrawal-flow.md and https://docs.optimism.io/op-stack/transactions/transaction-finality.md A withdrawal from [L2 network] appears stuck: [describe what you did, when, and the transaction hash or current status]. Using the withdrawal lifecycle in these docs, determine which stage the withdrawal is in, whether the delay is expected protocol behavior or an actual problem, and exactly what action (if any) unblocks the next step. ``` ## Contributing The prompts above are curated: each one maps to a task readers actually arrive with, and each grounds the assistant in maintained docs pages. To propose a new prompt or fix a stale one, [open an issue](https://github.com/ethereum-optimism/optimism/issues) or edit this page. # Bridging basics Source: https://docs.optimism.io/app-developers/guides/bridging/basics Learn about the fundamentals of sending data and tokens between Ethereum and OP Mainnet. OP Mainnet is a "Layer 2" system and is fundamentally connected to Ethereum. However, OP Mainnet is also a distinct blockchain with its own blocks and transactions. App developers commonly need to move data and tokens between OP Mainnet and Ethereum. This process of moving data and tokens between the two networks is called "bridging". ## Sending tokens One of the most common use cases for bridging is the need to send ETH or ERC-20 tokens between OP Mainnet and Ethereum. OP Mainnet has a system called the [Standard Bridge](./standard-bridge) that makes it easy to move tokens in both directions. If you mostly need to bridge tokens, make sure to check out the [Standard Bridge](./standard-bridge) guide. ## Sending data Under the hood, the Standard Bridge is just an application that uses the OP Mainnet [message passing system to send arbitrary data between Ethereum and OP Mainnet](./messaging). Applications can use this system to have a contract on Ethereum interact with a contract on OP Mainnet, and vice versa. All of this is easily accessible with a simple, clean API. ## Next steps Ready to start bridging? Check out these tutorials to get up to speed fast. * [Learn how to bridge ERC-20 tokens with viem](/app-developers/tutorials/bridging/cross-dom-bridge-erc20) * [Learn how to create a standard or custom bridged token](/app-developers/tutorials/bridging/standard-bridge-standard-token) * [Learn how to submit transactions from L1](/app-developers/tutorials/bridging/cross-dom-bridge-eth) # Custom bridges Source: https://docs.optimism.io/app-developers/guides/bridging/custom-bridge Important considerations when building custom bridges for OP Mainnet. Custom token bridges are any bridges other than the [Standard Bridge](./standard-bridge). You may find yourself in a position where you need to build a custom token bridge because the Standard Bridge doesn't completely support your use case. This guide provides important information you should be aware of when building a custom bridge. Custom bridges can bring a significant amount of complexity and risk to any project. Before you commit to a custom bridge, be sure that the [Standard Bridge](./standard-bridge) definitely does not support your use case. [Building a custom bridged token](/app-developers/tutorials/bridging/standard-bridge-standard-token) is often sufficient for projects that need more flexibility. ## Guidelines Custom bridges can use any design pattern you can think of. However, with increased complexity comes increased risk. Consider directly extending or modifying the [`StandardBridge`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol) contract before building your own bridge contracts from scratch. Doing so will provide you with an audited foundation upon which you can add extra logic. If you choose not to extend the `StandardBridge` contract, you may still want to follow the interface that the `StandardBridge` provides. Bridges that extend this interface will be compatible with the [Superchain Bridges UI](https://app.optimism.io/bridge?utm_source=op-docs\&utm_medium=docs). You can read more about the design of the Standard Bridge in the guide on [Using the Standard Bridge](./standard-bridge). ## The Superchain Token List The [Superchain Token List](/app-developers/reference/tokens/tokenlist) exists to help users and developers find the right bridged representations of tokens native to another blockchain. Once you've built and tested your custom bridge, make sure to register any tokens meant to flow through this bridge by [making a pull request against the Superchain Token List repository](https://github.com/ethereum-optimism/ethereum-optimism.github.io#adding-a-token-to-the-list). You **must** deploy your bridge to OP Sepolia before it can be added to the Superchain Token List. ## Next steps You can explore several examples of custom bridges for OP Mainnet: * [NFT Bridge](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol) * [L2 DAI Token Bridge](https://optimistic.etherscan.io/address/0x467194771dae2967aef3ecbedd3bf9a310c76c65#code) and [deployed addresses](https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/data/DAI/data.json) * [SNX Bridge](https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/data/SNX/data.json) # Sending data between L1 and L2 Source: https://docs.optimism.io/app-developers/guides/bridging/messaging Understand how bridging between L1 and L2 works, the messenger contracts that carry messages, what messages cost, and why the challenge period exists. Smart contracts on L1 (Ethereum) can interact with smart contracts on L2 (OP Mainnet) through a process called "bridging". This page explains how bridging works: the messenger contracts that carry messages between layers, how long delivery takes in each direction, what messages cost, and why messages from L2 to L1 must wait out a challenge period. This is a high-level overview of the bridging process. For a step-by-step tutorial on how to send data between L1 and L2, check out the [Solidity tutorial](/app-developers/tutorials/bridging/cross-dom-solidity). ## Understanding contract calls It can be easier to understand bridging if you first have a basic understanding of how contracts on EVM-based blockchains like OP Mainnet and Ethereum communicate within the *same* network. The interface for sending messages *between* Ethereum and OP Mainnet is designed to mimic the standard contract communication interface as much as possible. Here's how a contract on Ethereum might trigger a function within another contract on Ethereum: ```solidity theme={null} contract MyContract { function doTheThing(address myContractAddress, uint256 myFunctionParam) public { MyOtherContract(myContractAddress).doSomething(myFunctionParam); } } ``` Here, `MyContract.doTheThing` triggers a call to `MyOtherContract.doSomething`. Under the hood, Solidity is triggering the code for `MyOtherContract` by sending an [ABI encoded](https://docs.soliditylang.org/en/v0.8.23/abi-spec.html) call for the `doSomething` function. A lot of this complexity is abstracted away to simplify the developer experience. Solidity also has manual encoding tools that allow us to demonstrate the same process in a more verbose way. Here's how you might manually encode the same call: ```solidity theme={null} contract MyContract { function doTheThing(address myContractAddress, uint256 myFunctionParam) public { myContractAddress.call( abi.encodeCall( MyOtherContract.doSomething, ( myFunctionParam ) ) ); } } ``` Here you're using the [low-level "call" function](https://docs.soliditylang.org/en/v0.8.23/units-and-global-variables.html#members-of-address-types) and one of the [ABI encoding functions built into Solidity](https://docs.soliditylang.org/en/v0.8.23/units-and-global-variables.html#abi-encoding-and-decoding-functions). Although these two code snippets look a bit different, they're doing the exact same thing. Because of limitations of Solidity, **the OP Stack's bridging interface is designed to look like the second code snippet**. ## Basics of communication between layers At a high level, the process for sending data between L1 and L2 is pretty similar to the process for sending data between two contracts on Ethereum (with a few caveats). Communication between L1 and L2 is made possible by a pair of special smart contracts called the "messenger" contracts. Each layer has its own messenger contract, which serves to abstract away some lower-level communication details, a lot like how HTTP libraries abstract away physical network connections. We won't get into *too* much detail about these contracts here. The most important thing that you need to know is that each messenger contract has a `sendMessage` function that allows you to send a message to a contract on the other layer. ```solidity theme={null} function sendMessage( address _target, bytes memory _message, uint32 _minGasLimit ) public; ``` The `sendMessage` function has three parameters: 1. The `address _target` of the contract to call on the other layer. 2. The `bytes memory _message` calldata to send to the contract on the other layer. 3. The `uint32 _minGasLimit` minimum gas limit that can be used when executing the message on the other layer. This is basically equivalent to: ```solidity theme={null} address(_target).call{gas: _minGasLimit}(_message); ``` Except, of course, that you're calling a contract on a completely different network. This is glossing over a lot of the technical details that make this whole thing work under the hood, but this should be enough to get you started. Want to call a contract on OP Mainnet from a contract on Ethereum? It's dead simple: ```solidity theme={null} // Pretend this is on L2 contract MyOptimisticContract { function doSomething(uint256 myFunctionParam) public { // ... some sort of code goes here } } // And pretend this is on L1 contract MyContract { function doTheThing(address myOptimisticContractAddress, uint256 myFunctionParam) public { messenger.sendMessage( myOptimisticContractAddress, abi.encodeCall( MyOptimisticContract.doSomething, ( myFunctionParam ) ), 1000000 // or use whatever gas limit you want ) } } ``` You can find the addresses of the `L1CrossDomainMessenger` and the `L2CrossDomainMessenger` contracts on OP Mainnet and OP Sepolia on the [Contract Addresses](/op-mainnet/network-information/op-addresses) page. ## Communication speed Unlike calls between contracts on the same blockchain, calls between Ethereum and OP Mainnet are *not* instantaneous. Transactions sent from L1 to L2 take **approximately 1-3 minutes**, because the Sequencer waits for a certain number of L1 blocks to be created before including L1 to L2 transactions to avoid potentially annoying [reorgs](https://www.alchemy.com/overviews/what-is-a-reorg). Transactions sent from L2 to L1 take **approximately 7 days**: the message must be initiated on L2, proven on L1 against an output root, and finalized on L1 only after the [challenge period](#understanding-the-challenge-period) (7 days on mainnet, shorter on test networks) has elapsed. This waiting period is a core part of the security model of the OP Stack and cannot be circumvented. For the step-by-step mechanics in each direction, see [Deposit flow](/op-stack/bridging/deposit-flow) and [Withdrawal flow](/op-stack/bridging/withdrawal-flow). ## Accessing `msg.sender` Contracts frequently make use of `msg.sender` to make decisions based on the calling address. For example, many contracts will use the [Ownable](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol) pattern to selectively restrict access to certain functions. Because messages are essentially shuttled between L1 and L2 by the messenger contracts, **the `msg.sender` you'll see when receiving one of these messages will be the messenger contract** corresponding to the layer you're on. In order to get around this, you can find a `xDomainMessageSender` function to each messenger: ```solidity theme={null} function xDomainMessageSender() public returns (address); ``` If your contract has been called by one of the messenger contracts, you can use this function to see who's *actually* sending this message. Here's how you might implement an `onlyOwner` modifier on L2: ```solidity theme={null} modifier onlyOwner() { require( msg.sender == address(messenger) && messenger.xDomainMessageSender() == owner ); _; } ``` ## Fees for sending data between L1 and L2 ### For L1 to L2 transactions The majority of the cost of an L1 to L2 transaction comes from the smart contract execution on L1. When sending an L1 to L2 transaction, you send to the [`L1CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol) contract, which then sends a call to the [`OptimismPortal`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol) contract. This involves some execution on L1, which costs gas. The total cost is ultimately determined by gas prices on Ethereum when you're sending the cross-chain transaction. L1 to L2 execution also triggers contract execution on L2. The `OptimismPortal` contract charges you for this L2 execution by burning a dynamic amount of L1 gas during your L1 to L2 transaction, depending on the gas limit you requested on L2. The amount of L1 gas charged increases when more people are sending L1 to L2 transactions (and decreases when fewer people are sending L1 to L2 transactions). Since the gas amount charged is dynamic, the gas burn can change from block to block. You should always add a buffer of at least 20% to the gas limit for your L1 to L2 transaction to avoid running out of gas. ### For L2 to L1 transactions Each message from L2 to L1 requires three transactions: 1. An L2 transaction that *initiates* the transaction, which is priced the same as any other transaction made on OP Mainnet. 2. An L1 transaction that *proves* the transaction. This transaction can only be submitted after the L2 block, including your L2 transaction, is proposed on L1. This transaction is expensive because it includes verifying a [Merkle trie](/connect/resources/glossary#merkle-patricia-trie) inclusion proof on L1. 3. An L1 transaction that *finalizes* the transaction. This transaction can only be submitted after the transaction challenge period (7 days on mainnet) has passed. The total cost of an L2 to L1 transaction is therefore the combined cost of the L2 initialization transaction and the two L1 transactions. The L1 proof and finalization transactions are typically significantly more expensive than the L2 initialization transaction. ## Understanding the challenge period One of the most important things to understand about L1 ⇔ L2 interaction is that **mainnet messages sent from Layer 2 to Layer 1 cannot be relayed for at least 7 days**. This period of time is called the "challenge period" because it is the window during which a published transaction result can be challenged with a [fault proof](/op-stack/protocol/overview#fault-proofs): Optimistic Rollups publish transaction *results* to Ethereum without executing the transactions there, so L1 contracts must give challengers time to prove a published result faulty before acting on it. The practical consequence for app developers is that **you don't want to be making decisions about Layer 2 transaction results from inside a smart contract on Layer 1 until this challenge period has elapsed**, and L2 ⇒ L1 messages sent using the standard messenger contracts cannot be relayed until they've waited out the full challenge period. For how the challenge period fits into the withdrawal process, see [Withdrawal flow](/op-stack/bridging/withdrawal-flow); for why it exists, see the [fault proofs overview](/op-stack/protocol/overview#fault-proofs). # Using the Standard Bridge Source: https://docs.optimism.io/app-developers/guides/bridging/standard-bridge Learn how the Standard Bridge moves ETH and ERC-20 tokens between Layer 1 and Layer 2. The Standard Bridge is a basic token bridging system available on OP Mainnet and all other standard OP Stack chains. The Standard Bridge allows you to easily move ETH and most ERC-20 tokens between Ethereum and OP Mainnet. Transfers from Ethereum to OP Mainnet via the Standard Bridge are usually completed within 1-3 minutes. Transfers from OP Mainnet to Ethereum are completed in 7 days as a result of the [withdrawal challenge period](./messaging#understanding-the-challenge-period). The Standard Bridge is fully permissionless and supports standard ERC-20 tokens. Other bridging systems also exist that provide different features and security properties. You may wish to explore some of these options to find the bridge that works best for you and your application. The Standard Bridge **does not** support [**fee on transfer tokens**](https://github.com/d-xo/weird-erc20#fee-on-transfer) or [**rebasing tokens**](https://github.com/d-xo/weird-erc20#balance-modifications-outside-of-transfers-rebasingairdrops) because they can cause bridge accounting errors. ## Design The Standard Bridge allows users to convert tokens that are native to one chain (like Ethereum) into a representation of those tokens on the other chain (like OP Mainnet). Users can then convert these bridged representations back into their original native tokens at any time. This bridging mechanism functions identically in both directions — tokens native to OP Mainnet can be bridged to Ethereum, just like tokens native to Ethereum can be bridged to OP Mainnet. Here you'll get to understand how the Standard Bridge works when moving tokens from Ethereum to OP Mainnet. Since the bridging mechanism is mirrored on both sides, this will also explain how the bridge works in the opposite direction. ### Architecture The Standard Bridge is composed of two contracts, the [`L1StandardBridge`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1StandardBridge.sol) (on `Ethereum`) and the [`L2StandardBridge`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2StandardBridge.sol) (on `OP Mainnet`). These two contracts interact with one another via the `CrossDomainMessenger` system for sending messages between Ethereum and OP Mainnet. You can read more about the `CrossDomainMessenger` in the guide on [Sending Data Between L1 and L2](./messaging). ### Bridged tokens The Standard Bridge utilizes bridged representations of tokens that are native to another blockchain. Before a token native to one chain can be bridged to the other chain, a bridged representation of that token must be created on the receiving side. A bridged representation of a token is an ERC-20 token that implements the [`IOptimismMintableERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/universal/IOptimismMintableERC20.sol#L10-L18) interface. This interface includes a few functions that the `StandardBridge` contracts use to manage the bridging process. All bridged versions of tokens **must** implement this interface to be used with the `StandardBridge`. Native tokens do not need to implement this interface. A native token may have more than one bridged representation at the same time. Users must always specify which bridged token they wish to use when using the bridge. Different bridged representations of the same native token are considered entirely independent tokens. ### Bridging native tokens The Standard Bridge uses a "lock-and-mint" mechanism to convert native tokens into their bridged representations. This means that **native tokens are locked** into the Standard Bridge on one side, after which **bridged tokens are minted** on the other side. The process for bridging a native token involves a few steps. The Standard Bridge must be able to pull tokens from the user to lock them into the bridge contract. To do this, the user must first give the bridge an [allowance](https://eips.ethereum.org/EIPS/eip-20#approve) to transfer the number of tokens that the user wishes to convert into a bridged representation. After providing a sufficient allowance, the user calls the [`bridgeERC20To`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L217-L229) function on the `StandardBridge` contract on the chain where the native token lives (e.g., the `L1StandardBridge` contract if the token is native to Ethereum). The user must provide the following parameters to this function call: * `address _localToken`: Address of the native token on the sending side. * `address _remoteToken`: Address of the bridged representation on the receiving side. * `address _to`: Address of the recipient of these tokens, usually the sender's address. * `uint256 _amount`: Number of tokens to transfer. * `uint32 _minGasLimit`: Gas to use to complete the transfer on the receiving side. * `bytes calldata _extraData`: Optional identity extra data. Users can also trigger the [`bridgeERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L194-L206) function instead of `bridgeERC20To` to avoid needing to specify the `address _to` parameter. Doing so will automatically set the `address _to` parameter to the `msg.sender`. **The `bridgeERC20` function can be potentially dangerous for users with [smart contract wallets](https://web.archive.org/web/20231012141406/https://blockworks.co/news/what-are-smart-contract-wallets) as some smart contract wallets cannot be deployed at the same address on every blockchain.** To help users avoid potentially losing access to tokens by accident, the `bridgeERC20` function will always revert when triggered from a smart contract. Smart contract wallet users and other smart contracts should therefore use the `bridgeERC20To` function instead. When the user triggers the `bridgeERC20To` function while transferring a native token, the Standard Bridge will pull the `_amount` of `_localToken` tokens from the user's address and lock them inside of the bridge contract. A record of all locked tokens is stored within a [`deposits` mapping](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L41) that keeps track of the total number of tokens deposited for a given `_localToken` and `_remoteToken` pair. Since a native token may have more than one bridged representation, the `deposits` token must keep track of the deposit pools for each `_localToken`/`_remoteToken` pair independently. To illustrate, suppose that two users deposit 100 units of the same native token, `Token A`, but wish to receive two different bridged tokens, `Token B` and `Token C`. Although the Standard Bridge would now have a total balance of 200 units of `Token A`, the mapping would show that the `Token A`/`Token B` pool and the `Token A`/`Token C` pool both have only 100 units. After locking the native tokens, the Standard Bridge contract on the sending side will trigger a cross-chain message to the Standard Bridge contract on the receiving side via the [`CrossDomainMessenger`](./messaging) system. This message tells the receiving side to **mint** tokens according to the parameters specified by the user. Specifically, this message is an encoded call to the [`finalizeBridgeERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L272-L299) function on the other Standard Bridge contract. At this point, execution ends on the sending side. Once the minting message is sent, it must be relayed to the receiving side. Message relaying is automatic when sending from Ethereum to OP Mainnet but requires additional user transactions when sending from OP Mainnet to Ethereum. Read more about the message relaying process in the guide to [Sending Data Between L1 and L2](./messaging#communication-speed). When the message is relayed, the `finalizeBridgeERC20` function will be triggered on the receiving Standard Bridge contract. This function will receive the `_minGasLimit` gas defined by the user to execute to completion. Upon execution, `finalizeBridgeERC20` verifies a number of things about the incoming request: * [The request must have originated from the Standard Bridge contract on the other blockchain](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L281). * [The Standard Bridge must not be in an emergency paused state](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L283). * [The bridged token must properly implement the `IOptimismMintableERC20` interface](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L284). * [The bridged token must recognize the original native token as its `remoteToken()`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L285-L288). If the minting message is fully verified, `finalizeBridgeERC20` will [mint tokens to the recipient](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L290) equal to the number of tokens originally deposited on the other blockchain. For this to work properly, the bridged representation of the native token must correctly implement a `mint` function that allows the Standard Bridge to mint tokens arbitrarily. This is part of the [`IOptimismMintableERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/universal/IOptimismMintableERC20.sol) interface. This completes the process of bridging native tokens. This process is identical in both the Ethereum to OP Mainnet and OP Mainnet to Ethereum directions. ### Bridging non-native tokens The Standard Bridge uses a "burn-and-unlock" mechanism to convert bridged representations of tokens back into their native tokens. This means that **bridged tokens are burned** on the Standard Bridge on one side, after which **native tokens are unlocked** on the other side. The process for bridging a non-native, bridged representation of a token involves a few steps. Unlike when bridging native tokens, users do not need to provide an approval to trigger a transfer of a bridged token because the Standard Bridge should already have the ability to `burn` these tokens. Here, the user calls the [`bridgeERC20To`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L217-L229) function on the `StandardBridge` contract on the chain where the bridged token lives (e.g., the `L2StandardBridge` contract if the token is bridged to OP Mainnet). The user must provide the following parameters to this function call: * `address _localToken`: Address of the bridged token on the sending side. * `address _remoteToken`: Address of the native token on the receiving side. * `address _to`: Address of the recipient of these tokens, usually the sender's address. * `uint256 _amount`: Number of tokens to transfer. * `uint32 _minGasLimit`: Gas to use to complete the transfer on the receiving side. * `bytes calldata _extraData`: Optional identity extra data. When the user triggers the `bridgeERC20To` function while transferring a bridge token, [the Standard Bridge will burn the corresponding `_amount` of tokens from the sender's address](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L359). After burning the bridged tokens, the Standard Bridge contract on the sending side will trigger a cross-chain message to the Standard Bridge contract on the receiving side via the [`CrossDomainMessenger`](./messaging) system. This message tells the receiving side to **unlock** tokens according to the parameters specified by the user. Specifically, this message is an encoded call to the [`finalizeBridgeERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L272-L299) function on the other Standard Bridge contract. At this point, execution ends on the sending side. Once the unlock message is sent, it must be relayed to the receiving side. Message relaying is automatic when sending from Ethereum to OP Mainnet but requires additional user transactions when sending from OP Mainnet to Ethereum. Read more about the message relaying process in the guide to [Sending Data Between L1 and L2](./messaging#communication-speed). When the message is relayed, the `finalizeBridgeERC20` function will be triggered on the receiving Standard Bridge contract. This function will receive the `_minGasLimit` gas defined by the user to execute to completion. Upon execution, `finalizeBridgeERC20` verifies a number of things about the incoming request: * [The request must have originated from the Standard Bridge contract on the other blockchain](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L281). * [The Standard Bridge must not be in an emergency paused state](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L283). If the unlock message is fully verified, `finalizeBridgeERC20` will [unlock and transfer tokens to the recipient](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L292-L293) equal to the number of tokens originally burned on the other blockchain. This completes the process of bridging native tokens. This process is identical in both the Ethereum to OP Mainnet and OP Mainnet to Ethereum directions. ### Bridging ETH The Standard Bridge contracts can also be used to bridge ETH from Ethereum to OP Mainnet and vice versa. The ETH bridging process is generally less complex than the ERC-20 bridging process. Users simply need to trigger and send ETH to the [`bridgeETH`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L166-L168) or [`bridgeETHTo`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/StandardBridge.sol#L182-L184) functions on either blockchain. Users can also deposit ETH from Ethereum to OP Mainnet by sending a basic ETH transfer from an EOA to the `L1StandardBridgeProxy`. This works because the `L1StandardBridgeProxy` contains a [`receive`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1StandardBridge.sol#L134-L136) function. You can find the mainnet and testnet addresses on the [Contract Addresses](/op-mainnet/network-information/op-addresses) page. ## Tutorials * [Learn how to bridge ERC-20 tokens with viem](/app-developers/tutorials/bridging/cross-dom-bridge-erc20) * [Learn how to create a standard or custom bridged token](/app-developers/tutorials/bridging/standard-bridge-standard-token) * [Learn how to submit transactions from L1](/app-developers/tutorials/bridging/cross-dom-bridge-eth) ## Superchain Token List The [Superchain Token List](/app-developers/reference/tokens/tokenlist) exists to help users discover the right bridged token addresses for any given native token. Because a native token may have more than one bridged representation, and different bridged representations are entirely independent tokens, using the wrong one can lock up your native tokens permanently. Follow the guide on [verifying bridged token addresses](/app-developers/guides/bridging/verify-bridged-tokens) to confirm that you're using the correct bridged representation of a token before bridging. Developers who are creating their own bridged tokens should consider [adding their token](https://github.com/ethereum-optimism/ethereum-optimism.github.io#adding-a-token-to-the-list) to the Superchain Token List. Tokens on the Superchain Token List will automatically appear on certain tools like the [Superchain Bridges UI](https://app.optimism.io/bridge?utm_source=op-docs\&utm_medium=docs). # Verifying bridged token addresses Source: https://docs.optimism.io/app-developers/guides/bridging/verify-bridged-tokens Use the Superchain Token List to find and verify the correct bridged representation of a token before using the Standard Bridge. A native token may have more than one bridged representation on the other chain, and different bridged representations of the same native token are entirely independent tokens. Bridging to the wrong representation can lock up your native tokens permanently. This guide shows you how to use the [Superchain Token List](https://github.com/ethereum-optimism/ethereum-optimism.github.io) to find and verify the correct bridged token address before you bridge a token with the [Standard Bridge](/app-developers/guides/bridging/standard-bridge). ## Find the bridged representation of a token for OP Mainnet You can easily find the bridged representation of a token for OP Mainnet on the [Bridged token addresses](/app-developers/reference/tokens/tokenlist) page. That page is generated automatically from the Superchain Token List. ## Find the bridged representation of a token for another chain If you want to find the bridged representation of a token for another chain, use the following steps. The Superchain Token List is organized by the token's address and native blockchain. [Search the token list](https://github.com/ethereum-optimism/ethereum-optimism.github.io/blob/master/optimism.tokenlist.json) for the token you want to bridge to confirm that it's included in the list. Make sure that the chain ID in the entry matches the chain ID of the blockchain you're bridging from. Retrieve the token's name and symbol from the list. Once you've found the token you want to bridge, look for the token's name and symbol in the list. Find the entry that matches the name and symbol of the token you want to bridge and where the chain ID matches the chain ID of the blockchain you're bridging to. The address of this entry is the address of the bridged representation of the token you want to bridge. Identify the cross-chain bridge contract address used by the token pair. You can observe that some token pairs in the list utilize **custom bridge contracts** instead of the default Standard Bridge. Verify the bridge contract specified in the token list entry to ensure you are interacting with the correct bridge implementation for that token. ## Add a token to the Superchain Token List Developers who are creating their own bridged tokens should consider [adding their token](https://github.com/ethereum-optimism/ethereum-optimism.github.io#adding-a-token-to-the-list) to the Superchain Token List. Tokens on the Superchain Token List will automatically appear on certain tools like the [Superchain Bridges UI](https://app.optimism.io/bridge?utm_source=op-docs\&utm_medium=docs). ## Next steps * Learn how the [Standard Bridge](/app-developers/guides/bridging/standard-bridge) moves tokens between Ethereum and OP Mainnet. * Follow the tutorial to [bridge ERC-20 tokens with viem](/app-developers/tutorials/bridging/cross-dom-bridge-erc20). # Building apps on OP Stack chains Source: https://docs.optimism.io/app-developers/guides/building-apps Learn the basics of building apps on OP Stack chains. This guide explains the basics of OP Stack development. OP Stack chains are [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306), meaning they run a slightly modified version of the same `geth` you run on mainnet. Therefore, the differences between OP Stack development and Ethereum development are minor. But a few differences [do exist](/op-stack/protocol/differences). ## OP Stack chains endpoint URLs To access any Ethereum type network you need an endpoint. [These providers](/app-developers/reference/rpc-providers) support our networks. ### Network choice For development purposes we recommend you use either a local development network or [OP Sepolia](https://sepolia-optimism.etherscan.io). That way you don't need to spend real money. If you need ETH on OP Sepolia for testing purposes, [you can use this faucet](https://console.optimism.io/faucet?utm_source=op-docs\&utm_medium=docs). ## Interacting with contracts on OP Stack chains We have Hardhat's Greeter contract on OP Sepolia at address [0x9d334aFBa83865E67a9219830ADA57aaA9406681](https://testnet-explorer.optimism.io/address/0x9d334aFBa83865E67a9219830ADA57aaA9406681#code). You can verify your development stack configuration by interacting with it. ## Development stacks As you can see in the different development stacks below, the way you deploy contracts and interact with them on OP Stack chains is almost identical to the way you do it with L1 Ethereum. The most visible difference is that you have to specify a different endpoint (of course). For more detail, see the guide on [Differences between Ethereum and OP Stack Chains](/op-stack/protocol/differences). * [Foundry](https://getfoundry.sh/) * [Hardhat](https://hardhat.org/) * [Apeworx](https://www.apeworx.io/) * [Brownie](https://eth-brownie.readthedocs.io/en/stable/install.html) * [Remix](https://remix.ethereum.org) * [Waffle](https://getwaffle.io/) ## Best practices ### Use provided EVM It is best to start development with the EVM provided by the development stack. Not only is it faster, but such EVMs often have extra features, such as the [ability to log messages from Solidity](https://hardhat.org/tutorial/debugging-with-hardhat-network.html) or a [graphical user interface](https://trufflesuite.com/ganache/). ### Debug before deploying After you are done with that development, debug your decentralized application locally and then on a [Sepolia test network](/op-mainnet/network-information/connecting-to-op). This lets you debug parts that are OP Stack chains specific such as calls to bridges to transfer ETH or tokens between layers. Only when you have a version that works well on a test network should you deploy to the production network, where every transaction has a cost. **Running your app in production** A production application depends on infrastructure your team does not run: RPC endpoints that hold up under real traffic (the public endpoints are rate-limited and not built for production), bridges your users rely on, and a chain whose operator keeps sequencing, upgrades, and incident response going around the clock. These docs cover building and testing. If your application is growing toward dedicated blockspace of its own, [OP Enterprise](https://optimism.io/op-enterprise?utm_source=docs\&utm_medium=docs\&utm_campaign=op-enterprise) offers managed and supported paths to running a chain. These docs stay the reference for what you build either way. OP Enterprise is Optimism's managed offering. ### Contract source verification You don't have to upload your source code to [block explorers](/app-developers/tools/infrastructure/block-explorers), but it is a good idea. On the test network, it lets you issue queries and transactions from the explorer's user interface. On the production network, it lets users know exactly what your contract does, which is conducive to trust. Just remember, if you use [the Etherscan API](https://explorer.optimism.io/apis?utm_source=op-docs\&utm_medium=docs), you need one API key for OP Stack chains and a separate one for OP Sepolia. # Configuring Actions SDK Source: https://docs.optimism.io/app-developers/guides/configuring-actions Learn how to configure Actions SDK for your application. Actions SDK lets you choose which assets, markets, chains, protocols, and providers you want to support in your application via configuration file. Follow the [quickstart](/app-developers/quickstarts/actions) guide to add Actions SDK as a dependency in your app. Follow the [connecting a wallet to Actions SDK](/app-developers/guides/connect-wallet-to-actions) guide, choose and install a Wallet Provider. `actions.ts` - An accessible file that holds all of your configuration preference. Let Actions SDK know which Wallet Provider you've chosen: Select a wallet provider: ```typescript title="actions.ts" theme={null} const walletConfig = { hostedWalletConfig: { provider: { type: "privy" as const, }, }, smartWalletConfig: { provider: { type: "default" as const, attributionSuffix: "actions", }, }, }; ``` ```typescript title="actions.ts" theme={null} const walletConfig = { hostedWalletConfig: { provider: { type: "turnkey" as const, }, }, smartWalletConfig: { provider: { type: "default" as const, attributionSuffix: "actions", }, }, }; ``` ```typescript title="actions.ts" theme={null} const walletConfig = { hostedWalletConfig: { provider: { type: "dynamic" as const, }, }, smartWalletConfig: { provider: { type: "default" as const, attributionSuffix: "actions", }, }, }; ``` Select a wallet provider: ```typescript title="actions.ts" theme={null} import { PrivyClient } from '@privy-io/node' const privyClient = new PrivyClient( process.env.PRIVY_APP_ID, process.env.PRIVY_APP_SECRET, ) const walletConfig = { hostedWalletConfig: { provider: { type: "privy" as const, config: { privyClient, }, }, }, smartWalletConfig: { provider: { type: "default" as const, attributionSuffix: "actions", }, }, }; ``` ```typescript title="actions.ts" theme={null} import { Turnkey } from '@turnkey/sdk-server' const turnkeyClient = new Turnkey({ apiBaseUrl: 'https://api.turnkey.com', apiPublicKey: process.env.TURNKEY_API_KEY, apiPrivateKey: process.env.TURNKEY_API_SECRET, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }) const walletConfig = { hostedWalletConfig: { provider: { type: "turnkey" as const, config: { client: turnkeyClient.apiClient(), }, }, }, smartWalletConfig: { provider: { type: "default" as const, attributionSuffix: "actions", }, }, }; ``` Configure which assets you want to support across all lend providers: ```typescript title="actions.ts" theme={null} // Additional config from previous steps... // Import popular assets import { USDC } from '@eth-optimism/actions-sdk/assets' import type { Asset, AssetsConfig } from "@eth-optimism/actions-sdk"; // Or define custom assets export const CustomToken: Asset = { address: { [mainnet.id]: '0x123...', [unichain.id]: '0x456...', [baseSepolia.id]: '0x789...', }, metadata: { decimals: 6, name: 'Custom Token', symbol: 'CUSTOM', }, type: 'erc20', } // Configure allowed/blocked assets const assetsConfig: AssetsConfig = { allow: [USDC, CustomToken], block: [], // Optional } ``` Define which markets you want to support or block within your app: ```typescript title="actions.ts" theme={null} // Additional config from previous steps... export const GauntletUSDC: LendMarketConfig = { address: '0xabc...', chainId: unichain.id, name: 'Gauntlet USDC', asset: USDC, lendProvider: 'morpho', } ``` Configure which lend protocols you want to support. You can enable one or multiple providers: ```typescript title="actions.ts" theme={null} // Additional config from previous steps... import type { LendConfig } from "@eth-optimism/actions-sdk"; const lendConfig: LendConfig = { morpho: { marketAllowlist: [GauntletUSDC], marketBlocklist: [], // Optional }, aave: { marketAllowlist: [AaveWETH], marketBlocklist: [], // Optional }, }; ``` Configure supported chains: ```typescript title="actions.ts" theme={null} // Additional config from previous steps... import { optimism, base } from "viem/chains"; // Define any EVM chain const OPTIMISM = { chainId: optimism.id, rpcUrls: env.OPTIMISM_RPC_URL, bundler: { // Bundle and sponsor txs with a gas paymaster type: "simple" as const, url: env.OPTIMISM_BUNDLER_URL, }, }; const BASE = { chainId: base.id, rpcUrls: env.BASE_RPC_URL, bundler: { // Bundle and sponsor txs with a gas paymaster type: "simple" as const, url: env.BASE_BUNDLER_URL, }, }; const chains = [OPTIMISM, BASE]; ``` Finally bring it all together and initialize Actions: ```typescript title="actions.ts" theme={null} // Additional config from previous steps... export const actions = createActions({ wallet: walletConfig, assets: assetsConfig, lend: lendConfig, chains, }); ``` Once you've initialized your actions instance, import it anywhere you need to take action: ```typescript theme={null} import { actions } from './actions'; // Use actions anywhere in your app const market = await actions.lend.getMarket({ ... }); const wallet = await actions.wallet.createSmartWallet({ ... }); const receipt = await wallet.lend.openPosition({ ... }); ``` ## Next Steps For detailed API documentation and type definitions, see the [Actions SDK Reference](/app-developers/reference/actions/integrating-wallets). # Connecting a wallet to Actions SDK Source: https://docs.optimism.io/app-developers/guides/connect-wallet-to-actions Connect an embedded provider wallet to Actions SDK so it can perform DeFi actions like Lend, Borrow, Swap, and Pay. Actions SDK works with wallets from popular embedded wallet providers, regardless of where and how transactions are signed. This guide shows you how to connect a provider wallet to Actions so it can call Actions functions. For help deciding which wallet schema fits your use case, see [Integrating wallets](/app-developers/reference/actions/integrating-wallets). ## Connect your wallet Follow embedded wallet provider documentation and installation steps. Actions works with Typescript clients, both frontend React and backend Node. Import [Actions SDK](https://actions.money/) alongside your chosen wallet provider SDK. The [quickstart](/app-developers/quickstarts/actions#installation) covers installing Actions SDK in your project. Follow embedded wallet provider documentation for wallet creation and access. Call `actions.wallet.toActionsWallet(...)`, and [pass in](/app-developers/quickstarts/actions#choose-a-wallet-provider) the provider wallet. The quickstart includes provider-specific code examples for both frontend and backend clients. The returned [Wallet](/app-developers/reference/actions/wallet-definitions) is now capable of calling Actions [functions](/app-developers/quickstarts/actions#take-action) like Lend, Borrow, Swap and Pay! ## Next steps * Follow the [Configuring Actions](/app-developers/guides/configuring-actions) guide to define which protocols, chains, and assets to support. * Learn about [smart wallets & signers](/app-developers/reference/actions/integrating-wallets#smart-wallets--signers) if you want Actions to deploy smart contract wallets controlled by your users' embedded wallets. * See the [Wallet Documentation](/app-developers/reference/actions/wallet-definitions) for API details on wallet classes, functions, and parameters. # Build interoperable apps on OP Stack devnet Source: https://docs.optimism.io/app-developers/guides/interoperability/get-started Learn about deploying contracts, cross-chain messaging, and tutorials to help you build applications on OP Stack chains. Reimagine your app with OP Stack interop to deliver the unified UX your users expect. Hack on net-new, bold use cases on Interop devnet. Explore the [Superchain Dev Console](https://console.optimism.io/?utm_source=op-docs\&utm_medium=docs) to build, launch, and grow your app on OP Stack chains. ## Connect to OP Stack Interop Choose your development environment to build, test, and quickly iterate on your apps. | Environment | Purpose | Getting Started | | --------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------- | | **Local development** | Rapid iteration and testing with Supersim | [Setup Supersim guide](/app-developers/tutorials/development/supersim/installation) | | **Interop devnet** | Large-scale testing on testnets | [Network specs](/app-developers/guides/building-apps) | ## Tools & resources for building interoperable apps | Tool | Description | | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | [Superchain Faucet](https://console.optimism.io/faucet?utm_source=op-docs\&utm_medium=docs) | One-stop shop to grab testnet ETH for any OP Stack network. | | [Supersim](/app-developers/tools-sdks/supersim) | Local multi-chain testing environment for smart contracts. | | [Super CLI](https://github.com/ethereum-optimism/super-cli) | Command-line tool for seamless multichain app deployment and testing. | | [Superchain Relayer](https://github.com/ethereum-optimism/superchain-relayer) | UI for monitoring and managing cross-chain transactions. | | [Interop Docs](/op-stack/interop/explainer) | Comprehensive Interop information in the Optimism Docs. | | [Developer Console](https://console.optimism.io/?utm_source=op-docs\&utm_medium=docs) | Comprehensive tool to build, launch, and grow your app on OP Stack chains. | | [Developer Support GitHub](https://github.com/ethereum-optimism/developers/discussions) | Quick and easy developer support. | ## Handy step-by-step guides ## Discover and build net-new use cases with OP Stack Interop There is so much more than just bridge abstraction. Hack on the various cutting-edge applications that are uniquely enabled by OP Stack Interop. Here are some ideas to get you started: | Superloans | Superlend | SuperCDP | | :--------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------- | | Use collateral on ChainA and ChainB to execute an arbitrage opportunity on ChainA. | Deposit ETH into lending protocols across chains for optimal yield, with automatic rebalancing based on best rates. | Collateralized crosschain debt protocol that holds assets and issues cross-chain tokens on user preferred chains. | # Message expiration Source: https://docs.optimism.io/app-developers/guides/interoperability/message-expiration What message expiration is, why it exists, and how to reemit a previously sent message if it has expired and was never relayed. # Message expiration [Messages](/app-developers/guides/interoperability/message-passing) referenced between OP Stack chains have a limited validity period called the expiry window. Once this window elapses, the referenced message becomes invalid and can no longer be referenced. For messages using [`L2ToL2CrossDomainMessenger`](/app-developers/guides/interoperability/message-passing), if a message expires before being referenced, developers can reemit the message on the source chain. This triggers a fresh `SentMessage` event, enabling the message to be relayed. ## The expiry window The expiry window is an offchain constant that defines how long a cross-chain message or event emitted remains valid. For any chain in the [Superchain interop cluster](/interop/explainer#superchain-interop-cluster), messages must be referenced within 7 days (604,800 seconds) of the log being created. After this period, a message can no longer be referenced unless the event is remitted. ## Reemitting an expired message The `resendMessage` function on the [`L2ToL2CrossDomainMessenger`](/app-developers/guides/interoperability/message-passing) contract allows developers to reemit a message that was sent but not yet relayed. This emits a new `SentMessage` log with the same content as the original message, enabling offchain relayers to pick it up again. The process to reemit an expired message: 1. Call [`resendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/L2/IL2ToL2CrossDomainMessenger.sol#L114-L122) on the origin chain to reemit the message event. The contract verifies the message hash was originally sent. The call requires [every parameter](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/L2/IL2ToL2CrossDomainMessenger.sol#L114-L122) to rebuild the original message. 2. [Relay the new message](/interop/message-passing#executing-message) as normal. Note: Re-emitting an already relayed message will have no effect on the destination chain, since the destination chain only honors the original initiating message. ## Next steps * Learn how to [pass messages between blockchains](/app-developers/tutorials/interoperability/message-passing) # Interop message passing overview Source: https://docs.optimism.io/app-developers/guides/interoperability/message-passing Understand how interop message passing works, from the initiating message on the source chain to the executing message on the destination chain. OP Stack interop is in active development. Some features may be experimental. This is an explanation of how interop works. You can find a step by step tutorial [here](/app-developers/tutorials/interoperability/message-passing). The low-level [`CrossL2Inbox`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol) contract handles basic message execution. It verifies whether an initiating message exists but does not check the message's destination, processing status, or other attributes. The [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol) contract extends `CrossL2Inbox` by providing complete cross-domain messaging functionality. For high-level interoperability, both messages use the `L2ToL2CrossDomainMessenger` contract on their respective chains. ## Initiating message ```mermaid theme={null} sequenceDiagram participant app as Application box rgba(0,0,0,0.1) Source Chain participant srcContract as Source Contract participant srcXdom as L2ToL2CrossDomainMessenger participant log as Event Log end app->>srcContract: 1. Send a message srcContract->>srcXdom: 2. Call contract A
in chainId B
with calldata C note over srcXdom: 3. Sanity checks srcXdom->>log: 4. Log event SentMessage ``` 1. The application sends a transaction to a contract on the source chain. 2. The contract calls [`L2ToL2CrossDomainMessenger.SendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L125-L142). The call requires these parameters: * `_destination`: The chain ID of the destination blockchain. * `_target`: The address of the contract on that blockchain. * `_message`: The actual message. This message is provided to `_target` as calldata, which means it includes a function selector and the parameters for that function call. 3. `L2ToL2CrossDomainMessenger` on the source chain verifies the message is legitimate: * The destination chain is one to which this chain can send messages. * The destination chain is *not* the source chain. * The target is neither `CrossL2Inbox` nor `L2ToL2CrossDomainMessenger`. 4. `L2ToL2CrossDomainMessenger` emits a log entry. In addition to the parameters, the log entry also includes: * `_nonce`: A [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) value to ensure the message is only executed once. * `_sender`: The contract that sent the cross domain message. ## Executing message ```mermaid theme={null} sequenceDiagram participant app as Autorelayer box rgba(0,0,0,0.1) Source Chain participant log as Event Log end box rgba(0,0,0,0.1) Destination Chain participant dstNode as Destination Chain Node participant dstXdom as L2ToL2CrossDomainMessenger participant Xinbox as CrossL2Inbox participant dstContract as Destination Contract end log->>dstNode: 1. Initiating message log event app->>dstXdom: 2. Send an executing message dstXdom->>Xinbox: 3. Verify the initiating message is real note over dstXdom: 4. Sanity checks dstXdom->>dstContract: 5. Call with provided calldata ``` 1. Before the executing message is processed, the log event of the initiating message has to reach the destination chain's node before the [expiry window](/app-developers/guides/interoperability/message-expiration) of 7 days. 2. The autorelayer, the application, or a contract calling on the application's behalf calls [`L2ToL2CrossDomainMessenger.relayMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L150-L203). This call includes the message that was sent (`_sentMessage`), as well as the [fields required to find that message (`_id`)](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/L2/ICrossL2Inbox.sol#L4-L10). 3. The `L2ToL2CrossDomainMessenger` uses `CrossL2Inbox` to verify the message was sent from the source. 4. `L2ToL2CrossDomainMessenger` on the destination chain verifies the message is legitimate: * `_destination`: Chain ID of the destination chain. * `_nonce`: Nonce of the message sent * `_sender`: Address that sent the message * `_target`: Target contract or wallet address. * `message`: Message payload to call target with. 5. If everything checks out, `L2ToL2CrossDomainMessenger` calls the destination contract with the calldata provided in the message. ## Next steps * Learn how to [pass messages between blockchains](/app-developers/tutorials/interoperability/message-passing). # Reading Logs with OP Stack Interop Source: https://docs.optimism.io/app-developers/guides/interoperability/reading-logs Understand how contracts use CrossL2Inbox to validate logs from other interop chains, and how this pull model differs from sending messages. OP Stack interop is in active development. Some features may be experimental. OP Stack interop enables developers to leverage current and historical logs from other blockchains within the [OP Stack interop cluster](/interop/explainer#superchain-interop-cluster) directly on their local chain. This allows smart contracts to consume local and cross-chain logs with low latency in a trust-minimized way. ## Overview Instead of relying solely on [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol), developers can use [`CrossL2Inbox#validateMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol#L76) and treat `CrossL2Inbox` as an oracle for logs that occurred on different chains or even their local chain. This enables developers to: * Build cross-chain applications that react to events happening across OP Stack chains. * Create novel applications that leverage data from multiple chains. When reading logs, you must reference logs created within the [expiry window of 7 days](/app-developers/guides/interoperability/message-expiration). ## Why use `CrossL2Inbox`? * **Reference existing logs**: Allows contracts to verify and use logs that were already emitted, without requiring those logs to have been sent as cross-chain messages. * **Trust-minimized security**: Leverages the existing OP Stack security model with no additional trust assumptions. * **Flexibility**: Can be used to validate events from another chain or even the local chain. ## How it works ### Architecture The process works through the [`CrossL2Inbox`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol#L31) contract, which serves as an oracle for logs from other chains in the OP Stack interop cluster: 1. A smart contract on `Chain A` emits a log (event) 2. Your contract on `Chain B` calls `CrossL2Inbox#validateMessage` with the log's identifier 3. The `CrossL2Inbox` contract verifies the log's authenticity 4. Your contract can then use the validated log data ### Key components * **Identifier**: A struct containing information about the log, including `chainId`, `origin` (contract address), and other log metadata * **[validateMessage](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol#L79)**: Function that verifies a log's authenticity before allowing its use ## Example: cross-chain attestation verification Let's walk through a conceptual example of verifying an Ethereum Attestation Service (EAS) attestation across chains. EAS is a [predeploy](/app-developers/reference/contracts/interop/predeploy) in the OP Stack for making attestations on or off-chain about anything. ### Source chain: creating an attestation On the source chain (e.g., OP Mainnet), a user creates an attestation using EAS: ```mermaid theme={null} sequenceDiagram participant User participant App as Application participant EAS as EAS Contract participant Log as Event Log User->>App: Request attestation App->>EAS: createAttestation() EAS->>Log: Emit AttestationCreated event Note over Log: Event contains attestation data ``` 1. The user initiates a request for an attestation through an application. 2. The application calls the `createAttestation()` function on the EAS (Ethereum Attestation Service) contract on the source chain. 3. The EAS contract processes the attestation request and emits an `AttestationCreated` event. 4. The event is recorded in the chain's log, containing all necessary attestation data. ### Destination chain: verifying the attestation On the destination chain (e.g., Unichain), a DeFi application wants to verify this attestation: ```mermaid theme={null} sequenceDiagram participant User participant DeFi as DeFi Application participant Verifier as AttestationVerifier participant CrossL2 as CrossL2Inbox User->>DeFi: Request access using attestation DeFi->>Verifier: verifyAttestation(id, attestationEvent) Verifier->>CrossL2: validateMessage(id, keccak256(attestationEvent)) Note over CrossL2: Check the log exists on the source chain. CrossL2-->>Verifier: Return validation result Verifier-->>DeFi: Return verification status DeFi-->>User: Grant access based on attestation ``` 1. The user requests access to a DeFi application on the destination chain, referencing an attestation created on the source chain. 2. The DeFi application calls a verification function on an attestation verifier contract, passing the attestation's identifier and event data. 3. The attestation verifier calls `validateMessage()` on the `CrossL2Inbox` contract, passing the attestation identifier and a hash of the event data. 4. The [`CrossL2Inbox`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol) contract checks whether the specified log exists on the source chain. 5. The `CrossL2Inbox` returns the validation result to the attestation verifier. 6. The attestation verifier returns the verification status to the DeFi application. 7. If validation is successful, the DeFi application grants the user access based on the verified attestation. The primary benefit of this approach is that it allows your contract to verify attestations that already exist on another chain without requiring those attestations to have been explicitly sent as cross-chain messages. ## Overview of the process To implement cross-chain log reading: ```mermaid theme={null} flowchart TD A[1. Identify log to consume] --> B[2. Create Identifier struct] B --> C[3. Call validateMessage] C --> D[4. Process validated log data] subgraph "Conceptual Approach" E["Define an Identifier struct with: - chainId: The source chain ID - origin: The source contract address - Other required identifier parameters"] F["Call validateMessage on CrossL2Inbox Pass the identifier and hash of log data"] end B --> E C --> F ``` 1. First, identify which log from another chain you want to consume in your application. 2. Create an Identifier struct that contains all necessary information about the log, including the chain ID and the contract address that emitted the log. 3. Call the `validateMessage()` function on the `CrossL2Inbox` contract, passing the identifier and a hash of the log data. 4. After validation, process the log data according to your application's requirements. ## Important considerations * This feature works between chains within the [OP Stack interop cluster](/interop/explainer#superchain-interop-cluster). * The same functionality can be used on a single chain (for example, to maintain a consistent architecture). ### Handling validation failures * The `validateMessage` call will revert the entire transaction if validation fails. * Consider implementing a try-catch pattern in your application's frontend to handle these failures. * Design your contract to allow for retry mechanisms where appropriate. ## Comparison with `L2ToL2CrossDomainMessenger` | Feature | L2ToL2CrossDomainMessenger | CrossL2Inbox#validateMessage | | ---------- | ---------------------------------------------- | ------------------------------------------------- | | Purpose | Send messages between chains | Verify logs from other chains or local chain | | Initiation | Source explicitly sends message to destination | Destination queries for existing logs from source | | Use Case | Transfer tokens, trigger actions | Verify attestations, reference events | | Flow | Push model | Pull model | ## End-to-End flow comparison ```mermaid theme={null} flowchart LR subgraph "L2ToL2CrossDomainMessenger (Push Model)" A[Source Contract] -->|sendMessage| B[Source L2ToL2CrossDomainMessenger] B -->|emit event| C[Event Log] C -.->|relayed by| D[Autorelayer] D -->|relayMessage| E[Destination L2ToL2CrossDomainMessenger] E -->|execute| F[Destination Contract] end subgraph "CrossL2Inbox (Pull Model)" G[Source Contract] -->|emit event| H[Event Log] J[Destination Contract] -->|validateMessage| K[CrossL2Inbox] K -.->|verify log exists on source chain| H end ``` This diagram compares the two approaches for cross-chain communication: ### L2ToL2CrossDomainMessenger (Push Model): 1. A source contract calls `sendMessage()` on the `L2ToL2CrossDomainMessenger`. 2. The messenger emits an event to the event log. 3. An autorelayer detects the event and relays it to the destination chain. 4. The destination `L2ToL2CrossDomainMessenger` receives the relayed message. 5. The destination messenger executes the message on the target contract. ### CrossL2Inbox (Pull Model): 1. A source contract emits an event to the event log. 2. A destination contract calls `validateMessage()` on the `CrossL2Inbox`. 3. The `CrossL2Inbox` verifies that the log exists on the source chain. 4. The destination contract receives verification and proceeds with its logic. ## Next steps * Learn how to [pass messages between blockchains](/app-developers/tutorials/interoperability/message-passing) # Testing apps for OP Stack chains Source: https://docs.optimism.io/app-developers/guides/testing-apps Learn best practices for testing apps on OP Stack chains. For the most part, running applications on OP Stack chains is identical to running them on Ethereum, so the testing is identical too. In this guide, you learn the best practices for OP Stack testing where there are differences. ## Unit tests and single layer integration tests The vast majority of tests do not involve any OP Stack-specific features. In those cases, while you *could* test everything on an OP Stack chain or a test network, that would normally be inefficient. Most Ethereum development stacks include features that make testing easier, which normal Ethereum clients, such as geth (and our modified version, `op-geth`) don't support. Therefore, it is a good idea to run the majority of tests, which do not rely on OP Stack-specific features, in the development stack. It is a lot faster. It is a best practice to design and run thorough tests across an OP test network, either in your [local multichain development environment](/app-developers/tools/development/supersim), our [devnets](/op-stack/introduction/op-stack), or on [the test network](/op-mainnet/network-information/connecting-to-op#op-sepolia), depending on your use case. Alternatively, with [Tenderly Virtual TestNets](https://docs.tenderly.co/virtual-testnets?mtm_campaign=ext-docs\&mtm_kwd=optimism)you can run tests with complete integration with existing protocols, access to unlimited faucets, continuous state sync, and access to development tools such as Debugger and Simulator UI. Running proper testing is key to identifying fringe cases where the equivalence between OP Stack chains and Ethereum breaks down (or where Ethereum mainnet itself and the development stack may be non-equivalent in a production environment). ## Multilayer integration tests Some apps need OP Stack-specific features that aren't available as part of the development stack. For example, if your decentralized application relies on [inter-domain communication](/app-developers/guides/bridging/messaging), the effort of developing a stub to let you debug it in a development stack is probably greater than the hassle of having the automated test go to [a local multichain development environment](/app-developers/tools/development/supersim) each time. ## Testing and Staging with Tenderly Tenderly [Virtual TestNets](https://docs.tenderly.co/virtual-testnets?mtm_campaign=ext-docs\&mtm_kwd=optimism) provide a powerful environment for testing OP Stack applications with mainnet-like conditions. They offer several advantages for testing OP Stack applications: * **Mainnet State Replication**: Virtual TestNets can sync with the latest OP Stack mainnet state, allowing you to test against real network conditions and interact with up-to-date protocols without spending real assets. * **Unlimited Faucet**: Access [unlimited test tokens](https://docs.tenderly.co/virtual-testnets/unlimited-faucet?mtm_campaign=ext-docs\&mtm_kwd=optimism) for both native currency and ERC-20 tokens, enabling comprehensive testing of complex DeFi interactions. * **Collaborative Testing**: Your entire team can access the same testing environment, making it easier to debug issues and validate fixes. * **CI/CD Integration**: Incorporate automated testing in your deployment pipeline using [Virtual TestNets' API](https://docs.tenderly.co/reference/api?mtm_campaign=ext-docs\&mtm_kwd=optimism#/operations/createAlert) and [GitHub Actions integration](https://docs.tenderly.co/virtual-testnets/ci-cd/github-actions-foundry?mtm_campaign=ext-docs\&mtm_kwd=optimism). * **Development tools**: Rely on the built-in [developer explorer](https://docs.tenderly.co/developer-explorer?mtm_campaign=ext-docs\&mtm_kwd=optimism) and debugging tools to analyze test transactions and contract interactions. ## Integration with other products In many cases a decentralized application requires the services of other contracts. For example, [Perpetual v. 2](https://docs.perp.com/docs/guides/integration-guide) cannot function without [Uniswap v. 3](https://uniswap.org/blog/uniswap-v3). * If that is the case, you can use [mainnet forking](/app-developers/reference/tools/supersim/fork). It works with OP Stack chains. * Create a Virtual TestNet to get access to third party contracts (e.g. Uniswap) and it's latest or historical state. * Alternatively, you can connect to our [test network](/op-mainnet/network-information/connecting-to-op#op-sepolia) if those contracts are also deployed there (in many cases they are). # Estimating transaction fees on OP Mainnet Source: https://docs.optimism.io/app-developers/guides/transactions/estimates Learn how to properly estimate the total cost of a transaction on OP Mainnet. Check out the guide on understanding [Transaction Fees on OP Mainnet](/op-stack/transactions/fees) for an in-depth explanation of how OP Mainnet transaction fees work. It's important to properly estimate the cost of a transaction on OP Mainnet before submitting it to the network. Here you'll learn how to estimate both of the components that make up the total cost of an OP Mainnet transaction, the [execution gas fee](/op-stack/transactions/fees#execution-gas-fee) and the [L1 data fee](/op-stack/transactions/fees#l1-data-fee). Make sure to read the guide on [Transaction Fees on OP Mainnet](/op-stack/transactions/fees) for a detailed look at how these fees work under the hood. ## Execution gas fee Estimating the execution gas fee on OP Mainnet is just like estimating the execution gas fee on Ethereum. Steps are provided here for reference and convenience, but you can use the same tooling that you'd use to estimate the execution gas fee for a transaction on Ethereum. A transaction's execution gas fee is exactly the same fee that you would pay for the same transaction on Ethereum. This fee is equal to the amount of gas used by the transaction multiplied by the gas price attached to the transaction. Refer to the guide on [Transaction Fees on OP Mainnet](/op-stack/transactions/fees#execution-gas-fee) for more information about the execution gas fee. When estimating the execution gas fee for a transaction, you'll need to know the gas limit and the [max fee per gas](https://ethereum.org/en/developers/docs/gas/#maxfee) for the transaction. Your transaction fee will then be the product of these two values. Refer to the guide on [Setting Transaction Gas Parameters on OP Mainnet](./parameters) to learn how to select an appropriate gas limit and max fee per gas for your transaction. Using the same tooling that you'd use to estimate the gas limit for a transaction on Ethereum, estimate the gas limit for your transaction on OP Mainnet. OP Mainnet is designed to be [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306) so transactions will use the same amount of gas on OP Mainnet as they would on Ethereum. This means you can feed your transaction to the [`eth_estimateGas`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas) JSON-RPC method just like you would on Ethereum. Alternatively, use Tenderly's [`tenderly_estimateGas`](https://docs.tenderly.co/node/rpc-reference/optimism-mainnet/tenderly_estimateGas) for 100% accurate gas estimations. Like Ethereum, OP Mainnet uses an `EIP-1559` style fee market to determine the current base fee per gas. You can then additionally specify a priority fee (also known as a tip) to incentivize the Sequencer to include your transaction more quickly. Make sure to check out the guide on [Setting Transaction Gas Parameters on OP Mainnet](./parameters) to learn more about how to select an appropriate max fee per gas for your transaction. ## L1 data fee The Viem library provides a convenient method for estimating the L1 data fee for a transaction. Check out the tutorial on [Estimating Transaction Costs on OP Mainnet](/app-developers/tutorials/transactions/sdk-estimate-costs) to learn how to use the Viem library to estimate the L1 data fee for your transaction. Keep reading if you'd like to learn how to estimate the L1 data fee without the Viem library. The L1 data fee is a fee paid to the Sequencer for the cost of publishing your transaction to Ethereum. This fee is paid in ETH and is calculated based on the size of your transaction in bytes and the current gas price on Ethereum. Refer to the guide on [Transaction Fees on OP Mainnet](/op-stack/transactions/fees#l1-data-fee) for more information about the L1 data fee. Unlike the execution gas fee, the L1 data fee is an **intrinsic** fee for every transaction. This fee is automatically charged based on the size of your transaction and the current Ethereum gas price. You currently cannot specify a custom L1 data fee for your transaction. The L1 data fee is paid based on the current Ethereum gas price as tracked within the [`GasPriceOracle`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/GasPriceOracle.sol) smart contract. This gas price is updated automatically by the OP Mainnet protocol. Your transaction will be charged the Ethereum gas price seen by the protocol at the time that your transaction is included in an OP Mainnet block. This means that the L1 data fee for your transaction may differ from your estimated L1 data fee. The L1 data fee is calculated based on the size of your serialized transaction in bytes. Most Ethereum tooling will provide a method for serializing a transaction. For instance, Ethers.js provides the [`ethers.utils.serializeTransaction`](https://docs.ethers.org/v5/api/utils/transactions/#utils-serializeTransaction) method. Once you have serialized your transaction, you can estimate the L1 data fee by calling the [`getL1Fee`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/GasPriceOracle.sol#L64-L71) method on the [`GasPriceOracle`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/GasPriceOracle.sol) smart contract available on OP Mainnet and all OP Stack chains. This method takes the serialized transaction as input and returns the L1 data fee in wei using the formula described in the [Transaction Fees on OP Mainnet](/op-stack/transactions/fees#l1-data-fee) guide. Fee estimation is typically performed before the transaction is signed. As a result, the `getL1Fee` method assumes that your input is an **unsigned** Ethereum transaction. ### Tooling Several tools are available to help you estimate the L1 Data Fee for your transaction. Selecting the right tool for your use case will depend on your specific needs. * [Viem](https://viem.sh/op-stack#getting-started-with-op-stack) provides first-class support for OP Stack chains, including OP Mainnet. You can use Viem to estimate gas costs and send cross-chain transactions (like transactions through the Standard Bridge system). It's strongly recommended to use Viem if you are able to do so as it will provide the best native support at the moment. ### Future proofing The L1 Data Fee formula is subject to change in the future, especially as the data availability landscape evolves. As a result, it's important to future-proof your transaction fee estimation code to ensure that it will continue to function properly as the L1 Data Fee formula changes. * Use existing [tooling](#tooling) to estimate the L1 Data Fee for your transaction if possible. This tooling will be updated to reflect any changes to the L1 Data Fee formula. This way you won't need to modify your code to account for any changes to the formula. * Use the `getL1Fee` method on the `GasPriceOracle` if you are unable to use existing tooling. The `getL1Fee` method will be updated to reflect any changes to the L1 Data Fee formula. It's strongly recommended that you do **not** implement the L1 Data Fee formula yourself. # Integrate Subblocks in your app Source: https://docs.optimism.io/app-developers/guides/transactions/integrating-subblocks Query pre-confirmed Subblocks state from your app using standard JSON-RPC methods with the pending tag, or through viem and ethers. A chain that streams [Subblocks](/op-stack/features/subblocks) publishes a partial block every 200 ms, so your app can show a transaction's result well before the block containing it is sealed. This guide shows how to read that pre-confirmed state over standard Ethereum JSON-RPC and from the viem and ethers libraries. Most apps need only a change of endpoint and the `pending` block tag. * In production, point your app to a subblocks-aware RPC endpoint from your provider of choice. If your provider doesn't support subblocks yet, let us know on [Discord](https://discord.gg/jPQhHTdemH) and we'll work with them to get it added. * To run your own subblocks-aware node, start `op-reth` with `--flashblocks-url=` pointing at the chain's stream. The node then serves `pending` from the subblock state. OP Mainnet and OP Sepolia stream URLs are listed on the [network information page](/op-mainnet/network-information/connecting-to-op). This guide covers reading pre-confirmed state through an RPC endpoint, which is what most apps want. If you consume the WebSocket stream directly instead, four payload fields are zeroed and need handling — see the [Subblocks notice](/notices/subblocks). ## Supported RPC methods You read subblock state with the same Ethereum JSON-RPC calls you already use. The difference is using the "pending" tag in some of them to explicitly query the pre-confirmed state instead of the last finalized block. * **`eth_getBlockByNumber`**: Use the `pending` tag to retrieve the latest subblock snapshot. ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "number": "0x1234", "hash": "0x...", "transactions": [...] } } ``` * **`eth_call`**: Use the `pending` tag to execute calls against the most recent pre-confirmed state. ```json theme={null} { "jsonrpc": "2.0", "method": "eth_call", "params": [{"to": "0x...", "data": "0x..."}, "pending"], "id": 1 } ``` * `eth_getBalance` / `eth_getTransactionCount`: Use the `pending` tag to fetch balances or transaction counts respectively as they evolve within the block window. ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x0234" } ``` ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x1b" // 27 transactions } ``` Other methods, like `eth_getTransactionReceipt`, `eth_getTransactionByHash` or `eth_simulateV1`, return data from pre-confirmed transactions without requiring the `pending` tag. Consult the [Flashblocks specification](https://specs.optimism.io/protocol/flashblocks.html#flashblock-json-rpc-apis) for more details on each of these methods. ## Libraries You need a subblocks‑aware RPC endpoint to use the following libraries: ### Viem ```ts theme={null} import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { opSepolia } from 'viem/chains'; import { publicActionsL2, walletActionsL2 } from 'viem/op-stack'; const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`); const walletClient = createWalletClient({ account, chain: opSepolia, transport: http("https://sepolia.optimism.io"), }).extend(walletActionsL2()); const publicClient = createPublicClient({ chain: opSepolia, transport: http("https://sepolia.optimism.io"), }).extend(publicActionsL2()); const submissionTime = new Date(); const hash = await walletClient.sendTransaction({ to: '0x...', value: parseEther('0.0001'), }); // Wait for pre-confirmation const receipt = await publicClient.waitForTransactionReceipt({ hash }); const confirmTime = new Date(); console.log('pre-confirmed in ms:', confirmTime.getTime() - submissionTime.getTime()); ``` ### Ethers ```ts theme={null} import { ethers } from 'ethers'; // Here, provider is a subblocks-enabled RPC provider const provider = new ethers.JsonRpcProvider("https://sepolia.optimism.io"); const wallet = new ethers.Wallet(process.env.PRIVATE_KEY as string, provider); const tx = { to: '0x...', value: ethers.parseEther('0.0001') }; const submission = new Date(); const sent = await wallet.sendTransaction(tx); await sent.wait(0); const confirmed = new Date(); // should represent the transaction (pre)confirmation faster than standard RPC console.log('Pre-confirmed in ms:', confirmed.getTime() - submission.getTime()); // validates the transaction hash returned by the pre-confirmed transaction above const receipt = await provider.getTransactionReceipt(sent.hash); const validated = new Date(); console.log('Receipt validated in ms:', validated.getTime() - submission.getTime()); console.log('Transaction receipt:', receipt); ``` ## Next steps * Understand how subblocks affect [gas usage and large transactions](/app-developers/guides/transactions/subblocks-and-gas-usage). * Learn how subblocks work in the [Subblocks explainer](/op-stack/features/subblocks). * Review the [technical specs](https://specs.optimism.io/protocol/flashblocks.html) for architecture details. * Join our [community](https://discord.gg/jPQhHTdemH) to share best practices and get support! # Setting transaction gas parameters on OP Mainnet Source: https://docs.optimism.io/app-developers/guides/transactions/parameters Learn how to set gas parameters for transactions on OP Mainnet. OP Mainnet is designed to be [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306) which means that it is as compatible with Ethereum as possible, down to the client software used to run OP Mainnet nodes. Like Ethereum, OP Mainnet has an EIP-1559 style fee mechanism that dynamically adjusts a [base fee](https://ethereum.org/en/developers/docs/gas/#base-fee) that acts as the minimum fee that a transaction must pay to be included in a block. OP Mainnet also allows transactions to pay a [priority fee](https://ethereum.org/en/developers/docs/gas/#priority-fee) (also known as a tip) to incentivize the Sequencer to include transactions more quickly. Setting the base fee and the priority fee appropriately is important to ensure that your transactions are included in a timely manner. This guide will walk you through some best practices for determining the base fee and priority fee for your transactions. ## Selecting the base fee The base fee is the minimum fee that a transaction must pay to be included in a block. Transactions that specify a maximum fee per gas that is less than the current base fee cannot be included in the blockchain. The simplest way to select a base fee is to look at the latest available OP Mainnet block. Each OP Mainnet block includes the current base fee and the amount of gas used within that block. You can use this information to predict a reasonable maximum fee for your transaction. Note that, like Ethereum, the base fee is not explicitly defined within a transaction. Instead, the maximum base fee is determined as the difference between the `maxFeePerGas` and the `maxPriorityFeePerGas` fields of any given transaction. Using the JSON-RPC API or your favorite Ethereum library, retrieve the latest block on OP Mainnet. From the block, retrieve the `baseFeePerGas` and `gasUsed` fields. OP Mainnet adjusts the base fee based on the amount of gas used in the previous block. If the previous block used more than 5m gas (of the 30m gas limit), then the base fee will increase by up to 10%. If the previous block used less than 5m gas, then the base fee will decrease by up to 10%. Refer to the [OP Mainnet EIP-1559 Parameters](/op-stack/protocol/differences#eip-1559-parameters) section for more details. Using the current base fee per gas and the amount of gas used in the previous block, you can predict the next base fee per gas. If you are highly sensitive to the base fee, you may want to select a base fee per gas that is either 10% higher or 10% lower than the previous base fee. However, you may run the risk that your transaction will not be included in a block quickly. If you are less sensitive to the base fee, you may wish to simply use a large multiple of the previous base fee (e.g. 2x). ## Selecting the priority fee The priority fee is an optional tip that can be paid to the Sequencer to incentivize them to include your transaction more quickly. The priority fee is paid in addition to the base fee. The simplest way to select a priority fee is to use the [`eth_maxPriorityFeePerGas`](https://docs.alchemy.com/reference/eth-maxpriorityfeepergas) JSON-RPC method to retrieve an estimate for an acceptable priority fee. Many Ethereum libraries will provide a function to call this JSON-RPC method. You can also use the [`eth_feeHistory`](https://docs.alchemy.com/reference/eth-feehistory) JSON-RPC method to retrieve historical priority fee data. You can then use this data to predict a reasonable priority fee for your transaction. Alternatively, you can rely on Tenderly's [`tenderly_gasPrice`](https://docs.tenderly.co/node/rpc-reference/optimism-mainnet/tenderly_gasPrice?mtm_campaign=ext-docs\&mtm_kwd=optimism) to get real-time gas predictions with 3 levels of likelihood for transaction inclusion. # Transaction statuses on OP Mainnet Source: https://docs.optimism.io/app-developers/guides/transactions/statuses Reference for the statuses a transaction can have on OP Mainnet. This page is a reference for the statuses a transaction can have on OP Mainnet, listed in the order a transaction moves through them. Each entry gives the status, how long it typically takes to reach, what the status guarantees, and the JSON-RPC call used to observe it. Consult it when you need to troubleshoot a transaction, decide how many confirmations your application should wait for, or display accurate status information to your users. For an explanation of *why* a transaction moves through these states, see [Transaction flow](/op-stack/transactions/transaction-flow). ## Pending **Instant after sending to the Sequencer** A transaction is considered "pending" when it has been sent to the Sequencer but has not yet been included in a block. This is the first status a transaction will have after being sent to the Sequencer. At this point the transaction is not part of the blockchain and there is no guarantee that the transaction will be included in the blockchain. The list of all pending transactions can be retrieved by calling the standard JSON-RPC method [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) with the parameter `pending` as the block number. ## Sequencer confirmed or unsafe **Typically within 2-4 seconds** A transaction is considered "sequencer confirmed" or "unsafe" when it has been included in a block by the Sequencer but that block has **not** yet been published to Ethereum. Although the transaction is included in a block, it is still possible for the transaction to be excluded from the final blockchain if the Sequencer fails to publish the block to Ethereum within the [Sequencing Window](/connect/resources/glossary#sequencing-window) (approximately 12 hours). Applications should make sure to consider this possibility when displaying information about transactions that are in this state. The latest "sequencer confirmed" block can be retrieved by calling the standard JSON-RPC method [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) with the parameter `safe` as the block number and comparing this to the result returned for the `latest` block. If the `safe` block is behind the `latest` block, then the earliest "sequencer confirmed" block is the `safe` block plus one. ## Published to Ethereum or safe **Typically within 5-10 minutes, up to 12 hours** A transaction is considered "safe" when it has been included in a block by the Sequencer and that block has been published to Ethereum but that block is not yet finalized. Once a block has been published to Ethereum there is a high likelihood that the block will be included in the final blockchain. However, it is still possible for the block to be excluded from the final blockchain if the Ethereum blockchain experiences a reorganization. The latest "safe" block can be retrieved by calling the standard JSON-RPC method [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) with the parameter `safe` as the block number. Transactions typically become "safe" within a few minutes of becoming "sequencer confirmed". ## Finalized **Typically within 15-30 minutes, up to 12 hours** A transaction is considered "finalized" when it has been included in a block by the Sequencer, that block has been published to Ethereum, and that block has been finalized. Once a block has been finalized it is guaranteed to be included in the OP Mainnet blockchain. Applications that require the highest level of certainty that a transaction will be included in the blockchain should wait until the transaction is "finalized" before considering the transaction to be successful. The latest "finalized" block can be retrieved by calling the standard JSON-RPC method [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) with the parameter `finalized` as the block number. # Subblocks and gas usage on OP Stack Source: https://docs.optimism.io/app-developers/guides/transactions/subblocks-and-gas-usage Explains how Subblocks affect block gas usage, transaction inclusion, and why large transactions can be rejected or stay pending. This document explains how **subblocks** affect block gas usage, transaction inclusion, large-transaction handling, and how to avoid unexpected transaction rejections. If you are unfamiliar with subblocks you can read more in the [Subblocks explainer](/op-stack/features/subblocks). *** ## Background: Block Gas Limit vs. Transaction Gas Limit On OP Mainnet, the **theoretical block gas limit** is currently **40M gas**. In a traditional EVM mental model, a single transaction can use up to the full block gas limit, as long as it does not exceed it. With **subblocks**, block construction is incremental and *effective transaction inclusion depends on the gas already consumed within the block*, not just the theoretical maximum. *** ## What Are Subblocks? Subblocks are an incremental block-building mechanism: instead of constructing the full block at once, the sequencer's execution client assembles it as a series of subblocks, each of which adds to the *cumulative gas budget* available for inclusion. For what subblocks are and how a block's subblock count is determined, see the [Subblocks explainer](/op-stack/features/subblocks). The consequence for gas usage is that earlier subblocks can only include smaller transactions, and larger transactions fit only later in the block, *if enough gas remains*. ### Example Assume: * Block gas limit **B = 40M** * Number of subblocks **N = 10**, the count a 2-second block time and a 200 ms interval imply Then the cumulative gas limit increases as follows: | Subblock | Max cumulative gas available | | -------- | ---------------------------- | | 1 | 4M | | 2 | 8M | | 3 | 12M | | 4 | 16M | | 5 | 20M | | 6 | 24M | | 7 | 28M | | 8 | 32M | | 9 | 36M | | 10 | 40M | A transaction with a **20M gas limit** can only be included starting from subblock 5, *and only if prior subblocks have not already consumed that gas*. The subblock count is not fixed. Heavy execution in one interval leaves less time for the ones after it, so a real block may contain fewer subblocks than the interval implies. *** ## Why a Transaction Can Get Stuck A transaction may be submitted with a gas limit lower than the total block gas limit (e.g. **38M \< 40M**) and still remain pending or, depending on the EL implementation, be rejected with the error: `exceeds block gas limit`. This happens because transaction acceptance and transaction inclusion are decided by different components. Generally: * Incoming transactions first enter the Execution Layer txpool. * The EL checks whether `tx.gasLimit` exceeds the **full block gas limit**. * If it does, it rejects with `exceeds block gas limit`. * Otherwise, it keeps the transaction in the **pending/queued mempool** and **P2P-gossips** it, eventually reaching the **sequencer**. * The **sequencer's execution client** applies the incremental **remaining block gas** check to decide whether to include the tx in a subblock or leave it pending. ### Real-World Example * Block gas limit: **40M** * Gas already used in earlier subblocks: **13M** * Remaining gas: **27M** * Incoming transaction gas limit: **38M** The **EL** checks if the transaction exceeds **40M**. Since **38M \< 40M**, the transaction is accepted into the pending/queued mempool and gossiped to the **sequencer**. The sequencer's execution client applies the incremental remaining-gas constraint. With only **27M** gas remaining and the tx requiring **38M**, the transaction cannot be included yet and stays pending. **Result:** the transaction is not rejected, but remains pending in the mempool until there is enough remaining gas to include it in a subblock. *** ## Client Behavior and Error Messages There are two distinct outcomes depending on the transaction size: * **Rejected immediately (txpool admission failure):**\ The EL (e.g. **op-reth**) rejects transactions only when the transaction gas limit exceeds the **full block gas limit**: * Condition: `tx.gasLimit > blockGasLimit` * Error returned to the user: `exceeds block gas limit` * **Accepted but pending inclusion:**\ If the transaction gas limit is **within** the block gas limit, but still too large to fit into the **remaining block gas** at that point in the block, it will not be included yet. * The transaction remains in the **pending/queued mempool**, waiting for enough remaining gas to become available in a later subblock. * From the user’s perspective, the transaction may appear **pending** until it gets enough gas available for inclusion. In practice, transactions are sent to Execution Layer RPC nodes (e.g. via proxyd), checked, and only if accepted into the EL txpool are eventually propagated to the sequencer for potential inclusion. Implementing mechanisms such as txpool rebroadcasting can mitigate this divergence automatically, so users do not notice retries. However, when an error is surfaced, it may originate from the ingress client’s gas checks. *** ## Practical Guidance for Application Developers and End Users ### Leave Headroom for Large Transactions If you submit large transactions, avoid targeting the full block gas limit. **Recommended approach:** * Leave **20–30% headroom** relative to the block gas limit * For a 40M block, aim for ≤ **28–32M gas** Or: * Proactively cap single-transaction gas usage to \~16.7M gas to align with the upcoming L2 Fusaka transaction limit This increases the chance that the transaction fits within Execution Layer gas checks under partial block utilization. More generally, designing applications to avoid extremely large single transactions is good long-term practice since, with upcoming protocol changes (Fusaka on L2), transactions will be capped at 16.7M gas anyway. *** ### Expect Variable Gas Availability During Congestion Under high demand: * Early subblocks are often full * Remaining gas later in the block may be limited * Very large transactions may be rejected or require retries This is expected behavior with subblocks and not necessarily an issue with the transaction itself. *** ### Transaction Resubmission Because block state evolves quickly: * Retrying submission in a later block may succeed * Large transactions are more likely to be included when earlier subblocks are less congested *** ## Key Takeaways * Subblocks build blocks incrementally, unlocking gas capacity over time rather than all at once\ *(e.g. in a 40M gas block with 10 subblocks, only 4M is available at the first subblock, then 8M, and so on)* * A transaction must be **within the full block gas limit** to be accepted into the EL txpool, but it must fit within the **remaining block gas** to be included by the sequencer in the next subblock *(e.g. if 13M gas out of 40M has already been used, a 38M gas transaction can be accepted by EL but cannot be included until enough remaining gas is available once it reaches the sequencer)* * As a result, large transactions may be **accepted but remain pending** even when their gas limit is below the nominal block limit\ *(e.g. a 38M gas transaction can be accepted in a 40M gas block but delayed during periods of high activity)* * Leaving meaningful headroom is the most reliable way to improve inclusion success for large transactions\ *(e.g. targeting 28–32M gas instead of the full 40M or proactively implementing the Fusaka limit of 16.7M gas)* # Troubleshooting transactions Source: https://docs.optimism.io/app-developers/guides/transactions/troubleshooting Learn how to troubleshoot common problems with transactions. ## Transactions stuck in the transaction pool OP Chain uses EIP-1559, but with different parameters than L1 Ethereum. As a result, while the base fee on L1 can grow by up to 12.5% in a twelve-second period (in the case of a single 30M gas block), the L2 base fee can grow by up to 77% (in the case of six 30M gas blocks). However, it still shrinks by only up to 12.5% in the same twelve-second period (if all the blocks are empty). If the maximum fee per gas specified by the transaction is less than the block base fee, it does not get included until the base fee drops to below the value in the transaction. When this happens, some users may see their transaction become stuck. No ETH is lost, but the transaction does not clear on its own. We have a workaround that users and wallet operators can implement immediately, and we expect a protocol-level fix to be live by the end of Q4. ### Recommendation Set the maximum fee per gas for transactions to a relatively high value, such as 0.1 gwei. This will *not* increase the transaction cost because the same base fee, determined by a formula, is charged to all the transactions in the block. To save on the cost of L2 gas you want to minimize the max priority fee. Also, if the [current base fee](https://optimistic.grafana.net/public-dashboards/c84a5a9924fe4e14b270a42a8651ceb8?orgId=1\&refresh=5m) is comparable to 0.1 gwei or higher, you might want to suggest to users a higher multiple of the base fee than you would on L1 Ethereum because it can grow faster in the time interval between transaction creation and transaction signing and submission. #### Recommendations for wallet developers Wallets are usually in charge of determining the default priority fee and max fee that a transaction would include, so the above recommendations can be applied directly. #### Recommendations for app developers As an app developer, you can usually override the default recommendation of the wallet (see, for example, [ethers](https://github.com/ethers-io/ethers.js/blob/v5.7/packages/contracts/lib/index.d.ts#L10-L11)). As long as not all wallets are upgraded according to our recommendations, it makes sense for apps to get the current base fee and recommend a value based on that. #### Recommendations for users As a user, you are the final authority on transaction fields. Sometimes when submitting a transaction, the gas fee is set too low, and it gets stuck in the transaction pool (a.k.a. mempool). If you want to push that transaction through, [you can cancel it by submitting another transaction with the same nonce](https://info.etherscan.com/how-to-cancel-ethereum-pending-transactions/). This method increases the fee and the sequencer will process it from the mempool quicker. ## Deposit transactions don't have a chainId on L2 [Deposit transactions](https://specs.optimism.io/protocol/deposits.html?utm_source=op-docs\&utm_medium=docs#the-deposited-transaction-type) are transactions added to the L2 blockchain as part of the block derivation process. These transactions come from a dummy address and don't have a signature. Because in Ethereum the chainID is encoded as part of the signature, this means there is no recoverable chainID for these transactions. This is not a problem because the only source of deposit transactions is the block derivation process. There shouldn't be a need to recover the chainID. # App developers Source: https://docs.optimism.io/app-developers/index Routes app developers to the quickstarts, guides, tutorials, tools, and reference for building on OP Mainnet and other OP Stack chains. You are building an app on OP Mainnet or another OP Stack chain. Pick the path that matches where you are: start from zero, solve a specific task, or look something up. Go from zero to a working app on an OP Stack chain with the quickstart. Follow a guide for building and testing apps, bridging, interoperability, or transactions. Work through step-by-step tutorials, from deploying a contract to cross-chain messaging with Supersim. Choose supported SDKs, faucets, block explorers, and data tools for your stack. Find RPC providers, Actions SDK definitions, token lists, and Supersim reference material. Route by role from the documentation home: chain operators, node operators, and protocol learners each have their own section. # Integrating DeFi with Actions SDK Source: https://docs.optimism.io/app-developers/quickstarts/actions Perform DeFi actions with lightweight, composable, and type-safe modules. Actions SDK is still under construction and not ready for production use! This guide is meant for early testing purposes only. The [Actions SDK](https://actions.money/) is an open source Typescript development toolkit that simplifies the act of integrating DeFi into your application. ## How it works Here's a breakdown of what's under the hood: * **Modular Providers**: Actions is built with a set of core adapters called "Providers". Providers let you to pick an choose the right services and protocols for your use-case. * **Embedded Wallets**: Actions supports popular embedded [wallet providers](https://actions.money/#wallet), allowing your users to access DeFi with email authentication flows alone. * **Configure Actions**: Extend your embedded wallet with DeFi actions like Lend, Borrow, Swap, and Pay. Set multiple providers for each Action to choose the best markets across DeFi. * **Customize assets & chains**: Allow and block assets, markets, chains, and protocols from your application from a single config. ## Installation Install the Actions SDK in your project: ```bash npm theme={null} npm install @eth-optimism/actions-sdk ``` ```bash pnpm theme={null} pnpm add @eth-optimism/actions-sdk ``` ```bash yarn theme={null} yarn add @eth-optimism/actions-sdk ``` ```bash bun theme={null} bun add @eth-optimism/actions-sdk ``` ```bash deno theme={null} deno add @eth-optimism/actions-sdk ``` ## Choose a Wallet Provider Actions works with both frontend and backend wallets depending on your needs: Select a wallet provider: **Set Up Privy** Sign up for Privy and follow the full Privy installation [guide](https://docs.privy.io/basics/react/installation). **Configure Wallet Provider** Once you have set up Privy embedded wallets, pass them to Actions SDK: ```typescript theme={null} import { actions } from './config' import { useWallets } from '@privy-io/react-auth' // PRIVY: Fetch wallet const { wallets } = useWallets() const embeddedWallet = wallets.find( (wallet) => wallet.walletClientType === 'privy', ) // ACTIONS: Let wallet make onchain Actions const wallet = await actions.wallet.toActionsWallet({ connectedWallet: embeddedWallet, }) ``` **Configure Smart Wallets** Optionally, create signers for smart wallets you control: ```typescript theme={null} import { actions } from './config' import { useWallets } from '@privy-io/react-auth' // PRIVY: Fetch wallet const { wallets } = useWallets() const embeddedWallet = wallets.find( (wallet) => wallet.walletClientType === 'privy', ) // ACTIONS: Create signer from hosted wallet const signer = await actions.wallet.createSigner({ connectedWallet: embeddedWallet, }) // ACTIONS: Create smart wallet const { wallet } = await actions.wallet.createSmartWallet({ signer: signer }) ``` **Set Up Turnkey** Sign up for Turnkey and follow the full Turnkey installation [guide](https://docs.turnkey.com/sdks/react/getting-started). **Configure Wallet Provider** Once you have set up Turnkey embedded wallets, pass them to Actions SDK: ```typescript theme={null} import { useTurnkey, WalletSource } from "@turnkey/react-wallet-kit" import { actions, USDC, ExampleMarket } from './config' // Fetch Turnkey wallet const { wallets, httpClient, session } = useTurnkey() const embeddedWallet = wallets.find( (wallet) => wallet.accounts.some( (account) => account.addressFormat === 'ADDRESS_FORMAT_ETHEREUM', ) && wallet.source === WalletSource.Embedded, ) const walletAddress = embeddedWallet.accounts[0].address // Convert to Actions wallet const wallet = await actions.wallet.toActionsWallet({ client: httpClient, organizationId: session.organizationId, signWith: walletAddress, }) // Wallet can now take action const receipt = await wallet.lend.openPosition({ amount: 100, asset: USDC, ...ExampleMarket }) ``` **Configure Smart Wallets** Optionally, create signers for smart wallets you control: ```typescript theme={null} import { useTurnkey, WalletSource } from "@turnkey/react-wallet-kit" import { actions } from './config' // Fetch Turnkey wallet const { wallets, httpClient, session } = useTurnkey() const embeddedWallet = wallets.find( (wallet) => wallet.accounts.some( (account) => account.addressFormat === 'ADDRESS_FORMAT_ETHEREUM', ) && wallet.source === WalletSource.Embedded, ) const walletAddress = embeddedWallet.accounts[0].address // Create signer const signer = await actions.wallet.createSigner({ client: httpClient, organizationId: session.organizationId, signWith: walletAddress, }) // Create smart wallet const { wallet } = await actions.wallet.createSmartWallet({ signer: signer }) ``` **Set Up Dynamic** Sign up for Dynamic and follow the full Dynamic installation [guide](https://www.dynamic.xyz/docs/wallets/embedded-wallets/mpc/setup). **Configure Wallet Provider** Once you have set up Dynamic embedded wallets, pass them to Actions SDK: ```typescript theme={null} import { useDynamicContext } from "@dynamic-labs/sdk-react-core" import { actions, USDC, ExampleMarket } from './config' // Fetch Dynamic wallet const { primaryWallet } = useDynamicContext() // Convert to Actions wallet const wallet = await actions.wallet.toActionsWallet({ wallet: primaryWallet, }) // Wallet can now take action const receipt = await wallet.lend.openPosition({ amount: 100, asset: USDC, ...ExampleMarket }) ``` **Configure Smart Wallets** Optionally, create signers for smart wallets you control: ```typescript theme={null} import { useDynamicContext } from "@dynamic-labs/sdk-react-core" import { actions } from './config' // Fetch Dynamic wallet const { primaryWallet } = useDynamicContext() // Create signer const signer = await actions.wallet.createSigner({ wallet: primaryWallet }) // Create smart wallet const { wallet } = await actions.wallet.createSmartWallet({ signer: signer }) ``` Select a wallet provider: **Set Up Privy** Sign up for Privy and follow the full Privy installation [guide](https://docs.privy.io/basics/nodeJS/installation). **Configure Wallet Provider** Once you have set up Privy embedded wallets, pass them to Actions SDK: ```typescript theme={null} import { actions } from './config' import { PrivyClient } from '@privy-io/node' // PRIVY: Create wallet const privyClient = new PrivyClient(env.PRIVY_APP_ID, env.PRIVY_APP_SECRET) const privyWallet = await privyClient.wallets().create({ chain_type: 'ethereum', owner: { user_id: 'privy:did:xxxxx' }, }) // ACTIONS: Let wallet make onchain Actions const wallet = await actions.wallet.toActionsWallet({ walletId: privyWallet.id, address: privyWallet.address, }) ``` **Configure Smart Wallets** Optionally, create signers for smart wallets you control: ```typescript theme={null} import { actions } from './config' import { PrivyClient } from '@privy-io/node' import { getAddress } from 'viem' const privyClient = new PrivyClient(env.PRIVY_APP_ID, env.PRIVY_APP_SECRET) // PRIVY: Create wallet const privyWallet = await privyClient.wallets().create({ chain_type: 'ethereum', owner: { user_id: 'privy:did:xxxxx' }, }) // ACTIONS: Create signer const signer = await actions.wallet.createSigner({ walletId: privyWallet.id, address: getAddress(privyWallet.address), }) // ACTIONS: Create smart wallet const { wallet } = await actions.wallet.createSmartWallet({ signer: signer }) ``` **Set Up Turnkey** Sign up for Turnkey and follow the full Turnkey installation [guide](https://docs.turnkey.com/sdks/javascript-server). **Configure Wallet Provider** Once you have set up Turnkey embedded wallets, pass them to Actions SDK: ```typescript theme={null} import { Turnkey } from '@turnkey/sdk-server' import { actions, USDC, ExampleMarket } from './config' const turnkeyClient = new Turnkey({ apiBaseUrl: 'https://api.turnkey.com', apiPublicKey: process.env.TURNKEY_API_KEY, apiPrivateKey: process.env.TURNKEY_API_SECRET, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }) // Create Turnkey wallet const turnkeyWallet = await turnkeyClient.apiClient().createWallet({ walletName: 'ETH Wallet', accounts: [{ curve: 'CURVE_SECP256K1', pathFormat: 'PATH_FORMAT_BIP32', path: "m/44'/60'/0'/0/0", addressFormat: 'ADDRESS_FORMAT_ETHEREUM', }], }) // Convert to Actions wallet const wallet = await actions.wallet.toActionsWallet({ organizationId: turnkeyWallet.activity.organizationId, signWith: turnkeyWallet.addresses[0], }) // Wallet can now take action const receipt = await wallet.lend.openPosition({ amount: 100, asset: USDC, ...ExampleMarket }) ``` **Configure Smart Wallets** Optionally, create signers for smart wallets you control: ```typescript theme={null} import { Turnkey } from '@turnkey/sdk-server' import { actions } from './config' const turnkeyClient = new Turnkey({ apiBaseUrl: 'https://api.turnkey.com', apiPublicKey: process.env.TURNKEY_API_KEY, apiPrivateKey: process.env.TURNKEY_API_SECRET, defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, }) // Create Turnkey wallet const turnkeyWallet = await turnkeyClient.apiClient().createWallet({ walletName: 'ETH Wallet', accounts: [{ curve: 'CURVE_SECP256K1', pathFormat: 'PATH_FORMAT_BIP32', path: "m/44'/60'/0'/0/0", addressFormat: 'ADDRESS_FORMAT_ETHEREUM', }], }) // Create signer const signer = await actions.wallet.createSigner({ organizationId: turnkeyWallet.activity.organizationId, signWith: turnkeyWallet.addresses[0], }) // Create smart wallet const { wallet } = await actions.wallet.createSmartWallet({ signer: signer }) ``` ## Create your ActionsConfig Follow the [Configuring Actions](/app-developers/guides/configuring-actions) guide to define which protocols, chains, and assets to support. ## Take Action Once configured, you can use Actions to perform DeFi operations: ```typescript theme={null} import { USDC, ETH, USDT } from "@eth-optimism/actions-sdk/assets"; import { ExampleMarket } from "@/actions/markets"; // Enable asset lending in DeFi const lendReceipt = await wallet.lend.openPosition({ amount: 1, asset: USDC, ...ExampleMarket, }); // Manage user market positions const lendPosition = await wallet.lend.getPosition(market); // Fetch wallet balance const balance = await wallet.getBalance(); // ⚠️ COMING SOON const borrowReceipt = await wallet.borrow.openPosition({ amount: 1, asset: USDT, ...market, }); // ⚠️ COMING SOON const swapReceipt = await wallet.swap.execute({ amountIn: 1, assetIn: USDC, assetOut: ETH, }); // ⚠️ COMING SOON const sendReceipt = await wallet.send({ amount: 1, asset: USDC, to: "vitalik.eth", }); ``` ## Next Steps * [Configure Actions](/app-developers/guides/configuring-actions) to customize protocols, chains, and assets * Check out the [Actions demo](https://actions.money/earn) for a complete example application # App developer quickstart Source: https://docs.optimism.io/app-developers/quickstarts/get-started Get testnet ETH, deploy your first contract to OP Sepolia, and bridge assets - your first steps on the Superchain. OP Stack chains are [EVM equivalent](/op-stack/protocol/differences): everything you know from Ethereum works here, and everything you build here works across the OP Stack ecosystem. This quickstart takes you from zero to a deployed contract on the OP Sepolia testnet, using only free testnet funds. No real funds are needed at any point — everything below runs on testnets. ## Before you start You'll need: * A wallet you control (any EVM wallet works; you'll export or generate a private key for testnet use only). * A terminal with `curl` available. Use a fresh, testnet-only private key for tutorials. Never paste a key that holds real funds into a terminal. Grab free OP Sepolia ETH from the [Superchain Faucet](https://console.optimism.io/faucet). Other options are listed on the [testnet faucets page](/app-developers/tools-sdks/faucets). OP Sepolia's public RPC endpoint is `https://sepolia.optimism.io` and its chain ID is `11155420`. Verify you can reach it: ```bash theme={null} curl -s -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' \ https://sepolia.optimism.io ``` Expected result: `{"jsonrpc":"2.0","id":1,"result":"0xaa37dc"}` (`0xaa37dc` = 11155420). For other networks and production-grade endpoints, see [network information](/op-mainnet/network-information/connecting-to-op) and [RPC providers](/app-developers/reference/rpc-providers). Follow the [Deploy a contract to OP Sepolia](/app-developers/tutorials/deploy-a-contract) tutorial. It walks you through installing Foundry, deploying a small `Greeter` contract, and reading and writing to it from the command line — the same workflow you'd use on Ethereum. Apps often need to move assets between Ethereum and an OP Stack chain. Start with [Bridging basics](/app-developers/guides/bridging/basics) to understand the model, then follow the [Bridging ETH with Viem](/app-developers/tutorials/bridging/cross-dom-bridge-eth) tutorial to do a Sepolia → OP Sepolia deposit programmatically. ## Where to go next Development workflow, tooling, and what (little) is different from Ethereum. Test against OP Stack chains locally and in CI. Build apps that span multiple Superchain chains. Lend, borrow, and swap with lightweight, type-safe modules (early preview — not production-ready). **Running your app in production** A production application depends on infrastructure your team does not run: RPC endpoints that hold up under real traffic (the public endpoints are rate-limited and not built for production), bridges your users rely on, and a chain whose operator keeps sequencing, upgrades, and incident response going around the clock. These docs cover building and testing. If your application is growing toward dedicated blockspace of its own, [OP Enterprise](https://optimism.io/op-enterprise?utm_source=docs\&utm_medium=docs\&utm_campaign=op-enterprise) offers managed and supported paths to running a chain. These docs stay the reference for what you build either way. OP Enterprise is Optimism's managed offering. ## Need help? * Ask a question or report documentation issues on the [Optimism monorepo issue tracker](https://github.com/ethereum-optimism/optimism/issues). # Integrating wallets Source: https://docs.optimism.io/app-developers/reference/actions/integrating-wallets Understand the wallet options Actions SDK supports, embedded wallet providers, gas sponsorship, and smart wallets. ## Which wallets are right for my use case? In order to let your users access DeFi, they will need an EVM-compatible wallet. There are plenty of considerations when selecting a wallet schema that works for you: * Who will maintain custody of funds? * What permissions must exist for my use case? * Where in my stack should transaction signatures originate? * How can my users on and off ramp funds? Actions SDK supports popular [embedded wallet providers](#embedded-wallet-providers) to address all of these questions while remaining flexible to your use case. ## Embedded Wallet Providers Embedded wallet providers give your users the ability to sign onchain transactions through your app's existing email authentication and authorization flows. Actions works with: ## Gas Sponsorship Signing and sending onchain transactions requires gas, or fee payment, which adds [additional overhead](/app-developers/guides/transactions/estimates) for you and friction for users. Actions supports gas sponsorship via a combination of smart contract wallets and [paymasters](https://eips.ethereum.org/EIPS/eip-7677). First, configure a paymaster in the chain config by specifying a bundler url. Now, any transactions submitted via an actions SmartWallet on that chain will automatically use your paymaster, therefore eliminating the need for the wallet to pay gas. ## Connect your wallet to Actions Regardless of where and how transactions are signed, Actions has you covered. Once you've chosen a wallet provider, follow the guide on [connecting a wallet to Actions SDK](/app-developers/guides/connect-wallet-to-actions) to pass the provider wallet to Actions and start calling Actions functions like Lend, Borrow, Swap, and Pay. ## Smart wallets & signers In addition to using embedded provider wallets directly, Actions [supports the creation](/app-developers/quickstarts/actions#choose-a-wallet-provider) of custom smart contract wallets. This additional wallet type is separate from, but still controlled by the owner of the embedded wallet. If you [configure it](/app-developers/guides/configuring-actions), Actions will deploy a [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) compliant [Coinbase Smart Wallets](https://github.com/coinbase/smart-wallet) on the chains you've chosen to support. Once created, an embedded wallet can be added as a signer on the smart wallet, capable of signing transactions on behalf of the Smart Wallet. See [Wallet Documentation](/app-developers/reference/actions/wallet-definitions) for additional details. # Lend Documentation Source: https://docs.optimism.io/app-developers/reference/actions/lend-documentation API reference for Actions SDK lending operations, functions, and parameters. ## WalletLendNamespace Wallet Lend Namespace ### Methods | Function | Description | | --------------------------------------------- | -------------------------------------------------------- | | **[getMarkets()](#getmarkets)** | Get all markets across all configured providers | | **[getMarket()](#getmarket)** | Get a specific market by routing to the correct provider | | **[supportedChainIds()](#supportedchainids)** | Get supported chain IDs across all providers | | **[openPosition()](#openposition)** | Open a lending position | | **[getPosition()](#getposition)** | Get position information for this wallet | | **[closePosition()](#closeposition)** | Close a lending position (withdraw from market) | #### `getMarkets()` Get all markets across all configured providers | Parameter | Type | Description | | --------- | ---------------------- | ----------------------------- | | `params` | `GetLendMarketsParams` | Optional filtering parameters | **Returns:** Promise resolving to array of markets from all providers [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/lend/namespaces/BaseLendNamespace.ts#L25) *** #### `getMarket()` Get a specific market by routing to the correct provider | Parameter | Type | Description | | --------- | --------------------- | ----------------- | | `params` | `GetLendMarketParams` | Market identifier | **Returns:** Promise resolving to market information [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/lend/namespaces/BaseLendNamespace.ts#L37) *** #### `supportedChainIds()` Get supported chain IDs across all providers **Returns:** Array of unique chain IDs supported by any provider [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/lend/namespaces/BaseLendNamespace.ts#L46) *** #### `openPosition()` Open a lending position | Parameter | Type | Description | | ----------------- | ------------------------ | ------------------------------------- | | `params` | `LendOpenPositionParams` | Lending position parameters | | `params.marketId` | | Market identifier to open position in | | `params.amount` | `number` | Amount to lend | **Returns:** Promise resolving to transaction receipt [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/lend/namespaces/WalletLendNamespace.ts#L34) *** #### `getPosition()` Get position information for this wallet | Parameter | Type | Description | | ----------------- | ------------------- | -------------------------------- | | `params` | `GetPositionParams` | Position query parameters | | `params.marketId` | `LendMarketId` | Market identifier (required) | | `params.asset` | `Asset` | Asset filter (not yet supported) | **Returns:** Promise resolving to position information [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/lend/namespaces/WalletLendNamespace.ts#L54) *** #### `closePosition()` Close a lending position (withdraw from market) | Parameter | Type | Description | | ----------------- | --------------------- | -------------------------------------- | | `params` | `ClosePositionParams` | Position closing parameters | | `params.marketId` | `LendMarketId` | Market identifier to close position in | | `params.amount` | `number` | Amount to withdraw | **Returns:** Promise resolving to transaction receipt [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/lend/namespaces/WalletLendNamespace.ts#L75) *** # Swap Documentation Source: https://docs.optimism.io/app-developers/reference/actions/swap-documentation API reference for Actions SDK swap operations, functions, and parameters. ## WalletSwapNamespace Wallet swap namespace with full operations including signing. Provides getQuote() for pricing and execute() for swapping tokens. ### Methods | Function | Description | | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | **[getQuote()](#getquote)** | Get a swap quote with the wallet address as recipient. Ensures calldata is encoded for the real wallet, not a placeholder. | | **[getQuotes()](#getquotes)** | Get quotes from all providers with the wallet address as recipient. | | **[getMarket()](#getmarket)** | Get a specific swap market by ID. | | **[getMarkets()](#getmarkets)** | Get available swap markets across all providers | | **[supportedChainIds()](#supportedchainids)** | Get all supported chain IDs across all providers | | **[execute()](#execute)** | Execute a token swap. Accepts either raw params (re-quotes internally) or a pre-built SwapQuote (skips re-quoting). | #### `getQuote()` Get a swap quote with the wallet address as recipient. Ensures calldata is encoded for the real wallet, not a placeholder. | Parameter | Type | Description | | --------- | ----------------- | ----------- | | `params` | `SwapQuoteParams` | | [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/swap/namespaces/WalletSwapNamespace.ts#L32) *** #### `getQuotes()` Get quotes from all providers with the wallet address as recipient. | Parameter | Type | Description | | --------- | ----------------- | ----------- | | `params` | `SwapQuoteParams` | | [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/swap/namespaces/WalletSwapNamespace.ts#L42) *** #### `getMarket()` Get a specific swap market by ID. | Parameter | Type | Description | | ---------- | --------------------- | ----------------------------------------------------------------- | | `params` | `GetSwapMarketParams` | Market identifier (poolId + chainId) | | `provider` | `SwapProviderName` | Optional provider name to query directly instead of searching all | **Returns:** Market information [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/swap/namespaces/BaseSwapNamespace.ts#L145) *** #### `getMarkets()` Get available swap markets across all providers | Parameter | Type | Description | | --------- | ---------------------- | -------------------------------------- | | `params` | `GetSwapMarketsParams` | Optional filtering by chainId or asset | **Returns:** Promise resolving to array of markets from all providers [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/swap/namespaces/BaseSwapNamespace.ts#L174) *** #### `supportedChainIds()` Get all supported chain IDs across all providers [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/swap/namespaces/BaseSwapNamespace.ts#L184) *** #### `execute()` Execute a token swap. Accepts either raw params (re-quotes internally) or a pre-built SwapQuote (skips re-quoting). | Parameter | Type | Description | | | --------- | ------------------ | ----------- | -------------------------------------------------------- | | `params` | \`WalletSwapParams | SwapQuote\` | Swap parameters or a pre-built SwapQuote from getQuote() | **Returns:** Swap receipt with transaction details [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/swap/namespaces/WalletSwapNamespace.ts#L55) *** # Wallet Documentation Source: https://docs.optimism.io/app-developers/reference/actions/wallet-definitions API reference for Actions SDK wallet classes, functions, and parameters. ## WalletNamespace Wallet namespace that provides unified wallet operations ### Methods | Function | Description | | --------------------------------------------------- | -------------------------------------------------------- | | **[hostedWalletProvider()](#hostedwalletprovider)** | Get direct access to the hosted wallet provider | | **[smartWalletProvider()](#smartwalletprovider)** | Get direct access to the smart wallet provider | | **[createSmartWallet()](#createsmartwallet)** | Create a new smart wallet | | **[createSigner()](#createsigner)** | Create a viem LocalAccount signer from the hosted wallet | | **[toActionsWallet()](#toactionswallet)** | Convert a hosted wallet to an Actions wallet | | **[getSmartWallet()](#getsmartwallet)** | Get an existing smart wallet with a provided signer | #### `hostedWalletProvider()` Get direct access to the hosted wallet provider **Returns:** Promise resolving to the configured hosted wallet provider instance [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/namespace/WalletNamespace.ts#L86) *** #### `smartWalletProvider()` Get direct access to the smart wallet provider **Returns:** Promise resolving to the configured smart wallet provider instance [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/namespace/WalletNamespace.ts#L98) *** #### `createSmartWallet()` Create a new smart wallet | Parameter | Type | Description | | --------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------ | | `params` | `CreateSmartWalletOptions` | Smart wallet creation parameters | | `params.signer` | `LocalAccount` | Primary local account used for signing transactions | | `params.signers` | `Signer[]` | Optional array of additional signers for the smart wallet | | `params.nonce` | `bigint` | Optional nonce for smart wallet address generation (defaults to 0) | | `params.deploymentChainIds` | `SupportedChainId[]` | Optional chain IDs to deploy the wallet to. | | If not provided, the wallet will be deployed to all supported chains. | | | **Returns:** Promise resolving to deployment result containing: * `wallet`: The created SmartWallet instance * `deployments`: Array of deployment results with chainId, receipt, success flag, and error [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/namespace/WalletNamespace.ts#L120) *** #### `createSigner()` Create a viem LocalAccount signer from the hosted wallet | Parameter | Type | Description | | --------- | ------------------------------------ | ---------------------------- | | `params` | `TToActionsMap[THostedProviderType]` | Configuration for the signer | **Returns:** Promise resolving to a viem `LocalAccount` with the hosted wallet as the signer backend [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/namespace/WalletNamespace.ts#L136) *** #### `toActionsWallet()` Convert a hosted wallet to an Actions wallet | Parameter | Type | Description | | ----------------- | ------------------------------------ | -------------------------------------------------------------- | | `params` | `TToActionsMap[THostedProviderType]` | Parameters for converting a hosted wallet to an Actions wallet | | `params.walletId` | | Unique identifier for the hosted wallet | | `params.address` | | Ethereum address of the hosted wallet | **Returns:** Promise resolving to the Actions wallet instance [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/namespace/WalletNamespace.ts#L151) *** #### `getSmartWallet()` Get an existing smart wallet with a provided signer | Parameter | Type | Description | | -------------------------- | ----------------------- | ------------------------------------------------------------------ | | `params` | `GetSmartWalletOptions` | Wallet retrieval parameters | | `params.signer` | `LocalAccount` | Local account to use for signing transactions on the smart wallet | | `params.signers` | `Signer[]` | Optional array of additional signers for the smart wallet | | `params.deploymentSigners` | `Signer[]` | Optional array of signers used during wallet deployment | | `params.walletAddress` | `Address` | Optional explicit smart wallet address (skips address calculation) | | `params.nonce` | `bigint` | Optional nonce used during smart wallet creation | **Returns:** Promise resolving to the smart wallet instance with the provided signer [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/namespace/WalletNamespace.ts#L173) *** ## Wallet Base actions wallet class ### Namespaces | Namespace | Type | Description | | --------- | --------------------- | ------------------------------------------ | | `lend` | `WalletLendNamespace` | Lend namespace with all lending operations | | `swap` | `WalletSwapNamespace` | Swap namespace with all swap operations | ### Properties | Property | Type | Description | | --------- | -------------- | -------------------------------------- | | `address` | `Address` | Get the address of this actions wallet | | `signer` | `LocalAccount` | Get a signer for this actions wallet | ### Methods | Function | Description | | ------------------------------- | ------------------------------------------------------ | | **[getBalance()](#getbalance)** | Get asset balances across all supported chains | | **[send()](#send)** | Send a transaction using this actions wallet | | **[sendBatch()](#sendbatch)** | Send a batch of transactions using this actions wallet | #### `getBalance()` Get asset balances across all supported chains **Returns:** Promise resolving to array of token balances with chain breakdown [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/wallets/abstract/Wallet.ts#L89) *** #### `send()` Send a transaction using this actions wallet | Parameter | Type | Description | | ----------------- | ------------------ | ------------------------------- | | `transactionData` | `TransactionData` | The transaction data to execute | | `chainId` | `SupportedChainId` | Target blockchain chain ID | **Returns:** Promise resolving to the transaction hash [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/wallets/abstract/Wallet.ts#L150) *** #### `sendBatch()` Send a batch of transactions using this actions wallet | Parameter | Type | Description | | ----------------- | ------------------- | ------------------------------- | | `transactionData` | `TransactionData[]` | The transaction data to execute | | `chainId` | `SupportedChainId` | Target blockchain chain ID | **Returns:** Promise resolving to the transaction hash [ Source ↗](https://github.com/ethereum-optimism/actions/blob/@eth-optimism/actions-sdk@0.4.0/packages/sdk/src/wallet/core/wallets/abstract/Wallet.ts#L162) *** # Interoperability predeploys Source: https://docs.optimism.io/app-developers/reference/contracts/interop/predeploy Learn how interoperability predeploys work. OP Stack interop is in active development. Some features may be experimental. The following predeploys have been added to enable interoperability. *Predeployed smart contracts* exist at predetermined addresses, coming from the genesis state. They're similar to [precompiles](https://www.evm.codes/precompiled) but run directly in the EVM instead of running as native code. ## CrossL2Inbox The `CrossL2Inbox` is the system predeploy for cross chain messaging. Anyone can trigger the execution or validation of cross chain messages, on behalf of any user. * **Address:** `0x4200000000000000000000000000000000000022` * **Specs:** [`CrossL2Inbox`](https://specs.optimism.io/interop/predeploys.html?utm_source=op-docs\&utm_medium=docs#crossl2inbox) * **Source code:** [`CrossL2Inbox`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol) ## L2ToL2CrossDomainMessenger The `L2ToL2CrossDomainMessenger` is a higher level abstraction on top of the `CrossL2Inbox` that provides general message passing. It's utilized for secure ERC20 token transfers between L2 chains. Messages sent through the `L2ToL2CrossDomainMessenger` on the source chain receive both replay protection and domain binding (the executing transaction can only be valid on a single chain). * **Address:** `0x4200000000000000000000000000000000000023` * **Specs:** [`L2ToL2CrossDomainMessenger`](https://specs.optimism.io/interop/predeploys.html?utm_source=op-docs\&utm_medium=docs#l2tol2crossdomainmessenger) * **Source code:** [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol) ## SuperchainETHBridge The `SuperchainETHBridge` is a predeploy contract that facilitates cross-chain ETH bridging within the OP Stack interop cluster. It serves as an abstraction layer on top of the `L2ToL2CrossDomainMessenger` specifically designed for native ETH transfers between chains. The contract integrates with the `ETHLiquidity` contract to manage native ETH liquidity across chains, ensuring seamless cross-chain transfers of native ETH. * **Address:** `0x4200000000000000000000000000000000000024` * **Specs:** [`SuperchainETHBridge`](https://specs.optimism.io/interop/superchain-eth-bridge.html) * **Source code:** [`SuperchainETHBridge`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/SuperchainETHBridge.sol) ## ETHLiquidity The `ETHLiquidity` contract is a predeploy that manages native ETH liquidity for cross-chain transfers within the OP Stack interop set. It works in conjunction with the `SuperchainETHBridge` to facilitate the movement of ETH between chains without requiring modifications to the EVM to generate new ETH. The contract is initialized with a very large balance (type(uint248).max wei) to ensure it can handle all legitimate minting operations. This design allows the `SuperchainETHBridge` to have a guaranteed source of ETH liquidity on each chain, which is essential for the cross-chain ETH transfer mechanism. * **Address:** `0x4200000000000000000000000000000000000025` * **Specs:** [`ETHLiquidity`](https://specs.optimism.io/interop/eth-liquidity.html) * **Source code:** [`ETHLiquidity`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/ETHLiquidity.sol) ## SuperchainTokenBridge The `SuperchainTokenBridge` is an abstraction on top of the `L2ToL2CrossDomainMessenger` that facilitates token bridging using interop, as described in the [token bridging spec](https://specs.optimism.io/interop/token-bridging.html). * **Address:** `0x4200000000000000000000000000000000000028` * **Specs:** [`SuperchainTokenBridge`](https://specs.optimism.io/interop/predeploys.html?utm_source=op-docs\&utm_medium=docs#superchaintokenbridge) * **Source code:** [`SuperchainTokenBridge`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol) ## Next steps * Learn [how messages get from one chain to another chain](/app-developers/guides/interoperability/message-passing) # OP Stack RPC directory Source: https://docs.optimism.io/app-developers/reference/rpc-providers Find public RPC endpoints and production RPC providers across all OP Stack networks. This directory provides developers with a comprehensive collection of RPC endpoints across all OP Stack networks, making it easier to build, deploy, and scale applications on the OP Stack ecosystem. ## Public RPC endpoints The following table lists public RPC endpoints for all OP Stack networks. These endpoints are **rate-limited and not suitable for production use**, but are perfect for development, testing, and proof-of-concept work. For production use, please see the [Production RPC Providers](#production-rpc-providers) section below. | Chain | Public RPC URL | Documentation | | ---------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | OP Mainnet | [https://mainnet.optimism.io](https://mainnet.optimism.io) | [Docs](https://docs.optimism.io/superchain/networks) | | Base | [https://mainnet.base.org](https://mainnet.base.org) | [Docs](https://docs.base.org/chain/network-information) | | Ink | [https://rpc-gel.inkonchain.com](https://rpc-gel.inkonchain.com) | [Docs](https://docs.inkonchain.com/general/network-information) | | Unichain | [https://mainnet.unichain.org](https://mainnet.unichain.org) | [Docs](https://docs.unichain.org/docs/technical-information/network-information) | | Soneium | [https://rpc.soneium.org/](https://rpc.soneium.org/) | [Docs](https://docs.soneium.org/docs/builders/overview) | | Mode | [https://mainnet.mode.network/](https://mainnet.mode.network/) | [Docs](https://docs.mode.network/user-guides/network-details) | | Zora | [https://rpc.zora.energy](https://rpc.zora.energy) | [Docs](https://docs.zora.co/zora-network/network) | | Swell | [https://swell-mainnet.alt.technology](https://swell-mainnet.alt.technology) | [Docs](https://build.swellnetwork.io/docs/guides/getting-started) | | Arena-Z | [https://rpc.arena-z.gg](https://rpc.arena-z.gg) | [Docs](https://raas.gelato.network/rollups/details/public/arena-z) | | Metal | [https://rpc.metall2.com](https://rpc.metall2.com) | [Docs](https://docs.metall2.com/chain/networks) | | World | [https://worldchain-mainnet.g.alchemy.com/public](https://worldchain-mainnet.g.alchemy.com/public) | [Docs](https://docs.world.org/world-chain/quick-start/info) | | Lisk | [https://rpc.api.lisk.com](https://rpc.api.lisk.com) | [Docs](https://docs.lisk.com/network-info/) | | Polynomial | [https://rpc.polynomial.fi](https://rpc.polynomial.fi) | [Docs](https://docs.polynomial.fi/links) | | Mint | [https://rpc.mintchain.io](https://rpc.mintchain.io) | [Docs](https://docs.mintchain.io/build/network) | | Superseed | [https://mainnet.superseed.xyz](https://mainnet.superseed.xyz) | [Docs](https://docs.superseed.xyz/build-on-superseed/network-information) | | Shape | [https://mainnet.shape.network](https://mainnet.shape.network) | [Docs](https://docs.shape.network/technical-details/network-information) | | Epic | [https://mainnet.ethernitychain.io](https://mainnet.ethernitychain.io) | [Docs](https://docs.ethernity.io/introduction/network-information) | | Race | [https://racemainnet.io](https://racemainnet.io) | [Docs](https://raceecosystem.gitbook.io/docs/building-on-race-tm/network-information) | | BoB | [https://rpc.gobob.xyz/](https://rpc.gobob.xyz/) | [Docs](https://docs.gobob.xyz/learn/user-guides/getting-started/networks) | | Chain | Public RPC URL | Documentation | | ------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | OP Sepolia | [https://sepolia.optimism.io](https://sepolia.optimism.io) | [Docs](https://docs.optimism.io/superchain/networks) | | Base Sepolia | [https://sepolia.base.org](https://sepolia.base.org) | [Docs](https://docs.base.org/chain/network-information) | | Ink Sepolia | [https://rpc-gel-sepolia.inkonchain.com](https://rpc-gel-sepolia.inkonchain.com) | [Docs](https://docs.inkonchain.com/general/network-information) | | Unichain Sepolia | [https://sepolia.unichain.org](https://sepolia.unichain.org) | [Docs](https://docs.unichain.org/docs/technical-information/network-information) | | Soneium Sepolia | [https://rpc.minato.soneium.org/](https://rpc.minato.soneium.org/) | [Docs](https://docs.soneium.org/docs/builders/overview) | | Mode Sepolia | [https://sepolia.mode.network](https://sepolia.mode.network) | [Docs](https://docs.mode.network/user-guides/network-details) | | Zora Sepolia | [https://sepolia.rpc.zora.energy](https://sepolia.rpc.zora.energy) | [Docs](https://docs.zora.co/zora-network/network) | | Swell Sepolia | [https://swell-testnet.alt.technology](https://swell-testnet.alt.technology) | [Docs](https://build.swellnetwork.io/docs/guides/getting-started) | | Arena-Z Testnet | [https://rpc.arena-z.t.raas.gelato.cloud](https://rpc.arena-z.t.raas.gelato.cloud) | [Docs](https://raas.gelato.network/rollups/details/public/arena-z) | | Metal Testnet | [https://testnet.rpc.metall2.com/](https://testnet.rpc.metall2.com/) | [Docs](https://docs.metall2.com/chain/networks) | | World Sepolia | [https://worldchain-sepolia.g.alchemy.com/public](https://worldchain-sepolia.g.alchemy.com/public) | [Docs](https://docs.world.org/world-chain/quick-start/info) | | Lisk Sepolia | [https://rpc.sepolia-api.lisk.com](https://rpc.sepolia-api.lisk.com) | [Docs](https://docs.lisk.com/network-info/) | | Polynomial Sepolia | [https://rpc.sepolia.polynomial.fi](https://rpc.sepolia.polynomial.fi) | [Docs](https://docs.polynomial.fi/links) | | Mint Sepolia | [https://sepolia-testnet-rpc.mintchain.io](https://sepolia-testnet-rpc.mintchain.io) | [Docs](https://docs.mintchain.io/build/network) | | Superseed Sepolia | [https://sepolia.superseed.xyz](https://sepolia.superseed.xyz) | [Docs](https://docs.superseed.xyz/build-on-superseed/network-information) | | Shape Sepolia | [https://sepolia.shape.network](https://sepolia.shape.network) | [Docs](https://docs.shape.network/technical-details/network-information) | | Epic Testnet | [https://testnet.ethernitychain.io](https://testnet.ethernitychain.io) | [Docs](https://docs.ethernity.io/introduction/network-information) | | Race Testnet | [https://racetestnet.io](https://racetestnet.io) | [Docs](https://raceecosystem.gitbook.io/docs/building-on-race-tm/network-information) | | BoB Sepolia | [https://sepolia.rpc.gobob.xyz/](https://sepolia.rpc.gobob.xyz/) | [Docs](https://docs.gobob.xyz/learn/user-guides/getting-started/networks) | ## Production RPC providers The following providers offer production-grade RPC access to OP Stack networks. Most providers offer both free tiers with higher rate limits than public RPCs and paid plans for production applications. ### 1RPC **Description**: [1RPC](https://www.1rpc.io/) offers [free and paid plans](https://www.1rpc.io/#pricing) for the following [networks](https://docs.1rpc.io/using-the-web3-api/networks): **Supported Testnets**: Mode Sepolia, World Sepolia **Supported Mainnets**: OP Mainnet, Mode, Base ### Ankr **Description**: [Ankr](https://www.ankr.com/) offers [free and paid plans](https://www.ankr.com/rpc/pricing/) for the following [networks](https://www.ankr.com/rpc/): **Supported Testnets**: OP Sepolia, Swell Sepolia, Base Sepolia **Supported Mainnets**: OP Mainnet, Swell, Base ### Alchemy **Description**: [Alchemy](https://www.alchemy.com/) offers [free and paid plans](https://www.alchemy.com/pricing) for the following [networks](https://docs.alchemy.com/reference/api-overview): **Supported Testnets**: OP Sepolia, Ink Sepolia, Unichain Sepolia, Soneium Sepolia, Base Sepolia, World Sepolia, Shape Sepolia **Supported Mainnets**: OP Mainnet, Ink, Unichain, Soneium, Base, World, Shape ### All That Node **Description**: [All That Node](https://www.allthatnode.com/) offers [free and paid plans](https://www.allthatnode.com/pricing.dsrv) for the following [networks](https://docs.allthatnode.com/docs/supported-protocols-1): **Supported Testnets**: OP Sepolia **Supported Mainnets**: OP Mainnet, Base ### Blast **Description**: [Blast](https://blastapi.io/) offers [free and paid plans](https://blastapi.io/pricing) for the following [networks](https://blastapi.io/chains): **Supported Testnets**: OP Sepolia, Mode Sepolia, Base Sepolia, BoB Sepolia **Supported Mainnets**: OP Mainnet, Mode, Base, BoB ### Blockdaemon **Description**: [Blockdaemon](https://www.blockdaemon.com/) offers [free and paid plans](https://www.blockdaemon.com/api/pricing) for the following [networks](https://www.blockdaemon.com/protocols): **Supported Testnets**: OP Sepolia, Unichain Sepolia, Base Sepolia **Supported Mainnets**: OP Mainnet, Unichain, Base ### BlockPI **Description**: [BlockPI](https://blockpi.io/) offers [free and paid plans](https://blockpi.io/pricing) for the following [networks](https://blockpi.io/chains): **Supported Testnets**: OP Sepolia, Unichain Sepolia, Base Sepolia **Supported Mainnets**: OP Mainnet, Unichain, Base ### Chainstack **Description**: [Chainstack](https://chainstack.com/) offers [free and paid plans](https://chainstack.com/pricing/) for the following [networks](https://chainstack.com/protocols/): **Supported Testnets**: OP Sepolia, Base Sepolia **Supported Mainnets**: OP Mainnet, Base ### dRPC NodeCloud **Description**: [dRPC](https://drpc.org/nodecloud-multichain-rpc-management) offers [free and paid plans](https://drpc.org/pricing) for the following [networks](https://drpc.org/chainlist): **Supported Testnets**: OP Sepolia, Ink Sepolia, Unichain Sepolia, Soneium Sepolia, Mode Sepolia, Zora Sepolia, Swell Sepolia, Metal Sepolia, Base Sepolia, World Sepolia, Lisk Sepolia, Superseed Sepolia, BoB Sepolia **Supported Mainnets**: OP Mainnet, Ink, Unichain, Soneium, Mode, Zora, Swell, Metal, Base, World, Lisk, Superseed, BoB ### GetBlock **Description**: [GetBlock](https://getblock.io/) offers [free and paid plans](https://getblock.io/pricing/) for the following [networks](https://docs.getblock.io/api-reference/overview#supported-networks): **Supported Testnets**: OP Sepolia **Supported Mainnets**: OP Mainnet ### Grove **Description**: [Grove](https://grove.city/) offers [free and paid plans](https://www.grove.city/pricing) for the following [networks](https://www.grove.city/services): **Supported Testnets**: OP Sepolia, Base Sepolia **Supported Mainnets**: OP Mainnet, Base Mainnet, Ink Mainnet ### Infura **Description**: [Infura](https://infura.io) offers [free and paid plans](https://www.infura.io/pricing) for the following [networks](https://www.infura.io/networks): **Supported Testnets**: OP Sepolia, Unichain Sepolia, Swell Sepolia, Base Sepolia **Supported Mainnets**: OP Mainnet, Unichain, Swell, Base ### Moralis **Description**: [Moralis](https://moralis.io) offers [free and paid plans](https://developers.moralis.com/pricing/) for the following [networks](https://developers.moralis.com/chains/): **Supported Testnets**: OP Sepolia, Base Sepolia, Lisk Sepolia **Supported Mainnets**: OP Mainnet, Base, Lisk ### Nodies DLB **Description**: [Nodies DLB](https://www.nodies.app/) offers [free and paid plans](https://www.nodies.app/pricing) for the following [networks](https://docs.nodies.app/overview/supported-blockchains): **Supported Testnets**: OP Sepolia, Base Sepolia **Supported Mainnets**: OP Mainnet, Ink, Base ### NOWNodes **Description**: [NOWNodes](https://nownodes.io/) offers [free and paid plans](https://nownodes.io/pricing) for the following [networks](https://nownodes.io/nodes): **Supported Testnets**: n/a **Supported Mainnets**: OP Mainnet, Base, Lisk ### OnFinality **Description**: [OnFinality](https://onfinality.io/) offers [free and paid plans](https://onfinality.io/pricing) for the following [networks](https://onfinality.io/networks): **Supported Testnets**: OP Sepolia, Unichain Sepolia, Base Sepolia **Supported Mainnets**: OP Mainnet, Unichain, Base ### QuickNode **Description**: [QuickNode](https://www.quicknode.com/) offers [free and paid plans](https://www.quicknode.com/pricing) for the following [networks](https://www.quicknode.com/chains): **Supported Testnets**: OP Sepolia, Ink Sepolia, Unichain Sepolia, Base Sepolia, World Sepolia, Race Sepolia **Supported Mainnets**: OP Mainnet, Ink, Unichain, Mode, Zora, Base, World, Lisk, Race ### RockX **Description**: [RockX](https://www.rockx.com/) offers [free and paid plans](https://access.rockx.com/product/optimism-blockchain-api-for-web3-builders) for the following [networks](https://access.rockx.com/): **Supported Testnets**: n/a **Supported Mainnets**: OP Mainnet, Base ### Tenderly **Description**: [Tenderly](https://tenderly.co/) offers [free and paid plans](https://tenderly.co/pricing) for the following [networks](https://docs.tenderly.co/node/rpc-reference): **Supported Testnets**: OP Sepolia, Ink Sepolia, Unichain Sepolia, Soneium Sepolia, Mode Sepolia, Swell Sepolia, Base Sepolia, World Sepolia, Lisk Sepolia, Polynomial Sepolia, BoB Sepolia **Supported Mainnets**: OP Mainnet, Ink, Unichain, Soneium, Mode, Swell, Base, World, Lisk, Polynomial, BoB ### Validation Cloud **Description**: [Validation Cloud](https://www.validationcloud.io/) offers [free and paid plans](https://www.validationcloud.io/node) for the following [networks](https://docs.validationcloud.io/v1/optimism/overview): **Supported Testnets**: n/a **Supported Mainnets**: OP Mainnet, Base ## Directory governance The OP Stack RPC Directory is maintained by OP Labs with the following policies: * Providers must submit a docs PR to the [docs](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/) to be added * To be listed, providers must support at least one network in the [OP Stack ecosystem](/op-stack/protocol/superchain-registry) * Anyone can submit a PR to remove a provider that does not support a listed network ## Next steps * Want to run your own node? See the [Node operators overview](/node-operators/overview). * Looking for other developer tools? See [developer tools overview](/app-developers/tools) to explore more options! # Bridged token addresses Source: https://docs.optimism.io/app-developers/reference/tokens/tokenlist This reference guide lists the correct bridged token addresses for each token. Various ERC-20 tokens originally deployed to Ethereum also have corresponding "bridged" representations on OP Mainnet. The [Superchain Token List](https://github.com/ethereum-optimism/ethereum-optimism.github.io) exists to help users discover the correct bridged token addresses for each token. This page is automatically generated from the Superchain Token List. **Tokens listed on this page are provided for convenience only** and are automatically derived from the [Superchain Token List](https://github.com/ethereum-optimism/ethereum-optimism.github.io). **The presence of a token on this page does not imply any endorsement of the token or its minter.** ### USDC on OP Mainnet The legacy bridged version of USDC (USDC.e) at address `0x7f5c764cbc14f9669b88837ca1490cca17c31607` is being deprecated on OP Mainnet. Users and developers should migrate to using the native USDC token issued directly by [Circle](https://www.circle.com/en/), the issuer of [USDC](https://www.circle.com/en/usdc?gad_source=1). Information about the bridged `USDC.e` token and native USDC token can be found below. | Symbol | Description | Address | | -------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `USDC.e` | Bridged USDC from Ethereum | [`0x7f5c764cbc14f9669b88837ca1490cca17c31607`](https://explorer.optimism.io/token/0x7f5c764cbc14f9669b88837ca1490cca17c31607) | | `USDC` | Native USDC issued by Circle | [`0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85`](https://explorer.optimism.io/token/0x0b2c639c533813f4aa9d7837caf62653d097ff85) | ## OP Mainnet For a complete and up-to-date list of bridged token addresses for OP Mainnet (Chain ID: 10), please refer to the [Superchain Token List](https://github.com/ethereum-optimism/ethereum-optimism.github.io) repository. ## OP Sepolia For a complete and up-to-date list of bridged token addresses for OP Sepolia (Chain ID: 11155420), please refer to the [Superchain Token List](https://github.com/ethereum-optimism/ethereum-optimism.github.io) repository. # OPChainA (chainID 901) Source: https://docs.optimism.io/app-developers/reference/tools/supersim/chain-a Learn network details and contract addresses for OPChainA (chainID 901). This guide provides network details and contract addresses for OPChainA (chainID 901) when running `supersim` vanilla mode. ## Network details | **Parameter** | **Value** | | ------------- | ---------------------------------------------- | | **Name** | OPChainA | | **Chain ID** | 901 | | **RPC URL** | [http://127.0.0.1:9545](http://127.0.0.1:9545) | ## Contract addresses ### L1 contracts ```json theme={null} { "AddressManager": "0x78d21C9820A9135215202A9a8D6521483D4b75cD", "AnchorStateRegistry": "0x21799f09394c50220CCD95E7dAc1cdD774FC871a", "AnchorStateRegistryProxy": "0xa6F40d5770b3509aB40B2effa5cb544D29743ec7", "DelayedWETH": "0x49BBFf1629824A1e7993Ab5c17AFa45D24AB28c9", "DelayedWETHProxy": "0x309DA6B9a8fE16afD7D067528d358E55314bEa6b", "DisputeGameFactory": "0x20B168142354Cee65a32f6D8cf3033E592299765", "DisputeGameFactoryProxy": "0x444689B81D485bc58AB81aC02A95a937fAa152D7", "L1CrossDomainMessenger": "0x094e6508ba9d9bf1ce421fff3dE06aE56e67901b", "L1CrossDomainMessengerProxy": "0xcd712b03bc6424BF45cE6C29Fc90FFDece228F6E", "L1ERC721Bridge": "0x5C4F5e749A61a9503c4AAE8a9393e89609a0e804", "L1ERC721BridgeProxy": "0x018dC24a6617c47cAa00C3fA25097214B2D4F447", "L1StandardBridge": "0xb7900B27Be8f0E0fF65d1C3A4671e1220437dd2b", "L1StandardBridgeProxy": "0x8d515eb0e5F293B16B6bBCA8275c060bAe0056B0", "L2OutputOracle": "0x19652082F846171168Daf378C4fD3ee85a0D4A60", "L2OutputOracleProxy": "0x6cE0530E823e23be85D8e151FB023605eB4F6d43", "Mips": "0xB3A0348310a0ff78E5FbDB7f14BB7d3e02d40773", "OptimismMintableERC20Factory": "0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567", "OptimismMintableERC20FactoryProxy": "0x15c855966C196Be3a8ca747E8A8Bf40928d4741f", "OptimismPortal": "0x37a418800d0c812A9dE83Bc80e993A6b76511B57", "OptimismPortal2": "0xfcbb237388CaF5b08175C9927a37aB6450acd535", "OptimismPortalProxy": "0xF5fe61a258CeBb54CCe428F76cdeD04Cbc12F53d", "PreimageOracle": "0x3bd7E801E51d48c5d94Ea68e8B801DFFC275De75", "ProtocolVersions": "0xfbfD64a6C0257F613feFCe050Aa30ecC3E3d7C3F", "ProtocolVersionsProxy": "0x6dA4f6489039d9f4F3144954DDF5bb2F4986e90b", "ProxyAdmin": "0xe32a4D31ffD5596542DAc8239a1DE3Fff9d63475", "SafeProxyFactory": "0x4a05c09875DE2DD5B81Bc01dd46eD4699b181bfA", "SafeSingleton": "0x99A395CE6d6b37CaaCBad64fB42d556b6CA73a48", "SuperchainConfig": "0x068E44eB31e111028c41598E4535be7468674D0A", "SuperchainConfigProxy": "0x7E6c6ebCF109fa23277b86bdA39738035C21BB86", "SystemConfig": "0x6167B477F8d9138aa509f54b2800443857e28c0f", "SystemConfigProxy": "0xf32919Ed2490b56EaD65E72749894aE4C9523320", "SystemOwnerSafe": "0xc052b7316C87390E555aF97D42bCd5FB6d5eEFDa" } ``` ### L2 contracts ```json theme={null} { // OP Stack predeploys "L2ToL1MessagePasser": "0x4200000000000000000000000000000000000016", "L2CrossDomainMessenger": "0x4200000000000000000000000000000000000007", "L2StandardBridge": "0x4200000000000000000000000000000000000010", "L2ERC721Bridge": "0x4200000000000000000000000000000000000014", "SequencerFeeVault": "0x4200000000000000000000000000000000000011", "OptimismMintableERC20Factory": "0x4200000000000000000000000000000000000012", "OptimismMintableERC721Factory": "0x4200000000000000000000000000000000000017", "L1BlockInterop": "0x4200000000000000000000000000000000000015", "GasPriceOracle": "0x420000000000000000000000000000000000000F", "ProxyAdmin": "0x4200000000000000000000000000000000000018", "BaseFeeVault": "0x4200000000000000000000000000000000000019", "L1FeeVault": "0x420000000000000000000000000000000000001A", "OperatorFeeVault": "0x420000000000000000000000000000000000001B", "GovernanceToken": "0x4200000000000000000000000000000000000042", "SchemaRegistry": "0x4200000000000000000000000000000000000020", "EAS": "0x4200000000000000000000000000000000000021", "CrossL2Inbox": "0x4200000000000000000000000000000000000022", "L2ToL2CrossDomainMessenger": "0x4200000000000000000000000000000000000023", "SuperchainETHBridge": "0x4200000000000000000000000000000000000024", "SuperchainTokenBridge": "0x4200000000000000000000000000000000000028", // Periphery "L2NativeSuperchainERC20": "0x420beeF000000000000000000000000000000001" } ``` ## Next steps * Learn how to [deposit transactions](/app-developers/tutorials/bridging/deposit-transactions) with Supersim, using a much simpler approach that bypasses the derivation pipeline. - For more info about how OP Stack interoperability works under the hood, [check out the specs](https://specs.optimism.io/interop/overview.html?utm_source=op-docs\&utm_medium=docs). # OPChainB (chainID 902) Source: https://docs.optimism.io/app-developers/reference/tools/supersim/chain-b Learn network details and contract addresses for OPChainB (chainID 902). This guide provides network details and contract addresses for OPChainB (chainID 902) when running `supersim` vanilla mode. ## Network details | **Parameter** | **Value** | | ------------- | ---------------------------------------------- | | **Name** | OPChainB | | **Chain ID** | 902 | | **RPC URL** | [http://127.0.0.1:9546](http://127.0.0.1:9546) | ## Contract addresses ### L1 contracts ```json theme={null} { "AddressManager": "0xafB51A0f73C8409AeA1207DF7f39885c927BeA46", "AnchorStateRegistry": "0x05493149c84A71063f7948127bb931f8377F779C", "AnchorStateRegistryProxy": "0xfd0269a716A59fF125Bd7eb65Cd3427C8555bab7", "DelayedWETH": "0x49BBFf1629824A1e7993Ab5c17AFa45D24AB28c9", "DelayedWETHProxy": "0xA63353128502269b4A4A4c2677fE316cd9ad4397", "DisputeGameFactory": "0x20B168142354Cee65a32f6D8cf3033E592299765", "DisputeGameFactoryProxy": "0x5F416fEb15c8B382d338FDBDb7D44967ca2b59BC", "L1CrossDomainMessenger": "0x094e6508ba9d9bf1ce421fff3dE06aE56e67901b", "L1CrossDomainMessengerProxy": "0xeCA0f912b4bd255f3851951caE5775CC9400aA3B", "L1ERC721Bridge": "0x5C4F5e749A61a9503c4AAE8a9393e89609a0e804", "L1ERC721BridgeProxy": "0xDCE41E6C0901586EE27Eac329EBD4b5fe5A7170d", "L1StandardBridge": "0xb7900B27Be8f0E0fF65d1C3A4671e1220437dd2b", "L1StandardBridgeProxy": "0x67B2aB287a32bB9ACe84F6a5A30A62597b10AdE9", "L2OutputOracle": "0x19652082F846171168Daf378C4fD3ee85a0D4A60", "L2OutputOracleProxy": "0x006Af3fB62c4BE4fB0393995d364BbFe6b0F3CB2", "Mips": "0xB3A0348310a0ff78E5FbDB7f14BB7d3e02d40773", "OptimismMintableERC20Factory": "0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567", "OptimismMintableERC20FactoryProxy": "0x1A2A942d891e525D1Ab192578a378980729fD585", "OptimismPortal": "0x35e67BC631C327b60C6A39Cff6b03a8adBB19c2D", "OptimismPortal2": "0xfcbb237388CaF5b08175C9927a37aB6450acd535", "OptimismPortalProxy": "0xdfC9DEAbEEbDaa7620C71e2E76AEda32919DE5f2", "PreimageOracle": "0x3bd7E801E51d48c5d94Ea68e8B801DFFC275De75", "ProtocolVersions": "0xfbfD64a6C0257F613feFCe050Aa30ecC3E3d7C3F", "ProtocolVersionsProxy": "0xE139cB0CDa5EF722870068ea331d0989776A7aDf", "ProxyAdmin": "0xff5E6C2Af859f70B875BA59B958BEde60E36bf69", "SafeProxyFactory": "0xb68f3B057fE3c6CdDF9DB35837Ea769FCc81978a", "SafeSingleton": "0xeeB44D84d505AbD958d032e90704c56443eB3ED0", "SuperchainConfig": "0x068E44eB31e111028c41598E4535be7468674D0A", "SuperchainConfigProxy": "0x2ED4AA34573c36bF3856e597501aEf9d9Dc1687C", "SystemConfig": "0x6167B477F8d9138aa509f54b2800443857e28c0f", "SystemConfigProxy": "0x2Db03FE998D7c20E4B65afD1f50f04Ec4BfAb694", "SystemOwnerSafe": "0xBF3830711B7c559042453B7546dB4736eFB4245e" } ``` ### L2 contracts ```json theme={null} { // OP Stack predeploys "L2ToL1MessagePasser": "0x4200000000000000000000000000000000000016", "L2CrossDomainMessenger": "0x4200000000000000000000000000000000000007", "L2StandardBridge": "0x4200000000000000000000000000000000000010", "L2ERC721Bridge": "0x4200000000000000000000000000000000000014", "SequencerFeeVault": "0x4200000000000000000000000000000000000011", "OptimismMintableERC20Factory": "0x4200000000000000000000000000000000000012", "OptimismMintableERC721Factory": "0x4200000000000000000000000000000000000017", "L1BlockInterop": "0x4200000000000000000000000000000000000015", "GasPriceOracle": "0x420000000000000000000000000000000000000F", "ProxyAdmin": "0x4200000000000000000000000000000000000018", "BaseFeeVault": "0x4200000000000000000000000000000000000019", "L1FeeVault": "0x420000000000000000000000000000000000001A", "OperatorFeeVault": "0x420000000000000000000000000000000000001B", "GovernanceToken": "0x4200000000000000000000000000000000000042", "SchemaRegistry": "0x4200000000000000000000000000000000000020", "EAS": "0x4200000000000000000000000000000000000021", "CrossL2Inbox": "0x4200000000000000000000000000000000000022", "L2ToL2CrossDomainMessenger": "0x4200000000000000000000000000000000000023", "SuperchainETHBridge": "0x4200000000000000000000000000000000000024", "SuperchainTokenBridge": "0x4200000000000000000000000000000000000028", // Periphery "L2NativeSuperchainERC20": "0x420beeF000000000000000000000000000000001" } ``` ## Next steps * Learn how to [deposit transactions](/app-developers/tutorials/bridging/deposit-transactions) with Supersim, using a much simpler approach that bypasses the derivation pipeline. - For more info about how OP Stack interoperability works under the hood, [check out the specs](https://specs.optimism.io/interop/overview.html?utm_source=op-docs\&utm_medium=docs). # Fork mode Source: https://docs.optimism.io/app-developers/reference/tools/supersim/fork Learn how to fork Supersim. Supersim fork mode to simulate and interact with the state of the chain without needing to re-deploy or modify the contracts. This is possible if you're relying on contracts already deployed on testnet / mainnet chains. ```sh theme={null} supersim fork ``` ## How it works The `supersim` fork command simplifies the process of forking multiple chains in the OP Stack ecosystem simultaneously. It determines the appropriate block heights for each chain and launches both the L1 and L2 chains based on these values. This allows you to locally fork any chain in a superchain network of the [superchain registry](https://github.com/ethereum-optimism/superchain-registry), default `mainnet` versions. ### Example startup logs ``` Available Accounts ----------------------- (0): 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --- truncated for brevity --- Private Keys ----------------------- (0): 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --- truncated for brevity --- Orchestrator Config: L1: Name: mainnet Chain ID: 1 RPC: http://127.0.0.1:8545 LogPath: /var/folders/0w/ethers-phoenix/T/anvil-chain-1-1521250718 L2: Name: op Chain ID: 10 RPC: http://127.0.0.1:9545 LogPath: /var/folders/0w/ethers-phoenix/T/anvil-chain-10 Name: base Chain ID: 8453 RPC: http://127.0.0.1:9546 LogPath: /var/folders/0w/ethers-phoenix/T/anvil-chain-8453 Name: zora Chain ID: 7777777 RPC: http://127.0.0.1:9547 LogPath: /var/folders/0w/ethers-phoenix/T/anvil-chain-7777777 ``` ## Configuration ``` NAME: supersim fork - Locally fork a network in the superchain registry USAGE: supersim fork [command options] OPTIONS: --l1.fork.height value (default: 0) ($SUPERSIM_L1_FORK_HEIGHT) L1 height to fork the superchain (bounds L2 time). `0` for latest --chains value ($SUPERSIM_CHAINS) chains to fork in the superchain, mainnet options: [arena-z, automata, base, bob, cyber, ethernity, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, shape, soneium, sseed, swan, swell, tbn, unichain, worldchain, xterio-eth, zora]. In order to replace the public rpc endpoint for a chain, specify the ($SUPERSIM_RPC_URL_) env variable. i.e SUPERSIM_RPC_URL_OP=http://optimism-mainnet.infura.io/v3/ --network value (default: "mainnet") ($SUPERSIM_NETWORK) superchain network. options: mainnet, sepolia, sepolia-dev-0. In order to replace the public rpc endpoint for the network, specify the ($SUPERSIM_RPC_URL_) env variable. i.e SUPERSIM_RPC_URL_MAINNET=http://mainnet.infura.io/v3/ --interop.enabled (default: true) ($SUPERSIM_INTEROP_ENABLED) enable interop predeploy and functionality --admin.port value (default: 8420) ($SUPERSIM_ADMIN_PORT) Listening port for the admin server --interop.l2tol2cdm.override value ($SUPERSIM_INTEROP_L2TO2CDM_OVERRIDE) Path to the L2ToL2CrossDomainMessenger build artifact that overrides the default implementation --l1.port value (default: 8545) ($SUPERSIM_L1_PORT) Listening port for the L1 instance. `0` binds to any available port --l2.count value (default: 2) ($SUPERSIM_L2_COUNT) Number of L2s. Max of 5 --l2.starting.port value (default: 9545) ($SUPERSIM_L2_STARTING_PORT) Starting port to increment from for L2 chains. `0` binds each chain to any available port --interop.autorelay (default: false) ($SUPERSIM_INTEROP_AUTORELAY) Automatically relay messages sent to the L2ToL2CrossDomainMessenger using account 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 --interop.delay value (default: 0) ($SUPERSIM_INTEROP_DELAY) Delay before relaying messages sent to the L2ToL2CrossDomainMessenger --logs.directory value ($SUPERSIM_LOGS_DIRECTORY) Directory to store logs --l1.host value (default: "127.0.0.1") ($SUPERSIM_L1_HOST) Host address for the L1 instance --l2.host value (default: "127.0.0.1") ($SUPERSIM_L2_HOST) Host address for L2 instances --odyssey.enabled (default: false) ($SUPERSIM_ODYSSEY_ENABLED) Enable odyssey experimental features --dependency.set value ($SUPERSIM_DEPENDENCY_SET) Override local chain IDs in the dependency set.(format: '[901,902]' or '[]') --log.level value (default: INFO) ($SUPERSIM_LOG_LEVEL) The lowest log level that will be output --log.format value (default: text) ($SUPERSIM_LOG_FORMAT) Format the log output. Supported formats: 'text', 'terminal', 'logfmt', 'json', 'json-pretty', --log.color (default: false) ($SUPERSIM_LOG_COLOR) Color the log output if in terminal mode --log.pid (default: false) ($SUPERSIM_LOG_PID) Show pid in the log --help, -h (default: false) show help ``` ## Notes ### Fork height The fork height is determined by L1 block height (default `latest`). This is then used to derive the corresponding L2 block to start from. ### Interoperability contracts By default, interop contracts are not deployed on forked networks. To include them, run `supersim` with the `--interop.enabled` flag. ```sh theme={null} supersim fork --chains=op,base,zora --interop.enabled ``` ## Next steps * Explore the Supersim [included contracts](/app-developers/reference/tools/supersim/included-contracts) being used to help replicate the OP Stack environment. - Learn how to [deposit transactions](/app-developers/tutorials/bridging/deposit-transactions) with Supersim, using a much simpler approach that bypasses the derivation pipeline. # Included contracts Source: https://docs.optimism.io/app-developers/reference/tools/supersim/included-contracts Learn about the Supersim included contracts. The `supersim` chain environment includes contracts already deployed to help replicate the OP Stack interop environment. See [OP Chain A](./chain-a) for contract address examples for a L2 system. ## OP Stack system contracts (L1) These are the L1 contracts that are required for a rollup as part of the OP Stack protocol. Examples are the [OptimismPortal](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol), [L1StandardBridge](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1StandardBridge.sol), and [L1CrossDomainMessenger](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol). For more details, see [example contracts](/op-mainnet/network-information/op-addresses#ethereum-mainnet) or the [source code](https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1). ## OP Stack L2 contracts (L2) The OP Stack system contracts on the L2 are included at the standard addresses by default. * [Standard OP Stack predeploys (L2)](https://specs.optimism.io/protocol/predeploys.html) * [Interoperability predeploys (*experimental*) (L2)](https://specs.optimism.io/interop/predeploys.html?utm_source=op-docs\&utm_medium=docs) * [OP Stack preinstalls (L2)](https://specs.optimism.io/protocol/preinstalls.html?utm_source=op-docs\&utm_medium=docs) ## Periphery contracts (L2) L2 chains running on `supersim` also includes some useful contracts for testing purposes that are not part of the OP Stack by default. ### L2NativeSuperchainERC20 A simple ERC20 included in Supersim for testing cross-chain token transfers. It includes permissionless minting for easy testing. Source: [L2NativeSuperchainERC20.sol](https://github.com/ethereum-optimism/supersim/blob/main/contracts/src/L2NativeSuperchainERC20.sol) Deployed address: `0x420beeF000000000000000000000000000000001` #### Minting new tokens ```bash theme={null} cast send 0x420beeF000000000000000000000000000000001 "mint(address _to, uint256 _amount)" $RECIPIENT_ADDRESS 1ether --rpc-url $L2_RPC_URL ``` ## Next steps * Get network details about the two OP Stack systems spun up in vanilla mode: [OPChainA (chainID 901)](/app-developers/reference/tools/supersim/chain-a) and [OPChainB (chainID 902)](/app-developers/reference/tools/supersim/chain-b). - Learn how to [deposit transactions](/app-developers/tutorials/bridging/deposit-transactions) with Supersim, using a much simpler approach that bypasses the derivation pipeline. # Vanilla mode Source: https://docs.optimism.io/app-developers/reference/tools/supersim/vanilla Learn how to use Supersim in vanilla mode (non-forked). This guide explains how to start `supersim` in vanilla (non-forked) mode. By default, two OP Stack systems will be spun up in vanilla mode: * OPChainA (chainID 901) * OPChainB (chainID 902) Both "roll up" into a single L1 chain (chainID 900). ## How it works ```sh theme={null} supersim ``` Vanilla mode will start 3 chains, with the OP Stack contracts & periphery contracts already deployed. * (1) L1 Chain * Chain 900 * (2) L2 Chains * Chain 901 * Chain 902 ### Example startup logs ``` Available Accounts ----------------------- (0): 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (1): 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 (2): 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC (3): 0x90F79bf6EB2c4f870365E785982E1f101E93b906 (4): 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 (5): 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc (6): 0x976EA74026E726554dB657fA54763abd0C3a0aa9 (7): 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 (8): 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f (9): 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 Private Keys ----------------------- (0): 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 (1): 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d (2): 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a (3): 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6 (4): 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a (5): 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba (6): 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e (7): 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356 (8): 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97 (9): 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6 Orchestrator Config: L1: Name: L1 Chain ID: 900 RPC: http://127.0.0.1:8545 LogPath: /var/folders/0w/ethers-phoenix/T/anvil-chain-900 L2: Name: OPChainA Chain ID: 901 RPC: http://127.0.0.1:9545 LogPath: /var/folders/0w/ethers-phoenix/T/anvil-chain-901 Name: OPChainB Chain ID: 902 RPC: http://127.0.0.1:9546 LogPath: /var/folders/0w/ethers-phoenix/T/anvil-chain-902 ``` ## Configuration ``` NAME: supersim - Superchain Multi-L2 Simulator USAGE: supersim [global options] command [command options] VERSION: untagged DESCRIPTION: Local multichain optimism development environment COMMANDS: fork Locally fork a network in the superchain registry docs Display available docs links help, h Shows a list of commands or help for one command GLOBAL OPTIONS: --admin.port value (default: 8420) ($SUPERSIM_ADMIN_PORT) Listening port for the admin server --interop.l2tol2cdm.override value ($SUPERSIM_INTEROP_L2TO2CDM_OVERRIDE) Path to the L2ToL2CrossDomainMessenger build artifact that overrides the default implementation --l1.port value (default: 8545) ($SUPERSIM_L1_PORT) Listening port for the L1 instance. `0` binds to any available port --l2.count value (default: 2) ($SUPERSIM_L2_COUNT) Number of L2s. Max of 5 --l2.starting.port value (default: 9545) ($SUPERSIM_L2_STARTING_PORT) Starting port to increment from for L2 chains. `0` binds each chain to any available port --interop.autorelay (default: false) ($SUPERSIM_INTEROP_AUTORELAY) Automatically relay messages sent to the L2ToL2CrossDomainMessenger using account 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 --interop.delay value (default: 0) ($SUPERSIM_INTEROP_DELAY) Delay before relaying messages sent to the L2ToL2CrossDomainMessenger --logs.directory value ($SUPERSIM_LOGS_DIRECTORY) Directory to store logs --l1.host value (default: "127.0.0.1") ($SUPERSIM_L1_HOST) Host address for the L1 instance --l2.host value (default: "127.0.0.1") ($SUPERSIM_L2_HOST) Host address for L2 instances --odyssey.enabled (default: false) ($SUPERSIM_ODYSSEY_ENABLED) Enable odyssey experimental features --dependency.set value ($SUPERSIM_DEPENDENCY_SET) Override local chain IDs in the dependency set.(format: '[901,902]' or '[]') --log.color (default: false) ($SUPERSIM_LOG_COLOR) Color the log output if in terminal mode --log.format value (default: text) ($SUPERSIM_LOG_FORMAT) Format the log output. Supported formats: 'text', 'terminal', 'logfmt', 'json', 'json-pretty', --log.level value (default: INFO) ($SUPERSIM_LOG_LEVEL) The lowest log level that will be output --log.pid (default: false) ($SUPERSIM_LOG_PID) Show pid in the log MISC --help, -h (default: false) show help --version, -v (default: false) print the version ``` ## Next steps * Explore the Supersim [included contracts](/app-developers/reference/tools/supersim/included-contracts) being used to help replicate the OP Stack interop environment. * Get network details about the two OP Stack systems spun up in vanilla mode: [OPChainA (chainID 901)](/app-developers/reference/tools/supersim/chain-a) and [OPChainB (chainID 902)](/app-developers/reference/tools/supersim/chain-b). - Learn how to [deposit transactions](/app-developers/tutorials/bridging/deposit-transactions) with Supersim, using a much simpler approach that bypasses the derivation pipeline. # Account abstraction Source: https://docs.optimism.io/app-developers/tools-sdks/account-abstraction This guide explains how to use account abstraction to remove friction from your app experience This page includes providers that meet specific [inclusion criteria](#inclusion-criteria), as outlined below. Please visit the [community account abstractions page](https://github.com/ethereum-optimism/developers/blob/main/community/tools/account-abstraction.md) for an additional listing of third-party account abstraction tools. [ERC-4337](https://www.erc4337.io/docs/paymasters/introduction), also known as Account Abstraction, enables more opportunities for apps and wallet developers to innovate on user experiences, including the ability to: * Batch transactions together (e.g. approve and execute a swap in one go) * Offer wallets with easy recovery and no seed phrase * Sponsor the gas fees for transactions * Enable users to pay gas in the token(s) of their choice ## Bundlers The OP Stack includes support for the `eth_sendRawTransactionConditional` RPC method to assist bundlers on shared 4337 mempools. See the [specification](/op-stack/features/send-raw-transaction-conditional) for how this method is implemented in op-geth. If used by the chain operator, also see the supplemental [op-txproxy](/chain-operators/tools/op-txproxy) service which may apply additional restrictions prior to reaching the block builder. As of today, this endpoint is not enabled by default in the stack. The operator must explicitly configure this. ## Account abstraction tools Ready to enable account abstraction experiences in your app? Here's some helpful information on account abstraction infrastructure like ERC-4337 bundler and gas manager APIs that are available on OP Mainnet: * [Alchemy](https://www.alchemy.com/account-abstraction): Account Kit is a complete solution for account abstraction. Using Account Kit, you can create a smart contract wallet for every user that leverages account abstraction to simplify every step of your app's onboarding experience. It also offers Gas Manager and Bundler APIs for sponsoring gas and batching transactions. * [Biconomy](https://docs.biconomy.io/): is an Account Abstraction toolkit that enables you to provide the simplest UX for your app or wallet. It offers modular smart accounts, as well as paymasters and bundlers as a service for sponsoring gas and executing transactions at scale. * [GroupOS](https://docs.groupos.xyz/introduction/group-os): provides Smart Wallets that are ERC-4337 compliant smart wallets, offering full flexibility, programmability and extensibility as well as out-of-the-box toolkit groups need to gaslessly onboard and activate wallets to games, applications, and/or protocols. * [Openfort](https://openfort.io/docs/?utm_source=optimism\&utm_medium=docs\&utm_campaign=backlinks): an open-source wallet infrastructure solution. The core offerings include embedded wallets, global wallets and AA infrastructure (Paymaster and Bundler). It enables rapid integration of wallet functionality, intuitive onboarding, and stablecoin flows. * [Pimlico](https://docs.pimlico.io/): provides an infrastructure platform that makes building smart accounts simpler. If you are developing an ERC-4337 smart account, they provide bundlers, verifying paymasters, ERC-20 paymasters, and much more. * [Reown](https://reown.com/?utm_source=optimism\&utm_medium=docs\&utm_campaign=backlinks) gives developers the tools to build user experiences that make digital ownership effortless, intuitive, and secure. Using Reown's AppKit SDK, you can enable your users to create a smart wallet using their social logins, configure a paymaster to sponsor gas fees, enable chain abstraction and a lot more. * [Safe](https://docs.safe.global/home/what-is-safe): provides modular smart account infrastructure and account abstraction stack via their Safe\{Core} Account Abstraction SDK, API, and Protocol. * [Stackup](https://docs.stackup.sh/docs): provides smart account tooling for building account abstraction within your apps. They offer Paymaster and Bundler APIs for sponsoring gas and sending account abstraction transactions. * [thirdweb](https://portal.thirdweb.com/react/v5/account-abstraction/get-started?utm_source=opdocs\&utm_medium=docs): offers the complete tool-kit to leverage account abstraction technology to enable seamless user experiences for your users. This includes Account Factory contracts that lets your users spin up Smart Accounts, Bundler for UserOps support, and Paymaster to enable gas sponsorships. ## Helpful tips * [EIP-1271 Signature Validation](https://eip1271.io/) * [Making smart accounts work with WalletConnect v2](https://safe-global.notion.site/WalletConnect-v2-update-Issues-and-solutions-for-smart-wallets-3fc32fad6af4485fa5823eaebd486819) # Block explorers Source: https://docs.optimism.io/app-developers/tools-sdks/block-explorers Learn about different block explorers you can use to interact with contracts and view transaction history for OP Mainnet and OP Sepolia. ## Blockscout We have a Blockscout explorer for [OP Mainnet](https://optimism.blockscout.com) and [OP Sepolia](https://optimism-sepolia.blockscout.com/). It includes: * [Verified testnet contract source code, along with the ability to interact with it](https://optimism.blockscout.com/verified-contracts) * [Detailed testnet transaction information](https://optimism.blockscout.com/tx/0xa1b04233084d4067ec0bb3e09301012900f0e209f14a3d406f3d6dc696eea138) Blockscout also has some OP-Mainnet-specific features: * [An interactive list of deposits (L1-L2)](https://optimism.blockscout.com/l2-deposits) * [An interactive list of withdrawals (L2-L1)](https://optimism.blockscout.com/l2-withdrawals) * [Transaction batches](https://optimism.blockscout.com/l2-txn-batches) * [App marketplace](https://optimism.blockscout.com/apps) * And much more! ## Etherscan We have Etherscan explorers for the [OP Mainnet](https://explorer.optimism.io) and the [OP Sepolia](https://testnet-explorer.optimism.io/). Etherscan has lots of tools to help you debug transactions. Optimistic Etherscan has all the tools you expect from Etherscan, such as: * [Verified contract source code, along with the ability to interact with it](https://explorer.optimism.io/address/0x420000000000000000000000000000000000000F#code) * [Detailed transaction information](https://explorer.optimism.io/tx/0x292423266d6da24126dc4e0e81890c22a67295cc8b1a987e71ad84748511452f) * And everything else you might find on Etherscan! It's also got some OP-Mainnet-specific features: * [A list of L1-to-L2 transactions](https://explorer.optimism.io/txsEnqueued) * [A list of L2-to-L1 transactions](https://explorer.optimism.io/txsExit) * [A tool for finalizing L2-to-L1 transactions](https://explorer.optimism.io/messagerelayer) * And more! Just check it out and click around to find all of the available features. ## Superscan by Routescan [Superscan](https://superscan.network) is the dev-focused OP Stack explorer unified at the ecosystem level, powered by [Routescan](https://routescan.io). On the Superscan, developers can quickly glance at transactions, blocks, addresses, deployed contracts and more across OP Stack chains in unified pages. The Superscan currently includes: * Mainnet - OP Mainnet, Base, Zora, Mode, Cyber, Orderly, Fraxtal, Public Goods Network * Testnet - Zora, Mode, Orderly, Fraxtal ## Tenderly Tenderly's [Developer Explorer](https://docs.tenderly.co/developer-explorer?mtm_campaign=ext-docs\&mtm_kwd=optimism) for OP Mainnet and OP Sepolia allows you to monitor and inspect transactions, providing a high level of detail and additional tools: Tenderly Developer Explorer lets you: * Keep track of specific [contracts](https://docs.tenderly.co/developer-explorer/contracts?mtm_campaign=ext-docs\&mtm_kwd=optimism) and their transactions * Inspect [transaction execution](https://docs.tenderly.co/developer-explorer/inspect-transaction?mtm_campaign=ext-docs\&mtm_kwd=optimism) with fully decoded transaction trace * [Debug](https://docs.tenderly.co/debugger?mtm_campaign=ext-docs\&mtm_kwd=optimism) failing and [simulate](https://docs.tenderly.co/simulator-ui/using-simulation-ui?mtm_campaign=ext-docs\&mtm_kwd=optimism) correct transactions before sending them on-chain * Evaluate [function-level gas usage](https://docs.tenderly.co/debugger/gas-profiler?mtm_campaign=ext-docs\&mtm_kwd=optimism) for any transaction * Set up [Alerts](https://docs.tenderly.co/alerts/tutorials-and-quickstarts/alerting-quickstart-guide?mtm_campaign=ext-docs\&mtm_kwd=optimism) to monitor interactions, access control, asset transfers, and contracts' state changes * Create a [Virtual TestNet](https://docs.tenderly.co/virtual-testnets?mtm_campaign=ext-docs\&mtm_kwd=optimism) from a specific OP Mainnet or OP Chain transaction for systematic research ## Access to pre-regenesis history Because of our final regenesis on 11 November 2021, older transactions are not part of the current blockchain and do not appear on [Etherscan](https://explorer.optimism.io/?utm_source=op-docs\&utm_medium=docs). However, you **can** access transaction history between 23 June 2021 and the final regenesis using a number of different tools. For detailed instructions, see [Regenesis History](/op-mainnet/pre-bedrock-history/regenesis-history). ## Next Steps * Looking for other developer tools? See the [building apps overview](/app-developers/guides/building-apps) to explore more options! # Analytics tools Source: https://docs.optimism.io/app-developers/tools-sdks/data/analytics-tools Learn about platforms you can use to gather analytics and set up customizations about OP Mainnet. The following guide lists platforms you can use to gather analytics and set up customizations about OP Mainnet. ## Blocknative [Blocknative](https://www.blocknative.com/) lets you [decode](http://docs.blocknative.com/ethernow/batch-decoder-api) and [analyze](https://docs.blocknative.com/blocknative-data-archive/blob-archive) OP Stack Batches submitted to the Ethereum L1. You can inspect, analyze, decode, and download the data of any batch – confirmed on-chain or not – via public APIs or visually through the [Ethernow Explorer](http://ethernow.xyz). Below you can find links to the different resources: * [Batch Decoding API](http://docs.blocknative.com/ethernow/batch-decoder-api): decode OP Stack Batch transactions into their human-readable JSON format. * [Blob Archive API](https://docs.blocknative.com/blocknative-data-archive/blob-archive): take any versioned hash of an OP Stack Blob and receive the blob data (even beyond the 4096 epoch window of storage). * [Mempool Archive](https://docs.blocknative.com/blocknative-data-archive/mempool-archive): Analyze any OP Stack transaction that was in the Ethereum mempool to see detection time, time pending, gas, etc. * [Ethernow Explorer](http://ethernow.xyz): Visually see transactions and batches enter the mempool and get organized into blocks. Use this filter to see OP Stack Batches enter the mempool and land on-chain. ## Tenderly [Tenderly](https://tenderly.co/?mtm_campaign=ext-docs\&mtm_kwd=optimism) provides comprehensive monitoring and security solutions for OP-powered Chains, allowing you to stay informed and respond proactively to potential issues in real time. * Configure [Tenderly Alerts](https://docs.tenderly.co/alerts/intro-to-alerts?mtm_campaign=ext-docs\&mtm_kwd=optimism) for monitoring wallets and setting up real-time notifications on transactions and contract events. Notifications trigger external webhooks, PagerDuty, or chat apps like Telegram and Slack. * Rely on [Developer Explorer](https://docs.tenderly.co/developer-explorer?mtm_campaign=ext-docs\&mtm_kwd=optimism) to monitor and analyze transaction execution with a high level of detail. * Use [Web3 Actions](https://docs.tenderly.co/web3-actions/intro-to-web3-actions?mtm_campaign=ext-docs\&mtm_kwd=optimism) to automate predefined responses, improving security and user experience. * Integrate [Simulation RPC](https://docs.tenderly.co/simulations/single-simulations?mtm_campaign=ext-docs\&mtm_kwd=optimism#simulate-via-rpc) to predict transaction outcomes such as the expected asset changes, precise gas usage, and emitted events. ## Dune Analytics [Dune Analytics](https://dune.com) allows anyone to create dashboards that present information about OP Chains (OP Mainnet, Base, and Zora are available). See [Dune Docs](https://dune.com/docs/) for more info. You can find a list of community created dashboards for OP Chains [here](https://dune.com/browse/dashboards?q=tags%3Aop%2Coptimism%2Csuperchain\&order=trending\&time_range=24h), or [create your own](https://docs.dune.com/#queries) dashboard. For developers building apps on OP chains, Dune's developer platform, [Sim](https://sim.dune.com/), provides real-time onchain data access via [Sim APIs](https://docs.sim.dune.com/) and custom indexing with [Sim IDX](https://docs.sim.dune.com/idx). Here are some of our favorite dashboards so far: * [OP Chains / Superchain - L2 Activity, Chain Economics](https://dune.com/oplabspbc/op-stack-chains-l1-activity) * [OP Chains / Superchain - Popular Apps & Project Usage Trends](https://dune.com/oplabspbc/superchain-op-chains-apps-and-project-usage-trends) * [By OP Chain - L2/L1 Chain Economics](https://dune.com/oplabspbc/optimism-l2-l1-economics) * [OP Token House Delegates](https://dune.com/optimismfnd/optimism-op-token-house) * [Superchain NFTs](https://dune.com/oplabspbc/superchain-nfts) ## Additional tools and resources Here are some additional tools and resources for OP Mainnet analytics and development: * L2 Usage and Comparison: [growthepie](https://www.growthepie.xyz/) * OP Analytics (Incentive Tracking, Helper Functions, Public Analysis): [OP Analytics on GitHub](https://github.com/ethereum-optimism/op-analytics) * Contribute to NumbaNERDs: [Issues on GitHub](https://github.com/ethereum-optimism/op-analytics/issues) # Data and Dashboards Source: https://docs.optimism.io/app-developers/tools-sdks/data/data-and-dashboards Learn about various dashboards and terms to explore various OP Stack metrics. The following resources are available to help you explore various OP Stack metrics: * [Data Glossary](/app-developers/tools-sdks/data/data-glossary): Definitions, methodology, and calculation notes for key metrics * [Superchain Health Dashboard](https://docs.google.com/spreadsheets/d/1f-uIW_PzlGQ_XFAmsf9FYiUf0N9l_nePwDVrw0D5MXY/edit?gid=192497306#gid=192497306): High-level metrics across OP Stack chains * [Superchain Strategic Focus Dashboard](https://app.hex.tech/61bffa12-d60b-484c-80b9-14265e268538/app/d28726b2-ff11-4f94-8a9f-6bb0a86f4b46/latest): In-depth metrics with chain-level splits and industry benchmarks * [Optimism Superchain Raw Onchain Data](https://console.cloud.google.com/bigquery/analytics-hub/exchanges/projects/523274563936/locations/us/dataExchanges/optimism_192d403716e/listings/optimism_superchain_raw_onchain_data_192fdc72e35): Raw Blocks, Logs, Transactions, Traces data for OP Stack chains, updated daily. * [Optimism Superchain 4337 Account Abstraction Data](https://console.cloud.google.com/bigquery/analytics-hub/exchanges/projects/523274563936/locations/us/dataExchanges/optimism_192d403716e/listings/optimism_superchain_4337_account_abstraction_data_1954d8919e1): Decoded account abstraction UserOps across OP Stack chains. # Data Glossary Source: https://docs.optimism.io/app-developers/tools-sdks/data/data-glossary This glossary explains various data terms. This glossary is a living document and will be updated over time as new metrics emerge or definitions evolve. | Metric | What It Measures | Why It Matters | | ------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------- | | Real Economic Value (REV) | Fees paid by users to transact (txn fees + out-of-protocol tips) | Captures users' willingness to pay for onchain activity | | Collective Revenue | ETH earned by the Optimism Collective | Revenue can be directed by governance to support ecosystem growth | | Total Value Locked (TVL) | Tokens locked in DeFi protocols and other apps | Supply side of the DeFi ecosystem | | Gas Used per Second | Average compute consumed onchain | Measures throughput and execution load | | Median Transaction Fee | Typical cost for a user to transact | Lower fees reduce friction and may unlock broader usage | | Market Share | OP Stack ecosystem's share of activity vs. the broader crypto industry | Tracks relative performance against L2s or the broader market | ## Measure Demand ### Transaction Fees Paid **Metric:** Real Economic Value (REV) **Definition:** The total fees paid to execute a transaction onchain. This includes both the traditional gas fees required for inclusion onchain and additional fees paid to transaction execution services (e.g., Jito, Flashbots, Timeboost). **Calculation:** Gas Fees + Out-of-Protocol Tips (e.g., Jito, Flashbots, Timeboost) * Out-of-Protocol Tips can be sourced from Defillama's MEV category **Why it matters:** * REV is a topline metric that "measures the monetary demand to transact onchain" (Blockworks). * It's used as a proxy for users' willingness to pay, capturing all transaction fees to better reflect real demand (excludes app-level fees like DEX swap costs). ### Revenue **Metric:** Estimated Optimism Collective Revenue (Collective Revenue) **Definition:** The amount of ETH expected to be earned by the Optimism Collective from revenue sharing. **Calculation:** For each chain, take the greater of (a) 2.5% of Chain Revenue or (b) 15% of Net Onchain Profit. OP Mainnet contributes 100% of Net Onchain Profit. **Key Components:** * **Net Onchain Profit:** Chain Revenue - L1 Gas Fees * **Chain Revenue:** Sum of the L1 Data Fee + L2 Base Fee + L2 Priority Fee + L2 Operator Fee (Also includes any additional fee types added in the future.) * *L1 Gas Fees:* Total gas fees spent by the chain on L1 in transaction batches (including blob costs) and state output submissions or dispute games. * **Transaction Batches:** All transactions where the transaction from address is the `batcherHash` address as defined in the chains' `SystemConfigProxy` contract, and the transaction to address is the chain's `batch_inbox_address` as defined in the rollup config. * **State Output Submissions or Dispute Games:** All transactions where the transaction from address is the `Proposer` and the transaction to address is either the `outputOracleProxy` or the `disputeGameFactoryProxy` as defined in the chains' `SystemConfigProxy` contract. * Each chain's `SystemConfigProxy` contract can be found in the superchain-registry. * **Resolving Dispute Games:** All transactions sent to dispute game contracts created by the `disputeGameFactoryProxy`, where the transaction's method id (function call) is either `Resolve`, `ResolveClaim`, or `ClaimCredit`. **Why it matters:** * This is what the Optimism Collective earns by operating OP Stack chains, which can be directed by governance to support ecosystem growth. * See How (and why) the OP Stack drives fees to the Optimism Collective (Optimism blog, Aug 2024) ## Onchain Signals ### Value Onchain **Metric:** Total Value Locked (TVL) **Definition:** "Value of all coins held in smart contracts of the protocol" (Defillama). **Calculation:** The sum of all USD value of assets locked in applications, as reported by DefiLlama. * TVL can be priced in USD or a crypto asset like ETH, but both are subject to price volatility. USD is often used because it's easier to interpret and consistent across the broader crypto ecosystem. **Why it Matters:** TVL represents the supply side of onchain economic activity for use in protocols such as Decentralized Exchanges (DEXs) and lending markets. Strong TVL in the right places may enable greater onchain demand. #### How to Measure Growth: Net TVL Flows Because TVL is influenced by market fluctuations, it can be misleading when trying to measure true growth or user behavior. Net TVL Flows can adjust for this by tracking the net change in token balances, valued at current prices. **Calculation:** ( `# of Tokens on Day N` - `# of Tokens on Day 0` ) \* `Price of Tokens on Day N` **Example:** If an app has 100,000 ETH locked on Day 0 when ETH/USD is $2,000, and 90,000 ETH locked at $3,000 on Day N: * Net TVL Flows = −10,000 ETH × $3,000 = $30 million in net outflows * Naive TVL change would suggest growth: $200 million → $270 million ## Network Usage & Infrastructure **Metric:** Gas Used per Second (gas/s) **Definition:** "Gas refers to the unit that measures the amount of computational effort required to execute specific operations on Ethereum" (ethereum.org). Gas Used is tracked as an average rate per second for simplicity. **Why it Matters:** Gas, sometimes referred to as blockspace, is the limited resource that blockchains provide. Gas used shows how much of that resource is actually being consumed. **Caution:** Gas is only comparable across chains that use Ethereum-equivalent gas units. ### User Experience (UX) **Metric:** Median Transaction Fee (USD) **Definition:** The median gas fee paid to submit a transaction, expressed in USD for simplicity and easier comparison across ecosystems. **Calculation:** Median of all transaction fees over a period of time, marked at the USD price at the time of the transaction. **Why it Matters:** This metric serves as a proxy for the cost to transact. Lower median fees enable broader usage by reducing friction, lowering breakeven costs, and unlocking use cases that would otherwise be cost-prohibitive. ## Market Share **Definition:** The OP Stack ecosystem's share of a broader market segment for any measure (e.g., L2s, total crypto). **Calculation:** OP Stack Metric Value / Total Market Metric Value **Why it Matters:** Market share helps isolate whether growth is driven by the OP Stack ecosystem itself, or is simply part of a broader market trend. A rising share signals outperformance, while a declining share suggests that other ecosystems are growing faster. # Oracles Source: https://docs.optimism.io/app-developers/tools-sdks/data/oracles Learn about different oracles and how you can use them to access offchain data onchain as well as random number generation. This page includes providers that meet specific [inclusion criteria](#inclusion-criteria), as outlined below. Please visit the [community oracles page](https://github.com/ethereum-optimism/developers/blob/main/community/tools/oracles.md) for an additional listing of third-party Oracles. This reference guide lists different Oracles you can use when building on Optimism. [Oracles](https://ethereum.org/en/developers/docs/oracles/) provide offchain data onchain. This allows code running on a blockchain to access a wide variety of information. For example, a [stablecoin](https://ethereum.org/en/stablecoins/) that accepts ETH as collateral needs to know the ETH/USD exchange rate: * How many stablecoins can we give a user for a given amount of ETH? * Do we need to liquidate any deposits because they are under collateralized? ## Security and decentralization Different oracles have different security assumptions and different levels of decentralization. Usually they are either run by the organization that produces the information, or have a mechanism to reward entities that provide accurate information and penalize those that provide incorrect information. ## Types of oracles There are two types of oracles: 1. **Push oracles** are updated continuously and always have up to date information available onchain. 2. **Pull oracles** are only updated when information is requested by a contract. Pull oracles are themselves divided into two types: 1. Double-transaction oracles, which require two transactions. The first transaction is the request for information, which usually causes the oracle to emit an event that triggers some offchain mechanism to provide the answer (through its own transaction). The second transaction actually reads onchain the result from the oracle and uses it. 2. Single-transaction oracles, which only require one transaction. The way this works is that the transaction that requests the information includes a callback (address and the call data to provide it). When the oracle is updated (which also happens through a transaction, but one that is not sent by the user), the oracle uses the callback to inform a contract of the result. ## Random number generation (RNG) Random number generation in blockchain applications ensures that smart contracts can access unbiased random values. This is essential for certain use cases like generative NFTs, gaming, commit & reveal schemes and more. Various approaches include using a trusted third party, blockhash-based methods, Verifiable Random Functions (VRF), quantum random numbers to name a few. Each method has trade-offs between simplicity, security, and trust assumptions, allowing developers to select the most suitable option for their use case. ## List of oracles ### Gas oracle OP Mainnet provides a [Gas Price Oracle](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/GasPriceOracle.sol) that provides information about [gas prices and related parameters](/op-stack/transactions/fees). It can also calculate the total cost of a transaction for you before you send it. This contract is a predeploy at address `0x420000000000000000000000000000000000000F`: * [On OP Mainnet](https://explorer.optimism.io/address/0x420000000000000000000000000000000000000F#readContract) * [On OP Sepolia](https://testnet-explorer.optimism.io/address/0x420000000000000000000000000000000000000F) This is a push Oracle. OP Mainnet (and the testnets) updates the gas price parameters onchain whenever those parameters change. The L1 gas price, which can be volatile, is only pushed once every 5 minutes, and each time can change only by up to 20%. * [Blocknative](https://docs.blocknative.com/gas-prediction) provides real-time gas estimation powered by predictive modeling to forecast gas price distribution for select OP Stack chains, including OP Mainnet and Base. The [API](https://docs.blocknative.com/gas-prediction) is also available on Ethereum Mainnet to estimate base fee costs. ### API3 The [API3 Market](https://market.api3.org/optimism) provides access to 200+ price feeds on [Optimism Mainnet](https://market.api3.org/optimism) and [Testnet](https://market.api3.org/optimism-sepolia-testnet). The price feeds operate as a native push oracle and can be activated instantly via the Market UI. The price feeds are delivered by an aggregate of [first-party oracles](https://docs.api3.org/oev-searchers/glossary.html#first-party-oracles) using signed data and support [OEV recapture](https://docs.api3.org/dapps/integration/security-considerations.html#oracle-extractable-value-oev). Unlike traditional data feeds, reading [API3 price feeds](https://docs.api3.org/oev-searchers/in-depth/#dapps-catalog) enables dApps to auction off the right to update the price feeds to searcher bots which facilitates more efficient liquidation processes for users and LPs of DeFi money markets. The OEV recaptured is returned to the dApp. API3's QRNG provides dApps with truly random numbers based on quantum mechanics at no charge. More details are available on the [API3 website](https://api3.org/). ### Chainlink [Chainlink](https://chain.link/) is the industry-standard decentralized computing platform powering the verifiable web. Chainlink powers verifiable applications and high-integrity markets for banking, DeFi, global trade, gaming, and other major sectors. Chainlink provides a number of [price feeds](https://docs.chain.link/docs/optimism-price-feeds/). Those feeds are available on the production network @ [OP Mainnet](https://docs.chain.link/data-feeds/price-feeds/addresses?network=optimism\&page=1#optimism-mainnet). * Data Feeds: Chainlink Data Feeds provide a secure, reliable, and decentralized source of off-chain data to power unique smart contract use cases for DeFi and beyond. * Automation: Chainlink Automation is an ultra-reliable and performant smart contract automation solution enabling developers to quickly scale their operations in a verifiable, decentralized, and cost-efficient manner, to build next-generation apps. * CCIP: Chainlink CCIP provides a secure interoperability protocol for powering token transfers and sending arbitrary messages cross-chain. This is a push Oracle. See the [Using Data Feeds guide](https://docs.chain.link/docs/get-the-latest-price/) to learn how to use the Chainlink feeds. * Chainlink VRF provides cryptographically secure randomness for blockchain-based applications. More details [here](https://chain.link/vrf) ### Chronicle The first Oracle on Ethereum, Chronicle's decentralized Oracle network was originally built within MakerDAO for the development of DAI and is now available to builders on OP Mainnet and OP Stack chains. * **Data Feeds**: Builders can choose from 65+ data feeds, including crypto assets, yield rates, and RWAs. Chronicle's data is sourced via custom-built data models, only utilizing Tier 1 Primary Sources, such as the markets where tokens are actively traded, including Coinbase, Binance, Uniswap, and Curve. * **Transparency & Integrity**: Chronicle's Oracle network is fully transparent and verifiable. Via [The Chronicle](https://chroniclelabs.org/dashboard/oracle/DAI/USD?blockchain=OPT\&txn=0x53e60e6e79eb938e5ca3ca6c56b0795e003dd6b3a17cfd810ca5042b3d33b680\&contract=0x104916d38828DA8B83a88A1775Aa058e1F0B1647), the data supply chain for any Oracle can be viewed in real-time and historically, including data sources and the identity of all Validators/Signers. Users can cryptographically challenge the integrity of every Oracle update using the 'verify' feature. Data is independently sourced by a [community of Validators](https://chroniclelabs.org/validators), including Gitcoin, Etherscan, Infura, DeFi Saver, and MakerDAO. * **Gas Efficiency:** Pioneering the Schnorr-based Oracle architecture, Chronicle's Oracles use 60-80% less gas per update than other Oracle providers. This lowest cost per update allows Push Oracle updates to be made more regularly, ensuring more accurate and granular data reporting. Every Oracle implementation is customized to fit your needs. Implement one of our existing data models or contact Chronicle to develop custom Oracle data feeds via [Discord](https://discord.gg/CjgvJ9EspJ) or [Email](mailto:gm@chroniclelabs.org). Developers can dive deeper into Chronicle Protocol's architecture and unique design choices [via the docs](https://docs.chroniclelabs.org/). ### Gelato [Gelato VRF](https://www.gelato.network/) enables smart contracts on Optimism to access verifiable randomness. Gelato VRF offers real randomness for blockchain applications by leveraging Drand, a trusted decentralized source for random numbers. Gelato VRF (Verifiable Random Function) provides trustable randomness on EVM-compatible blockchains. Here's a brief overview: * Contract Deployment: Use GelatoVRFConsumerBase.sol as an interface for requesting random numbers. * Requesting Randomness: Emit the RequestedRandomness event to signal the need for a random number. * Processing: Gelato VRF fetches the random number from Drand. * Delivery: The fulfillRandomness function delivers the random number to the requesting contract. Ready to integrate? Head over to the [Gelato VRF Quick Start Guide](https://docs.gelato.network/web3-services/vrf/quick-start). ### Pyth Network The Pyth Network is a financial oracle network which delivers over 400 low-latency, high-fidelity price feeds across cryptocurrencies, FX pairs, equities, ETFs, and commodities. * Pyth's price data is sourced from over [95 first-party sources](https://pyth.network/publishers) including exchanges, market makers, and financial services providers. * Pyth [Price Feeds](https://www.pyth.network/developers/price-feed-ids) offer both the real-time spot price of the asset as well as an accompanying confidence interval band around that price * The Pyth [TradingView](https://docs.pyth.network/guides/how-to-create-tradingview-charts) integration allows users to view and display Pyth prices on their own website and UI. You can explore the full catalog of Pyth Price Feed IDs for [OP Mainnet and Sepolia (EVM Stable)](https://www.pyth.network/developers/price-feed-ids). * Pyth Entropy allows developers to quickly and easily generate secure random numbers on the blockchain. More details [here](https://pyth.network/blog/secure-random-numbers-for-blockchains) ### RedStone [RedStone](https://redstone.finance/) offers flexible Data Feeds for Lending Markets, Perpetuals, Options, Stablecoins, Yield Aggregators and other types of novel DeFi protocols. The infrastructure is well battle-tested and secures hundreds of millions of USD across mainnet. Builders can choose how they want to consume the data among 3 dedicated models: * [RedStone Core](https://docs.redstone.finance/docs/dapps/redstone-pull/) (pull oracle) - less than 10s update time, broad spectrum of feeds, best for most use cases. All [Core Price Feeds](https://app.redstone.finance/#/app/tokens) are available on OP Mainnet & OP Sepolia. * [RedStone Classic](https://docs.redstone.finance/docs/dapps/redstone-push/) (push oracle) - for protocols designed for the traditional oracle interface, customizable heartbeat and deviation threshold. * [Hybrid (push + push) ERC7412](https://docs.redstone.finance/docs/dapps/redstone-erc7412/) - specifically for Perps and Options, highest update frequency and front-running protection. Interested in integration? [Get in contact](https://discord.com/invite/PVxBZKFr46) with the RedStone team! ### Stork [Stork](https://stork.network) delivers price feeds with ultra-low latency, high uptime, and broad asset coverage for DeFi applications on OP Mainnet and OP Stack chains. * **Ultra-Low Latency**: Stork provides price data at ultra-low latency, enabling protocols to maintain functionality during high-volatility periods and support time-sensitive trading operations. * **High Reliability**: With best-in-class uptime and reliability, Stork supports perpetuals markets, lending protocols, and DeFi ecosystems that require consistent data availability. * **Day 1 Asset Support**: Price feeds for new digital assets are available from Day 1, allowing protocols to launch new markets immediately after token generation events. * **Broad Coverage**: Stork provides comprehensive asset coverage across crypto assets, equities, ETFs and commodities, supporting a wide range of DeFi use cases from derivatives trading to collateralized lending. Visit the [Stork documentation](https://docs.stork.network) to get started. ### DIA [DIA](https://www.diadata.org/) is a cross-chain, trustless oracle network delivering verifiable price feeds for Optimism. DIA sources raw trade data directly from primary markets and computes it onchain, ensuring complete transparency and data integrity. * Complete verifiability from source to destination smart contract. * Direct data sourcing from 100+ primary markets eliminating intermediary risk. * Support for 20,000+ assets across all major asset classes. * Custom oracle configuration with tailored sources and methodologies. To get started: * [Explore the Optimism Oracle Integration Guide](https://www.diadata.org/docs/guides/chain-specific-guide/optimism) * [Request a Custom Oracle](https://www.diadata.org/docs/guides/how-to-guides/request-a-custom-oracle) ## Next steps * Looking for other developer tools? See the [building apps overview](/app-developers/guides/building-apps) to explore more options! # Testnet faucets Source: https://docs.optimism.io/app-developers/tools-sdks/faucets Learn how to get testnet ETH on test networks like Sepolia and OP Sepolia for development and testing purposes. Faucets are developer tools that allow you to get free ETH (and other tokens) on test networks like Sepolia and OP Sepolia so that you can send transactions and create smart contracts. Here you'll find a list of active faucets that you can try out. Different faucets use different authentication methods, so you may have to try a few before you find one that works for you. Faucets can occasionally also run out of ETH, so if you're having trouble getting ETH from a faucet, try another one. Tokens on test networks like Sepolia or OP Sepolia have no value and are only meant for testing. Optimists only take what they need so that others can use faucets too! ## Optimism's faucet The [Optimism's faucet](https://console.optimism.io/faucet?utm_source=op-docs\&utm_medium=docs) is a developer tool hosted by Optimism that allows developers to get free testnet ETH to test apps on testnet OP Chains like Base Sepolia, OP Sepolia, PGN Sepolia, Zora Sepolia, and other OP Stack chains. Optimism's faucet is a great place to start if you're looking for testnet ETH. ## Additional faucets | Faucet Name | Supported Networks | | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | [Alchemy Faucet](https://sepoliafaucet.com) | Sepolia | | [Chain Platform Faucet](https://faucet.chainplatform.co/faucets/ethereum-sepolia/) | Sepolia | | [Ethereum Ecosystem Faucets](https://www.ethereum-ecosystem.com/faucets) | Sepolia, OP Sepolia, Base Sepolia | | [ETHGlobal Testnet Faucet](https://ethglobal.com/faucet) | Sepolia, OP Sepolia, Base Sepolia, Zora Sepolia, Holesky | | [Farcaster Frame Faucet by LearnWeb3](https://warpcast.com/haardikkk/0x28f4237d) | Sepolia, OP Sepolia | | [Infura Faucet](https://www.infura.io/faucet/sepolia) | Sepolia | | [Native USDC Faucet](https://faucet.circle.com/) | Sepolia, OP Sepolia | | [QuickNode Faucet](https://faucet.quicknode.com/optimism/) | Sepolia, OP Sepolia | | [Tenderly Unlimited Faucet](https://docs.tenderly.co/virtual-testnets/unlimited-faucet?mtm_campaign=ext-docs\&mtm_kwd=optimism) | OP Sepolia, OP Mainnet, and [85+ other networks](https://docs.tenderly.co/supported-networks?mtm_campaign=ext-docs\&mtm_kwd=optimism) | | [thirdweb OP Sepolia Faucet](https://thirdweb.com/op-sepolia-testnet?utm_source=opdocs\&utm_medium=docs) | OP Sepolia | | [thirdweb Sepolia Faucet](https://thirdweb.com/sepolia?utm_source=opdocs\&utm_medium=docs) | Sepolia | | [ethfaucet.com](https://ethfaucet.com?utm_source=opdocs\&utm_medium=docs) | Sepolia, OP Sepolia, Base Sepolia, Zora Sepolia, Unichain Sepolia, Ink Sepolia, Mode Sepolia, Shape Sepolia, Worldchain Sepolia, BOB Sepolia | ## Bridge from Sepolia If you have testnet ETH on Sepolia, you can bridge it to OP Sepolia (and vice versa) using the [Superchain Bridges UI](https://app.optimism.io/bridge/?utm_source=op-docs\&utm_medium=docs) or this collection of [Superchain Testnet Tools](https://www.superchain.tools/). ## Next steps * If you're new to onchain development, check out [Optimism Unleashed](https://cryptozombies.io/en/optimism) by CryptoZombies and [Superchain Builder NFT](https://web.archive.org/web/20231218203510/https://blog.thirdweb.com/guides/optimism-superchain-faucet-nft/) by ThirdWeb. * If you're familiar with onchain development, check out the [Optimism Ecosystem's Contributions Dashboard](https://github.com/ethereum-optimism/ecosystem-contributions) for project ideas that Optimism is looking for. * Looking for other developer tools? See the [building apps overview](/app-developers/guides/building-apps) to explore more options! # Tools & SDKs Listing Criteria Source: https://docs.optimism.io/app-developers/tools-sdks/listing-criteria What a tool or SDK must meet to be listed on the support matrix, the removal rule, and the maintenance sweep that keeps listings accurate. This page governs the [Tools & SDKs support matrix](/app-developers/tools-sdks/support-matrix). It exists so that adding or removing a listing is the application of written policy, not a per-pull-request argument. The approach follows the [ethereum.org product-listing policy](https://ethereum.org/en/contributing/adding-products/), which uses published criteria plus a standing removal rule for the same reason. Listings must also satisfy the site-wide [content guide](/op-stack/contribute/content-guide): the matrix is a routing page (clause 3 of the three-clause test), so every listing links one canonical documentation home and restates nothing. ## Listing Criteria A tool or SDK is eligible for the matrix only if **all** of the following hold: 1. **Open source, public repository.** The source is publicly available and the repository is linkable from the matrix. 2. **Works with the OP Stack as documented.** A developer can follow the tool's own quickstart against an OP Stack chain and succeed. Listings for tools that only incidentally support the OP Stack must link the OP-Stack-relevant entry point, not a generic homepage. 3. **Actively maintained.** The project ships releases and responds to issues. An archived or visibly abandoned repository is disqualifying. 4. **Has one canonical documentation home.** There is a single place we can link as the source of truth (per the content guide's dual-sourcing ban we will not maintain a copy of its documentation here). 5. **Honest support status.** The listing's support status must match what the owner declares in its own repository or docs. Experimental or preview software is listed as such, never as production. 6. **Third-party listings are marked.** Any listing not owned by the Optimism Collective passes through the `` component, per the [content guide](/op-stack/contribute/content-guide). ## Proposing a Listing Open a pull request against the [matrix page](/app-developers/tools-sdks/support-matrix) that adds one row and, in the PR description, states how the tool meets each criterion above — with links as evidence (repository, docs home, release page, the owner's own status declaration). Reviewers apply this page; if a criterion is unclear, the fix is a PR to this page, not an exception. ## Removal Rule A listing is removed — not left stale — when it no longer meets the criteria. Typical triggers: * The repository is archived, or releases and issue activity have stopped. * The documented quickstart no longer works against an OP Stack chain. * The canonical docs home is gone or no longer maintained. * The owner's declared status changed and the listing was not updated (in that case, update the row instead if the tool still qualifies). Removal is an ordinary pull request that cites the failed criterion. Rows are never soft-deprecated in place: the ethereum.org experience this policy is modeled on shows that stale curated tables are worse than absent ones. ## Maintenance Sweep Curated listings rot silently, so accuracy is maintained by a scheduled sweep rather than by hoping readers report drift: * **What is checked.** Every sweep re-verifies all four cells of every row — purpose, owner, canonical docs link, and support status — against the upstream repository and docs, and re-checks each criterion above. * **What is recorded.** The sweep PR (or its "no changes" note) lists what was checked and the upstream sources consulted, so the next sweep starts from evidence. * **Who runs it.** The docs maintainers own the sweep as part of the standing docs review rotation; anyone may run one ahead of schedule by opening the same kind of PR. * **Outcome.** Each row is updated, confirmed, or removed under the removal rule. A sweep that cannot verify a row treats it as failing. ## Next Steps * Browse the [Tools & SDKs support matrix](/app-developers/tools-sdks/support-matrix). * Read the [content guide](/op-stack/contribute/content-guide) for the site-wide rules this policy inherits. # Consensus Source: https://docs.optimism.io/app-developers/tools-sdks/op-alloy/building/consensus The `op-alloy-consensus` crate provides an Optimism consensus interface. It contains constants, types, and functions for implementing Optimism EL consensus and communication. This includes an extended `OpTxEnvelope` type with [deposit transactions](https://specs.optimism.io/protocol/deposits.html), and receipts containing OP Stack specific fields (`deposit_nonce` + `deposit_receipt_version`). In general a type belongs in this crate if it exists in the `alloy-consensus` crate, but was modified from the base Ethereum protocol in the OP Stack. For consensus types that are not modified by the OP Stack, the `alloy-consensus` types should be used instead. ## Block [`op-alloy-consensus`](https://crates.io/crates/op-alloy-consensus) exports an Optimism block type, [`OpBlock`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/type.OpBlock.html). This type simply re-uses the `alloy-consensus` block type, with `OpTxEnvelope` as the type of transactions in the block. ## Transactions Optimism extends the Ethereum [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) transaction envelope to include a deposit variant. ### [`OpTxEnvelope`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/transaction/enum.OpTxEnvelope.html) The [`OpTxEnvelope`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/transaction/enum.OpTxEnvelope.html) type is based on [Alloy](https://github.com/alloy-rs/alloy)'s `TxEnvelope` type. Optimism modifies the `TxEnvelope` to the following. * Legacy * EIP-2930 * EIP-1559 * EIP-7702 * Deposit Deposit is a custom transaction type that is either an L1 attributes deposit transaction or a user-submitted deposit transaction. Read more about deposit transactions in [the specs](https://specs.optimism.io). ### Transaction Types ([`OpTxType`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/transaction/enum.OpTxType.html)) The [`OpTxType`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/transaction/enum.OpTxType.html) enumerates the transaction types using their byte identifier, represents as a `u8` in rust. ## Receipt Types Just like [`op-alloy-consensus`](https://crates.io/crates/op-alloy-consensus) defines transaction types, it also defines associated receipt types. [`OpReceiptEnvelope`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/enum.OpReceiptEnvelope.html) defines an [Eip-2718](https://eips.ethereum.org/EIPS/eip-2718) receipt envelope type modified for the OP Stack. It contains the following variants - mapping directly to the `OpTxEnvelope` variants defined above. * Legacy * EIP-2930 * EIP-1559 * EIP-7702 * Deposit There is also an [`OpDepositReceipt`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/struct.OpDepositReceipt.html) type, extending the alloy receipt type with a deposit nonce and deposit receipt version. # RPC Engine Types Source: https://docs.optimism.io/app-developers/tools-sdks/op-alloy/building/engine The [`op-alloy-rpc-types-engine`](https://docs.rs/op-alloy-rpc-types-engine/latest/op_alloy_rpc_types_engine/) crate provides Optimism types for interfacing with the Engine API in the OP Stack. Optimism defines a custom payload attributes type called [`OpPayloadAttributes`](https://docs.rs/op-alloy-rpc-types-engine/latest/op_alloy_rpc_types_engine/struct.OpPayloadAttributes.html). `OpPayloadAttributes` extends alloy's [`PayloadAttributes`](https://docs.rs/alloy-rpc-types-engine/latest/alloy_rpc_types_engine/payload/struct.PayloadAttributes.html) with a few fields: transactions, a flag for enabling the tx pool, the gas limit, EIP 1559 parameters, and a minimum base fee (used after the Jovian hardfork). Optimism also returns a custom type for the `engine_getPayload` request for both V3 and V4 payload envelopes. These are the [`OpExecutionPayloadEnvelopeV3`](https://docs.rs/op-alloy-rpc-types-engine/latest/op_alloy_rpc_types_engine/payload/v3/struct.OpExecutionPayloadEnvelopeV3.html) and [`OpExecutionPayloadEnvelopeV4`](https://docs.rs/op-alloy-rpc-types-engine/latest/op_alloy_rpc_types_engine/payload/v4/struct.OpExecutionPayloadEnvelopeV4.html) types, which both wrap payload envelope types from [`alloy-rpc-types-engine`](https://crates.io/crates/alloy-rpc-types-engine). # Building Source: https://docs.optimism.io/app-developers/tools-sdks/op-alloy/building/index This section offers in-depth documentation into the various `op-alloy` crates. Some of the primary crates and their types are listed below. * [`op-alloy-consensus`](https://crates.io/crates/op-alloy-consensus) provides [`OpBlock`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/type.OpBlock.html), [`OpTxEnvelope`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/transaction/enum.OpTxEnvelope.html), [`OpReceiptEnvelope`](https://docs.rs/op-alloy-consensus/latest/op_alloy_consensus/enum.OpReceiptEnvelope.html), and more. * [`op-alloy-rpc-types-engine`](https://crates.io/crates/op-alloy-rpc-types-engine) provides the [`OpPayloadAttributes`](https://docs.rs/op-alloy-rpc-types-engine/latest/op_alloy_rpc_types_engine/struct.OpPayloadAttributes.html). # op-alloy Source: https://docs.optimism.io/app-developers/tools-sdks/op-alloy/intro Welcome to the hands-on guide for getting started with `op-alloy`! `op-alloy` connects applications to the OP Stack, leveraging high performance types, traits, and middleware from [Alloy](https://github.com/alloy-rs/alloy). **Development Status** `op-alloy` is in active development, and is not yet ready for use in production. During development, this documentation will evolve quickly and may contain inaccuracies. Please [open an issue](https://github.com/ethereum-optimism/optimism/issues/new) if you find any errors or have any suggestions for improvements, and also feel free to [contribute](https://github.com/ethereum-optimism/optimism/blob/develop/CONTRIBUTING.md) to the project! ## Sections ### [Getting Started](/app-developers/tools-sdks/op-alloy/starting) To get started with op-alloy, add its crates as a dependency and take your first steps. ### [Building with op-alloy](/app-developers/tools-sdks/op-alloy/building/index) Walk through types and functionality available in different `op-alloy` crates. ### [Contributing](https://github.com/ethereum-optimism/optimism/blob/develop/CONTRIBUTING.md) Contributors are welcome! It is built and maintained by Alloy contributors, members of [OP Labs](https://github.com/ethereum-optimism), and the broader open source community. `op-alloy` follows and expands the OP Stack standards set in the [specs](https://specs.optimism.io). ### Licensing `op-alloy` is licensed under the combined Apache 2.0 and MIT License, along with a SNAPPY license for snappy encoding use. # Add op-alloy to your project Source: https://docs.optimism.io/app-developers/tools-sdks/op-alloy/starting Add the op-alloy crates to a Rust project with Cargo and pick the feature flags you need. [op-alloy](https://github.com/ethereum-optimism/optimism/tree/develop/rust/op-alloy) consists of a number of crates that provide a range of functionality essential for interfacing with any OP Stack chain. The most succinct way to work with `op-alloy` is to add the [`op-alloy`](https://crates.io/crates/op-alloy) crate with the `full` feature flag from the command-line using Cargo. ```txt theme={null} cargo add op-alloy --features full ``` Alternatively, you can add the following to your `Cargo.toml` file. ```txt theme={null} op-alloy = { version = "2.0", features = ["full"] } ``` For more fine-grained control over the features you wish to include, you can add the individual crates to your `Cargo.toml` file, or use the `op-alloy` crate with the features you need. After `op-alloy` is added as a dependency, crates re-exported by `op-alloy` are now available. ```rust theme={null} use op_alloy::{ consensus::OpBlock, network::Optimism, rpc_types::OpTransactionReceipt, rpc_types_engine::OpPayloadAttributes, }; ``` ## Features The [`op-alloy`](https://crates.io/crates/op-alloy) defines many [feature flags](https://docs.rs/crate/op-alloy/latest/features) including the following. Default * `std` * `k256` * `serde` Full enables the most commonly used crates: `consensus`, `network`, `rpc-types`, `rpc-types-engine`, and `rpc-jsonrpsee`. The `provider` crate is not part of `full` and is enabled with its own `provider` feature. * `full` The `k256` feature flag enables the `k256` feature on the `op-alloy-consensus` crate. * `k256` Arbitrary enables arbitrary features on crates, deriving the `Arbitrary` trait on types. * `arbitrary` Serde derives serde's Serialize and Deserialize traits on types. * `serde` Additionally, individual crates can be enabled using their shorthand names. For example, the `consensus` feature flag provides the `op-alloy-consensus` re-export so `op-alloy-consensus` types can be used from `op-alloy` through `op_alloy::consensus::InsertTypeHere`. ## Crates * [`op-alloy-network`](https://crates.io/crates/op-alloy-network) * [`op-alloy-provider`](https://crates.io/crates/op-alloy-provider) * [`op-alloy-consensus`](https://crates.io/crates/op-alloy-consensus) (supports `no_std`) * [`op-alloy-rpc-jsonrpsee`](https://crates.io/crates/op-alloy-rpc-jsonrpsee) * [`op-alloy-rpc-types`](https://crates.io/crates/op-alloy-rpc-types) (supports `no_std`) * [`op-alloy-rpc-types-engine`](https://crates.io/crates/op-alloy-rpc-types-engine) (supports `no_std`) ## `no_std` As noted above, the following crates are `no_std` compatible. * [`op-alloy-consensus`](https://crates.io/crates/op-alloy-consensus) * [`op-alloy-rpc-types-engine`](https://crates.io/crates/op-alloy-rpc-types-engine) * [`op-alloy-rpc-types`](https://crates.io/crates/op-alloy-rpc-types) To add `no_std` support to a crate, ensure the [check\_no\_std](https://github.com/ethereum-optimism/optimism/blob/develop/rust/op-alloy/scripts/check_no_std.sh) script is updated to include this crate once `no_std` compatible. # op-revm Source: https://docs.optimism.io/app-developers/tools-sdks/op-revm op-revm is the Optimism variant of revm, implementing OP Stack modifications to the EVM. `op-revm` is the Optimism variant of [revm](https://github.com/bluealloy/revm) — the OP Stack's modifications to the Ethereum Virtual Machine, packaged as a custom EVM built on top of the upstream `revm` framework. ## Features `op-revm` extends `revm` with everything the OP Stack needs on top of vanilla Ethereum execution: * **Deposit transactions** — the L1-to-L2 deposit transaction type and its execution semantics. * **L1 cost accounting** — `L1BlockInfo` and per-transaction L1 fee / blob fee calculation. * **Operator fees** — operator fee handling introduced in Isthmus and refined in Jovian. * **OP-specific precompiles** — including accelerated BN254 pairing. * **OP halt reasons & transaction errors** — OP Stack–specific execution failure modes. * **Hardfork-aware spec selection** — `OpSpecId` selects the right behavior for each OP Stack hardfork (Bedrock, Regolith, Canyon, Ecotone, Fjord, Granite, Holocene, Isthmus, Jovian, …). ## Provenance `op-revm` is vendored from upstream [`bluealloy/revm`'s `crates/op-revm`](https://github.com/bluealloy/revm/tree/main/crates/op-revm) and imported into the monorepo so it can evolve in lock-step with the rest of the OP Stack Rust code. The upstream release history lives in the [revm releases](https://github.com/bluealloy/revm/releases). ## Crate features The crate exposes the usual `revm` feature knobs, forwarded through to the underlying `revm` crate: * `default = ["std", "c-kzg", "secp256k1", "portable", "blst"]` * `std` — enables `std`-dependent code paths in `revm`, `alloy-primitives`, `serde_json`, etc. * `serde` — derives `serde` impls and forwards to `revm/serde` and `alloy-primitives/serde`. * `portable`, `c-kzg`, `secp256k1`, `blst`, `bn` — pass-through feature gates for the cryptographic backends. * `dev`, `memory_limit`, `optional_balance_check`, `optional_block_gas_limit`, `optional_eip3541`, `optional_eip3607`, `optional_no_base_fee`, `optional_fee_charge` — debugging and testing knobs forwarded to `revm`. `op-revm` supports `no_std` builds: disabling default features (or building with `--no-default-features`) produces a crate suitable for fault-proof and zkVM targets such as `riscv32imac-unknown-none-elf`. ## Building & testing From the `rust/` workspace root: ```bash theme={null} # Build cargo build -p op-revm # Run tests with all features cargo nextest run -p op-revm --all-features # no_std check (mirrors upstream's riscv32imac CI) cargo build -p op-revm \ --target riscv32imac-unknown-none-elf \ --no-default-features ``` The `no_std` build is also exercised by `just check-no-std` and runs in CI on every PR that touches `rust/**`. ## Using op-revm `op-revm` is the EVM used by [op-reth](/op-stack/components/op-reth) for OP Stack block execution, and by [Kona](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona) inside the fault-proof program and rollup node. Most users will consume it transitively through one of those components rather than depending on it directly; depend on `op-revm` directly only when building a custom OP Stack execution environment (for example, an alternate client or a zkVM proof backend). ## License `op-revm` is licensed under the MIT License — see [`rust/op-revm/LICENSE`](https://github.com/ethereum-optimism/optimism/blob/develop/rust/op-revm/LICENSE). # Supersim Multichain Development Environment Source: https://docs.optimism.io/app-developers/tools-sdks/supersim Learn how to use the Supersim local dev environment tool designed to simulate the OP Stack multi-chain environment. Interop is currently in active development and not yet ready for production use. The information provided here may change. Check back regularly for the most up-to-date information. [Supersim](https://github.com/ethereum-optimism/Supersim) is a local development environment tool designed to simulate the OP Stack for developers building multi-chain applications. It provides a simplified way to test and develop applications that interact with multiple chains within the OP Stack ecosystem. ## Supersim workflow ```mermaid theme={null} graph LR A[Write Smart Contracts] --> B[Deploy on Supersim] B --> C[Test Cross-Chain Interactions] C --> D[Debug and Refine] D --> B C --> E[Ready for Production] ``` This diagram illustrates the typical workflow for developers using Supersim, from writing smart contracts to testing and refining cross-chain interactions. ## Features and benefits * Simulates multiple OP Stack chains locally (e.g., chain 901, 902) * Supports testing of cross-chain messaging and interactions * Includes pre-deployed interoperability contracts * Offers a CLI interface for starting and managing Supersim instances * Provides local JSON-RPC endpoints for each simulated chain * Allows for custom configuration of chain parameters * Facilitates testing of Superchain-specific features like cross-chain token transfers * Easy to use with common Ethereum development tools * Supports chain forking ## Supersim CLI interaction ```mermaid theme={null} graph TD A[Developer] --> B[Supersim CLI] B --> C[Chain 901] B --> D[Chain 902] B --> E[...] C --> F[JSON-RPC Endpoint] D --> G[JSON-RPC Endpoint] E --> H[JSON-RPC Endpoint] ``` This diagram illustrates how developers interact with Supersim through the CLI, which simulates OP Stack-specific features (specifically interop) on locally run chains, each with its own JSON-RPC endpoint and pre-deployed interoperability contracts. ## Next steps * View more [Supersim tutorials](/app-developers/tutorials/development/supersim/first-steps) # Tools & SDKs Support Matrix Source: https://docs.optimism.io/app-developers/tools-sdks/support-matrix One page that differentiates the OP Stack SDK surfaces and developer tools — what each is for, who owns it, where its canonical docs live, and its support status. Items on this page refer to third-party projects or products that are not maintained by Optimism. They are provided for convenience; refer to each project's own documentation as the source of truth. This page is the canonical hub for the tools and SDKs that surround the OP Stack. Following the [content guide](/op-stack/contribute/content-guide), each listing links exactly one canonical documentation home — this page routes, it does not restate. What gets listed here (and what gets removed) is governed by the [listing criteria](/app-developers/tools-sdks/listing-criteria). ## Support Status Levels | Status | Meaning | | --------------------- | ------------------------------------------------------------------------------------------ | | **Production** | Stable and recommended for production use by its owner. | | **Developer preview** | Usable today, but its owner has declared it not yet ready for production; APIs may change. | | **Experimental** | A staging ground. Features may change, move, or be upstreamed elsewhere. | ## The Matrix | Tool | Purpose | Owner | Canonical docs | Support status | | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | [`viem/op-stack`](https://viem.sh/op-stack) | General-purpose TypeScript client for OP Stack chains: deposits, withdrawals, L1 gas estimation, and all standard chain interaction, built into viem | [wevm](https://github.com/wevm/viem) (third party) | [viem.sh/op-stack](https://viem.sh/op-stack) | Production | | [`@eth-optimism/viem`](https://github.com/ethereum-optimism/ecosystem/tree/main/packages/viem) | viem extension for OP Stack features that have not yet been upstreamed into viem — Superchain interop actions and utilities; used by this site's bridging and interop tutorials | Optimism ([`ecosystem`](https://github.com/ethereum-optimism/ecosystem) repo) | [Package README & SDK reference](https://github.com/ethereum-optimism/ecosystem/tree/main/packages/viem#readme) | Experimental | | [Actions SDK](https://github.com/ethereum-optimism/actions) (`@eth-optimism/actions-sdk`) | High-level abstractions for building onchain apps — wallet, lend, and swap namespaces over Superchain protocols | Optimism ([`actions`](https://github.com/ethereum-optimism/actions) repo) | [Actions quickstart](/app-developers/quickstarts/actions) and [reference](/app-developers/reference/actions/integrating-wallets) on this site | Developer preview | | [wagmi](https://wagmi.sh) | React hooks for Ethereum apps; works with OP Stack chains as with any EVM chain | [wevm](https://github.com/wevm/wagmi) (third party) | [wagmi.sh](https://wagmi.sh) | Production | | [supersim](/app-developers/tools-sdks/supersim) | Local Superchain simulator: one L1 plus multiple OP Stack L2s for testing L1↔L2 and L2↔L2 message passing without deploying to live networks | Optimism ([`supersim`](https://github.com/ethereum-optimism/supersim) repo) | [Supersim docs](https://supersim.pages.dev) | Developer preview (all releases are alpha pre-releases; interop features in active development) | | [super-cli](https://github.com/ethereum-optimism/super-cli) (`sup`) | Foundry companion CLI for multichain workflows: deploy and verify contracts on multiple chains at once, bridge funds, use connected wallets | Optimism ([`super-cli`](https://github.com/ethereum-optimism/super-cli) repo) | [Repository README](https://github.com/ethereum-optimism/super-cli#readme) | Experimental | | [superchain-registry](https://github.com/ethereum-optimism/superchain-registry) tooling | Not an SDK — the source-of-truth library of chain configs that OP Stack software (such as `op-node` and `op-geth`) consumes, plus the `just` tasks and validation checks used to add and verify a chain | Optimism ([`superchain-registry`](https://github.com/ethereum-optimism/superchain-registry) repo) | [Registry operations docs](https://github.com/ethereum-optimism/superchain-registry/tree/main/docs) | Production | | [op-alloy](/app-developers/tools-sdks/op-alloy/intro) | Rust crates for interfacing with OP Stack chains: consensus, RPC, engine, and network types built on the [Alloy](https://github.com/alloy-rs/alloy) ecosystem; the type layer consumed by kona and op-reth | Optimism ([`rust/op-alloy`](https://github.com/ethereum-optimism/optimism/tree/develop/rust/op-alloy) in the monorepo) | [op-alloy docs](/app-developers/tools-sdks/op-alloy/intro) on this site | Developer preview (owner-declared not yet production-ready; APIs may change) | | [op-revm](/app-developers/tools-sdks/op-revm) | Rust crate implementing the OP Stack's EVM: a revm variant with deposit transactions, L1 and operator fee accounting, and OP-specific precompiles; the EVM inside op-reth and kona | Optimism ([`rust/op-revm`](https://github.com/ethereum-optimism/optimism/tree/develop/rust/op-revm) in the monorepo, vendored from upstream [`bluealloy/revm`](https://github.com/bluealloy/revm)) | [op-revm docs](/app-developers/tools-sdks/op-revm) on this site | Production (consumed transitively through op-reth or kona by most users) | ## Choose an SDK Surface Three of the rows above are TypeScript SDK surfaces that are easy to confuse. The distinction: * **Start with [`viem/op-stack`](https://viem.sh/op-stack).** viem provides first-class OP Stack support in the core library: extend any viem client with `publicActionsL2()` (and friends) imported from `viem/op-stack` to get deposits, withdrawals, and L1 gas estimation. If a feature is available here, this is its production home. Super Root withdrawal proving requires `viem` `2.51.0` or later. * **Reach for [`@eth-optimism/viem`](https://github.com/ethereum-optimism/ecosystem/tree/main/packages/viem) when you need what viem does not have yet.** The package's stated goal is to upstream as much as possible into viem itself; until then it is the home of Superchain interop actions and other pre-production features. The [interop tutorials](/app-developers/tutorials/interoperability/manual-relay) and [bridging tutorials](/app-developers/tutorials/bridging/cross-dom-bridge-erc20) on this site use it. * **Use the [Actions SDK](/app-developers/quickstarts/actions) for app-level building blocks, not chain plumbing.** Where the two viem surfaces expose protocol operations, the Actions SDK offers wallet, lend, and swap namespaces for building end-user apps. It is a developer preview and not yet ready for production use. Building in Rust rather than TypeScript? Start from [op-alloy](/app-developers/tools-sdks/op-alloy/intro) for OP Stack types and RPC surfaces and [op-revm](/app-developers/tools-sdks/op-revm) for execution, and see the [Stack Components index](/op-stack/components/index) for the Rust clients themselves (op-reth, kona-node, kona-client). ## Using wagmi With the OP Stack If you build with React, you likely start from wagmi — and it works with OP Stack chains out of the box. OP Stack chains are standard EVM chains, and `wagmi/chains` ships their definitions (`optimism`, `base`, `zora`, and every other chain from `viem/chains`). Nothing OP-specific is required for reads, writes, or wallet connections. For OP Stack–specific operations — deposits, withdrawals, interop — use the fact that wagmi is a wrapper over viem: 1. Get a viem client from wagmi with the [`useClient`](https://wagmi.sh/react/api/hooks/useClient) or [`useConnectorClient`](https://wagmi.sh/react/api/hooks/useConnectorClient) hooks, following wagmi's own [viem guide](https://wagmi.sh/react/guides/viem). 2. Extend that client with the [`viem/op-stack`](https://viem.sh/op-stack) actions and call them directly. For Superchain interop specifically, the experimental [`@eth-optimism/wagmi`](https://github.com/ethereum-optimism/ecosystem/tree/main/packages/wagmi) package provides React hooks (such as `useSendL2ToL2Message`) over `@eth-optimism/viem`. Treat it like its underlying package: experimental. ## Next Steps * Read the [listing criteria and maintenance-sweep policy](/app-developers/tools-sdks/listing-criteria) that govern this page. * Adding a chain rather than building an app? See [Join the Superchain Registry](/chain-operators/guides/join-superchain-registry). * For where content belongs in general, see the [content guide](/op-stack/contribute/content-guide). # Transferring ETH Source: https://docs.optimism.io/app-developers/tutorials/bridging/bridge-crosschain-eth Learn how to transfer ETH across the OP Stack interop cluster OP Stack interop is in active development. Some features may be experimental. This tutorial provides step-by-step instructions for how to send ETH from one chain in the OP Stack interop cluster to another. For a conceptual overview, see the [interoperable ETH explainer](/op-stack/interop/superchain-eth-bridge). ## Overview Crosschain ETH transfers across OP Stack chains are facilitated through the [SuperchainETHBridge](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/SuperchainETHBridge.sol) contract. This tutorial walks through how to send ETH from one chain to another. You can do this on [Supersim](/app-developers/tools-sdks/supersim) or production once it is released. ### What you'll build * A TypeScript application to transfer ETH between chains ### What you'll learn * How to send ETH on the blockchain and between blockchains * How to relay messages between chains ## Prerequisites Before starting this tutorial, ensure your development environment meets the following requirements: ### Technical knowledge * Intermediate TypeScript knowledge * Understanding of smart contract development * Familiarity with blockchain concepts ### Development environment * Unix-like operating system (Linux, macOS, or WSL for Windows) * Node.js version 16 or higher * Git for version control ### Required tools The tutorial uses these primary tools: * Foundry: For smart contract development * Supersim: For local blockchain simulation * TypeScript: For implementation * Viem: For blockchain interaction 1. Install [Foundry](https://book.getfoundry.sh/getting-started/installation). 2. Install [Node](https://nodejs.org/en). 3. Install [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). The exact mechanism to do this depends on your operating system; most come with it preinstalled. You can run this tutorial either with [Supersim](/app-developers/tools-sdks/supersim) running locally, or using the [Interop devnet](/app-developers/guides/building-apps). Select the correct tab and follow the directions. 1. Follow [Install Supersim](/app-developers/tutorials/development/supersim/installation) to set up Supersim for running blockchains with Interop. 2. Start Supersim. ```sh theme={null} ./supersim --interop.autorelay ``` 3. Supersim uses Foundry's `anvil` blockchains, which start with ten prefunded accounts. Set these environment variables to access one of those accounts on the L2 blockchains. ```sh theme={null} export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` 4. Specify the URLs to the chains. ```sh theme={null} SRC_URL=http://localhost:9545 DST_URL=http://localhost:9546 ``` Get the ETH balances for your address on both the source and destination chains. ```sh theme={null} cast balance --ether `cast wallet address $PRIVATE_KEY` --rpc-url $SRC_URL cast balance --ether `cast wallet address $PRIVATE_KEY` --rpc-url $DST_URL ``` 1. Set `PRIVATE_KEY` to the private key of an address that has [Sepolia ETH](https://cloud.google.com/application/web3/faucet/ethereum/sepolia). ```sh theme={null} export PRIVATE_KEY=0x ``` 2. Send ETH to the two L2 blockchains via their OptimismPortal contracts on Sepolia. ```sh theme={null} cast send --rpc-url https://endpoints.omniatech.io/v1/eth/sepolia/public --private-key $PRIVATE_KEY --value 0.02ether 0x7385d89d38ab79984e7c84fab9ce5e6f4815468a cast send --rpc-url https://endpoints.omniatech.io/v1/eth/sepolia/public --private-key $PRIVATE_KEY --value 0.02ether 0x55f5c4653dbcde7d1254f9c690a5d761b315500c ``` 3. Wait a few minutes until you can see the ETH [on the block explorer](https://sid.testnet.routescan.io/) for your address. 4. Specify the URLs to the chains. ```sh theme={null} SRC_URL=https://interop-alpha-0.optimism.io DST_URL=https://interop-alpha-1.optimism.io ``` Get the ETH balances for your address on both the source and destination chains. ```sh theme={null} cast balance --ether `cast wallet address $PRIVATE_KEY` --rpc-url $SRC_URL cast balance --ether `cast wallet address $PRIVATE_KEY` --rpc-url $DST_URL ``` Run these commands: ```sh theme={null} DST_CHAINID=`cast chain-id --rpc-url $DST_URL` MY_ADDRESS=`cast wallet address $PRIVATE_KEY` SUPERCHAIN_ETH_BRIDGE=0x4200000000000000000000000000000000000024 BEFORE=`cast balance $MY_ADDRESS --rpc-url $DST_URL | cast from-wei` cast send --rpc-url $SRC_URL --private-key $PRIVATE_KEY $SUPERCHAIN_ETH_BRIDGE "sendETH(address,uint256)" $MY_ADDRESS $DST_CHAINID --value 0.001ether sleep 10 AFTER=`cast balance $MY_ADDRESS --rpc-url $DST_URL | cast from-wei` echo -e Balance before transfer\\t$BEFORE echo -e Balance after transfer\\t$AFTER ``` Messages are relayed automatically in the interop devnet. ```sh theme={null} mkdir transfer-eth cd transfer-eth npm init -y npm install --save-dev -y viem tsx @types/node @eth-optimism/viem typescript mkdir src ``` ```sh theme={null} curl https://raw.githubusercontent.com/ethereum-optimism/optimism/refs/heads/develop/packages/contracts-bedrock/snapshots/abi/SuperchainETHBridge.json > src/SuperchainETHBridge.abi.json ``` ```typescript theme={null} import { createWalletClient, http, publicActions, getContract, Address, formatEther, parseEther, } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { supersimL2A, supersimL2B, interopAlpha0, interopAlpha1 } from '@eth-optimism/viem/chains' import { walletActionsL2, publicActionsL2, contracts as optimismContracts } from '@eth-optimism/viem' import superchainEthBridgeAbi from './SuperchainETHBridge.abi.json' const supersimAddress = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) const sourceChain = account.address === supersimAddress ? supersimL2A : interopAlpha0 const destinationChain = account.address === supersimAddress ? supersimL2B : interopAlpha1 const sourceWallet = createWalletClient({ chain: sourceChain, transport: http(), account, }).extend(publicActions) .extend(publicActionsL2()) .extend(walletActionsL2()) const destinationWallet = createWalletClient({ chain: destinationChain, transport: http(), account, }).extend(publicActions) .extend(publicActionsL2()) .extend(walletActionsL2()) const ethBridgeOnSource = await getContract({ address: optimismContracts.superchainETHBridge.address, abi: superchainEthBridgeAbi, client: sourceWallet, }) const reportBalance = async (address: string): Promise => { const sourceBalance = await sourceWallet.getBalance({ address }) const destinationBalance = await destinationWallet.getBalance({ address }) console.log(` Address: ${address} Balance on source chain: ${formatEther(sourceBalance)} Balance on destination chain: ${formatEther(destinationBalance)} `) } console.log('Before transfer') await reportBalance(account.address) const sourceHash = await ethBridgeOnSource.write.sendETH({ value: parseEther('0.001'), args: [account.address, destinationChain.id], }) const sourceReceipt = await sourceWallet.waitForTransactionReceipt({ hash: sourceHash, }) console.log('After transfer on source chain') await reportBalance(account.address) const sentMessages = await sourceWallet.interop.getCrossDomainMessages({ logs: sourceReceipt.logs, }) const sentMessage = sentMessages[0] const relayMessageParams = await sourceWallet.interop.buildExecutingMessage({ log: sentMessage.log, }) const relayMsgTxnHash = await destinationWallet.interop.relayCrossDomainMessage(relayMessageParams) await destinationWallet.waitForTransactionReceipt({ hash: relayMsgTxnHash }) console.log('After relaying message to destination chain') await reportBalance(account.address) ``` ```typescript theme={null} import { supersimL2A, supersimL2B, interopAlpha0, interopAlpha1 } from '@eth-optimism/viem/chains' ``` Import all chain definitions from `@eth-optimism/viem`. ```typescript theme={null} const supersimAddress="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) const sourceChain = account.address == supersimAddress ? supersimL2A : interopAlpha0 const destinationChain = account.address == supersimAddress ? supersimL2B : interopAlpha1 ``` If the address we use is `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266`, one of the prefunded addresses on `anvil`, assume we're using Supersim. Otherwise, use Interop devnet. ```typescript theme={null} const sourceHash = await ethBridgeOnSource.write.sendETH({ value: parseEther('0.001'), args: [account.address, destinationChain.id] }) const sourceReceipt = await sourceWallet.waitForTransactionReceipt({ hash: sourceHash }) ``` To relay a message we need the information in the receipt. Also, we need to wait until the transaction with the relayed message is actually part of a block. ```typescript theme={null} const sentMessages = await sourceWallet.interop.getCrossDomainMessages({ logs: sourceReceipt.logs, }) const sentMessage = sentMessages[0] ``` A single transaction can send multiple messages. But here we know we sent just one, so we look for the first one in the list. ```typescript theme={null} const relayMessageParams = await sourceWallet.interop.buildExecutingMessage({ log: sentMessage.log, }) const relayMsgTxnHash = await destinationWallet.interop.relayCrossDomainMessage(relayMessageParams) ``` This is how you use `@eth-optimism/viem` to create an executing message. 1. Run the example. ```sh theme={null} npx tsx src/transfer-eth.mts ``` 2. Read the results. ``` Before transfer Address: 0x7ED53BfaA58B79Dd655B2f229258C093b6C09A8C Balance on source chain: 0.020999799151902245 Balance on destination chain: 0.026999459226731331 ``` The initial state. Note that the address depends on your private key; it should be different from mine. ``` After transfer on source chain Address: 0x7ED53BfaA58B79Dd655B2f229258C093b6C09A8C Balance on source chain: 0.019999732176717961 Balance on destination chain: 0.026999459226731331 ``` After the initiating message the balance on the source chain is immediately reduced. Notice that even though we are sending 0.001 ETH, the balance on the source chain is reduced by a bit more (here, approximately 67 gwei). This is the cost of the initiating transaction on the source chain. Of course, as there has been no transaction on the destination chain, that balance is unchanged. ``` After relaying message to destination chain Address: 0x7ED53BfaA58B79Dd655B2f229258C093b6C09A8C Balance on source chain: 0.019999732176717961 Balance on destination chain: 0.027999278943880868 ``` Now the balance on the destination chain increases, by slightly less than 0.001 ETH. The executing message also has a transaction cost (in this case, about 180gwei). ## Next steps * Check out the [SuperchainETHBridge guide](/op-stack/interop/superchain-eth-bridge) for more information. * Review the [OP Stack interop explainer](/op-stack/interop/explainer) for answers to common questions about interoperability. # Bridging ERC-20 tokens to OP Mainnet Source: https://docs.optimism.io/app-developers/tutorials/bridging/cross-dom-bridge-erc20 Learn how to use @eth-optimism/viem and viem packages to transfer ERC-20 tokens between Layer 1 (Ethereum or Sepolia) and Layer 2 (OP Mainnet or OP Sepolia). This tutorial explains how you can use [@eth-optimism/viem](https://www.npmjs.com/package/@eth-optimism/viem) and [viem](https://viem.sh/op-stack) to bridge ERC-20 tokens between L1 (Ethereum or Sepolia) and L2 (OP Mainnet or OP Sepolia). The `@eth-optimism/viem` and `viem` packages are an easy way to add bridging functionality to your javascript-based application. They also provide some safety rails to prevent common mistakes that could cause tokens to be made inaccessible. Behind the scenes, `@eth-optimism/viem` package uses the [Standard Bridge](/app-developers/guides/bridging/standard-bridge) contracts to transfer tokens. Make sure to check out the [Standard Bridge guide](/app-developers/guides/bridging/standard-bridge) if you want to learn more about how the bridge works under the hood. The Standard Bridge **does not** support [**fee on transfer tokens**](https://github.com/d-xo/weird-erc20#fee-on-transfer) or [**rebasing tokens**](https://github.com/d-xo/weird-erc20#balance-modifications-outside-of-transfers-rebasingairdrops) because they can cause bridge accounting errors. ## Supported networks Viem supports any of the [OP Stack networks](https://viem.sh/op-stack/chains). If you want to use a network that isn't included by default, you can add it to Viem's chain [configurations](https://viem.sh/op-stack/chains#configuration). ## Dependencies * [node](https://nodejs.org/en/) * [pnpm](https://pnpm.io/installation) ## Create a demo project You're going to use the library for this tutorial. Since is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. ```bash theme={null} mkdir bridging-erc20-tokens cd bridging-erc20-tokens ``` ```bash theme={null} pnpm init ``` ```bash theme={null} pnpm add @eth-optimism/viem viem ``` ## Get ETH on Sepolia and OP Sepolia This tutorial explains how to bridge tokens from Sepolia to OP Sepolia. You will need to get some ETH on both of these testnets. ## Add a private key to your environment You need a private key in order to sign transactions. Set your private key as an environment variable with the `export` command. Make sure this private key corresponds to an address that has ETH on . Want to create a new wallet for this tutorial? If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) installed you can run `cast wallet new` in your terminal to create a new wallet and get the private key. ```bash theme={null} export TUTORIAL_PRIVATE_KEY=0x... ``` ## Start the Node REPL You're going to use the Node REPL to interact with . To start the Node REPL, run the following command in your terminal: ```bash theme={null} node ``` This will bring up a Node REPL prompt that allows you to run JavaScript code. ## Import dependencies You need to import some dependencies into your Node REPL session. The `@eth-optimism/viem` package uses ESM modules, and to use in the Node.js REPL, you need to use dynamic imports with await. Here's how to do it: ```js theme={null} const viem = await import('viem'); const { createPublicClient, createWalletClient, http, formatEther, parseEther} = viem; const accounts = await import('viem/accounts'); const { privateKeyToAccount } = accounts; const viemChains = await import('viem/chains'); const { optimismSepolia, sepolia } = viemChains; const opActions = await import('@eth-optimism/viem/actions'); const { depositERC20, withdrawOptimismERC20 } = opActions; ``` ## Set session variables You'll need a few variables throughout this tutorial. Let's set those up now. This step retrieves your private key from the environment variable you set earlier and converts it into an account object that Viem can use for transaction signing. The private key is essential for authorizing transactions on both L1 and L2 networks. For security reasons, we access it from an environment variable rather than hardcoding it. ```js theme={null} const PRIVATE_KEY = process.env.TUTORIAL_PRIVATE_KEY; const account = privateKeyToAccount(PRIVATE_KEY); ``` Here we establish the connections to both networks by creating four different clients: 1. L1 Public Client: For reading data from the Sepolia network 2. L1 Wallet Client: For signing and sending transactions on Sepolia 3. L2 Public Client: For reading data from OP Sepolia 4. L2 Wallet Client: For signing and sending transactions on OP Sepolia Each client is configured with the appropriate chain information and RPC endpoint. This dual-network setup allows us to seamlessly interact with both layers using the same account. Replace `` with your API key from a RPC provider. ```js theme={null} const L1_RPC_URL = 'https://ethereum-sepolia-rpc.publicnode.com'; const L2_RPC_URL = 'https://sepolia.optimism.io'; const publicClientL1 = createPublicClient({ chain: sepolia, transport: http(L1_RPC_URL), }); const walletClientL1 = createWalletClient({ account, chain: sepolia, transport: http(L1_RPC_URL), }); const publicClientL2 = createPublicClient({ chain: optimismSepolia, transport: http(L2_RPC_URL), }); const walletClientL2 = createWalletClient({ account, chain: optimismSepolia, transport: http(L2_RPC_URL), }); ``` We define the addresses of the ERC-20 tokens on both networks. These are specially deployed test tokens with corresponding implementations on both L1 (Sepolia) and L2 (OP Sepolia). The L2 token is configured to recognize deposits from its L1 counterpart. We also define a constant `oneToken` representing the full unit (10^18 wei) to simplify our deposit and withdrawal operations. ```js theme={null} const l1Token = "0x5589BB8228C07c4e15558875fAf2B859f678d129"; const l2Token = "0xD08a2917653d4E460893203471f0000826fb4034"; ``` If you're coming from the [Create an L2 token for the Standard Bridge](./standard-bridge-standard-token) tutorial, you can use the addresses of your own ERC-20 tokens here instead. ## Get L1 tokens You're going to need some tokens on L1 that you can bridge to L2. The L1 testing token located at [`0x5589BB8228C07c4e15558875fAf2B859f678d129`](https://sepolia.etherscan.io/address/0x5589BB8228C07c4e15558875fAf2B859f678d129) has a `faucet` function that makes it easy to get tokens. The Application Binary Interface (ABI) defines how to interact with the smart contract functions. This ERC-20 ABI includes several critical functions: * `balanceOf`: Allows us to check token balances for any address * `faucet`: A special function in this test token that mints new tokens to the caller * `approve`: Required to grant the bridge permission to transfer tokens on our behalf * `allowance`: To check how many tokens we've approved for the bridge * `decimals` and `symbol`: Provide token metadata This comprehensive ABI gives us everything we need to manage our tokens across both L1 and L2. ```js theme={null} const erc20ABI = [ { inputs: [ { internalType: "address", name: "account", type: "address", }, ], name: "balanceOf", outputs: [ { internalType: "uint256", name: "", type: "uint256", }, ], stateMutability: "view", type: "function", }, { inputs: [], name: "faucet", outputs: [], stateMutability: "nonpayable", type: "function", }, { inputs: [ { internalType: "address", name: "spender", type: "address" }, { internalType: "uint256", name: "value", type: "uint256" } ], name: "approve", outputs: [ { internalType: "bool", name: "", type: "bool" } ], stateMutability: "nonpayable", type: "function" }, ]; ``` Now we'll call the `faucet` function on the L1 test token contract to receive free tokens for testing. This transaction will mint new tokens directly to our wallet address. The function doesn't require any parameters - it simply credits a predetermined amount to whoever calls it. We store the transaction hash for later reference and wait for the transaction to be confirmed. ```js theme={null} console.log('Getting tokens from faucet...'); const tx = await walletClientL1.writeContract({ address: l1Token, abi: erc20ABI, functionName: 'faucet', account, }); console.log('Faucet transaction:', tx); ``` After using the faucet, we verify our token balance by calling the `balanceOf` function on the L1 token contract. This step confirms that we've successfully received tokens before proceeding with the bridging process. The balance is returned in the smallest unit (wei), but we format it into a more readable form using the `formatEther` utility function from `viem`, since this token uses 18 decimal places. ```js theme={null} const l1Balance = await publicClientL1.readContract({ address: l1Token, abi: erc20ABI, functionName: 'balanceOf', args: [account.address] }); console.log(`L1 Balance after receiving faucet: ${formatEther(l1Balance)}`); ``` ## Deposit tokens Now that you have some tokens on L1, you can deposit those tokens into the `L1StandardBridge` contract. You'll then receive the same number of tokens on L2 in return. We define a variable `oneToken` that represents 1 full token in its base units (wei). ERC-20 tokens typically use 18 decimal places, so 1 token equals 10^18 wei. This constant helps us work with precise token amounts in our transactions, avoiding rounding errors and ensuring exact value transfers. We'll use this value for both deposits and withdrawals ```js theme={null} const oneToken = parseEther('1') ``` ERC-20 tokens require a two-step process for transferring tokens on behalf of a user. First, we must grant permission to the bridge contract to spend our tokens by calling the `approve` function on the token contract. We specify the bridge address from the chain configuration and the exact amount we want to bridge. This approval transaction must be confirmed before the bridge can move our tokens. ```js theme={null} const bridgeAddress = optimismSepolia.contracts.l1StandardBridge[sepolia.id].address; const approveTx = await walletClientL1.writeContract({ address: l1Token, abi: erc20ABI, functionName: 'approve', args: [bridgeAddress, oneToken], }); console.log('Approval transaction:', approveTx); ``` After submitting the approval transaction, we need to wait for it to be confirmed on L1. We use the `waitForTransactionReceipt` function to monitor the transaction until it's included in a block. The receipt provides confirmation details, including which block includes our transaction. This step ensures our approval is finalized before attempting to bridge tokens. ```js theme={null} await publicClientL1.waitForTransactionReceipt({ hash: approveTx }); ``` Now we can execute the actual bridging operation using the `depositERC20` function from the `@eth-optimism/viem` package. This function handles all the complex interactions with the `L1StandardBridge` contract for us. We provide: * The addresses of both the L1 and L2 tokens * The amount to bridge * The target chain (OP Sepolia) * Our wallet address as the recipient on L2 * A minimum gas limit for the L2 transaction This streamlined process ensures our tokens are safely transferred to L2. ```js theme={null} console.log('Depositing tokens to L2...'); const depositTx = await depositERC20(walletClientL1, { tokenAddress: l1Token, remoteTokenAddress: l2Token, amount: oneToken, targetChain: optimismSepolia, to: account.address, minGasLimit: 200000, }); console.log(`Deposit transaction hash: ${depositTx}`); ``` Using a smart contract wallet? As a safety measure, `depositERC20` will fail if you try to deposit ETH from a smart contract wallet without specifying a `recipient`. Add the `recipient` option to the `depositERC20` call to fix this. Check out the [@eth-optimism/viem docs](https://github.com/ethereum-optimism/ecosystem/tree/main/packages/viem) for more info on the options you can pass to `depositERC20`. After initiating the deposit, we need to wait for the L1 transaction to be confirmed. This function tracks the transaction until it's included in an L1 block. Note that while this confirms the deposit was accepted on L1, there will still be a short delay (typically a few minutes) before the tokens appear on L2, as the transaction needs to be processed by the Optimism sequencer. ```js theme={null} const depositReceipt = await publicClientL1.waitForTransactionReceipt({ hash: depositTx }); console.log(`Deposit confirmed in block ${depositReceipt.blockNumber}`); ``` After the deposit transaction is confirmed, we check our token balance on L1 again to verify that the tokens have been deducted. This balance should be lower by the amount we bridged, as those tokens are now escrowed in the `L1StandardBridge` contract. This step helps confirm that the first part of the bridging process completed successfully: ```js theme={null} const l1BalanceAfterDeposit = await publicClientL1.readContract({ address: l1Token, abi: erc20ABI, functionName: 'balanceOf', args: [account.address] }); console.log(`L1 Balance after deposit: ${formatEther(l1BalanceAfterDeposit)}`); ``` After allowing some time for the L2 transaction to be processed, we check our token balance on L2 to verify that we've received the bridged tokens. The newly minted L2 tokens should appear in our wallet at the same address we used on L1. This step confirms the complete success of the bridge operation from L1 to L2. ```js theme={null} const l2Balance = await publicClientL2.readContract({ address: l2Token, abi: erc20ABI, functionName: 'balanceOf', args: [account.address] }); console.log(`L2 Balance after withdrawal: ${formatEther(l2Balance)}`); ``` ## Withdraw tokens You just bridged some tokens from L1 to L2. Nice! Now you're going to repeat the process in reverse to bridge some tokens from L2 to L1. To move tokens back to L1, we use the `withdrawOptimismERC20` function from the `@eth-optimism/viem` package. This function interacts with the `L2StandardBridge` contract to initialize the withdrawal process. We specify: * The L2 token address * The amount to withdraw (we're using half of a token in this tutorial) * Our address as the recipient on L1 * A minimum gas limit for the transaction Unlike deposits, withdrawals from L2 to L1 are not immediate and require a multi-step process including a 7-day challenge period for security reasons. ```js theme={null} console.log('Withdrawing tokens back to L1...'); const withdrawTx = await withdrawOptimismERC20(walletClientL2, { tokenAddress: l2Token, amount: oneToken / 2n, to: account.address, minGasLimit: 200000, }); console.log(`Withdrawal transaction hash: ${withdrawTx}`); ``` Similar to deposits, we wait for the withdrawal transaction to be confirmed on L2. This receipt provides confirmation that the withdrawal has been initiated. The transaction logs contain critical information that will be used later in the withdrawal verification process. This is only the first step in the withdrawal - the tokens are now locked on L2, but not yet available on L1. ```js theme={null} const withdrawReceipt = await publicClientL2.waitForTransactionReceipt({ hash: withdrawTx }); console.log(`Withdrawal initiated in L2 block ${withdrawReceipt.blockNumber}`); ``` This step can take a few minutes. Feel free to take a quick break while you wait. After the withdrawal transaction is confirmed, we check our token balance on L2 again to verify that the tokens have been deducted. Our L2 balance should now be lower by the amount we initiated for withdrawal. At this point, the withdrawal process has begun, but the tokens are not yet available on L1 - please refer to [Withdraw ETH](./cross-dom-bridge-eth#withdraw-eth) to continue with the “prove” and “finalize” withdrawal steps. ```js theme={null} const l2Balance = await publicClientL2.readContract({ address: l2Token, abi: erc20ABI, functionName: 'balanceOf', args: [account.address] }); console.log(`L2 Balance after withdrawal initiation: ${formatEther(l2Balance)}`); ``` ## Next steps Congrats! You've just deposited and withdrawn tokens using `@eth-optimism/viem` package. You should now be able to write applications that use the `@eth-optimism/viem` package to transfer ERC-20 tokens between L1 and L2. Although this tutorial used Sepolia and OP Sepolia, the same process works for Ethereum and OP Mainnet. # Submitting Transactions from L1 Source: https://docs.optimism.io/app-developers/tutorials/bridging/cross-dom-bridge-eth Learn how to process deposit transactions and withdrawals with Viem. **Learn the OP Stack — stop 10 of 13.** You've read how deposits and withdrawals work. In this project you walk both directions end to end from code, using Viem. When you're done, continue to [Fault proofs explainer](/op-stack/fault-proofs/explainer). This tutorial explains how to use [Viem](https://viem.sh/op-stack) to process cross-domain transactions: * [Deposited transactions](https://specs.optimism.io/protocol/deposits.html): Also known as deposits, these are transactions initiated on L1 and executed on L2. They can be used to submit arbitrary L2 transactions from L1. * [Withdrawals](https://specs.optimism.io/protocol/withdrawals.html): These are cross-domain transactions initiated on L2 and finalized by a transaction executed on L1. They can be used to send arbitrary messages on L1 from L2 via the `OptimismPortal`. Both deposit transactions and withdrawals can transfer ETH and data. ## Supported networks Viem supports any of the [OP Stack networks](https://viem.sh/op-stack/chains). The OP Stack networks are included in Viem by default. If you want to use a network that isn't included by default, you can add it to Viem's chain [configurations](https://viem.sh/op-stack/chains#configuration). ## Dependencies * [node](https://nodejs.org/en/) * [pnpm](https://pnpm.io/installation) ## Create a demo project You're going to use the library for this tutorial. Since is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. ```bash theme={null} mkdir bridge-eth cd bridge-eth ``` ```bash theme={null} pnpm init ``` ```bash theme={null} pnpm add viem@^2.51.0 ``` ## Get ETH on Sepolia This tutorial explains how to bridge ETH from Sepolia to OP Sepolia. You will need to get some ETH on Sepolia to follow along. ## Add a private key to your environment You need a private key in order to sign transactions. Set your private key as an environment variable with the `export` command. Make sure this private key corresponds to an address that has ETH on . Want to create a new wallet for this tutorial? If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) installed you can run `cast wallet new` in your terminal to create a new wallet and get the private key. ```bash theme={null} export TUTORIAL_PRIVATE_KEY=0x... ``` ## Start the Node REPL You're going to use the Node REPL to interact with . To start the Node REPL, run the following command in your terminal: ```bash theme={null} node ``` This will bring up a Node REPL prompt that allows you to run JavaScript code. ## Import dependencies You need to import some dependencies into your Node REPL session. ```js theme={null} const { createPublicClient, http, createWalletClient, parseEther, formatEther } = require('viem'); const { sepolia, optimismSepolia } = require('viem/chains'); const { privateKeyToAccount } = require('viem/accounts'); const { getL2TransactionHashes, publicActionsL1, publicActionsL2, walletActionsL1, walletActionsL2, isSuperGameType } = require('viem/op-stack'); ``` ```js theme={null} const PRIVATE_KEY = process.env.TUTORIAL_PRIVATE_KEY; const account = privateKeyToAccount(PRIVATE_KEY); ``` ```js theme={null} const publicClientL1 = createPublicClient({ chain: sepolia, transport: http("https://ethereum-sepolia-rpc.publicnode.com"), }).extend(publicActionsL1()) ``` ```js theme={null} const walletClientL1 = createWalletClient({ account, chain: sepolia, transport: http("https://ethereum-sepolia-rpc.publicnode.com"), }).extend(walletActionsL1()); ``` ```js theme={null} const publicClientL2 = createPublicClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io"), }).extend(publicActionsL2()); ``` ```js theme={null} const walletClientL2 = createWalletClient({ account, chain: optimismSepolia, transport: http("https://sepolia.optimism.io"), }).extend(walletActionsL2()); ``` ## Get ETH on Sepolia You're going to need some ETH on L1 that you can bridge to L2. You can get some Sepolia ETH from [this faucet](https://sepoliafaucet.com). ## Deposit ETH Now that you have some ETH on L1, in addition to using the method described in [Bridging ETH](/app-developers/guides/bridging/standard-bridge#bridging-eth), you can also deposit ETH using the approach shown in the example below. If you are using a contract account, you should pay attention to [Address Aliasing](https://specs.optimism.io/protocol/deposits.html#address-aliasing). See how much ETH you have on L1 so you can confirm that the deposit worked later on. ```js theme={null} const l1Balance = await publicClientL1.getBalance({ address: account.address }); console.log(`L1 Balance: ${formatEther(l1Balance)} ETH`); ``` We used `formatEther` method from `viem` to format the balance to ether. Use [buildDepositTransaction](https://viem.sh/op-stack/actions/buildDepositTransaction) to build the deposit transaction parameters on L2. Be sure to understand the meanings of the optional parameters `mint` and `value`. You can also use someone else’s address as the `to` value if desired. ```js theme={null} const depositArgs = await publicClientL2.buildDepositTransaction({ mint: parseEther("0.01"), to: account.address, }); ``` Send the deposit transaction on L1 and log the L1 transaction hash. ```js theme={null} const depositHash = await walletClientL1.depositTransaction(depositArgs); console.log(`Deposit transaction hash on L1: ${depositHash}`); ``` Wait for the L1 transaction to be processed and log the receipt. ```js theme={null} const depositReceipt = await publicClientL1.waitForTransactionReceipt({ hash: depositHash }); console.log('L1 transaction confirmed:', depositReceipt); ``` Extracts the corresponding L2 transaction hash from the L1 receipt, and logs it. This hash represents the deposit transaction on L2. ```js theme={null} const [l2Hash] = getL2TransactionHashes(depositReceipt); console.log(`Corresponding L2 transaction hash: ${l2Hash}`); ``` Wait for the L2 transaction to be processed and confirmed and logs the L2 receipt to verify completion. ```js theme={null} const l2Receipt = await publicClientL2.waitForTransactionReceipt({ hash: l2Hash, }); console.log('L2 transaction confirmed:', l2Receipt); console.log('Deposit completed successfully!'); ``` ```js theme={null} const { createPublicClient, http, createWalletClient, parseEther, formatEther } = require('viem'); const { sepolia, optimismSepolia } = require('viem/chains'); const { privateKeyToAccount } = require('viem/accounts'); const { getL2TransactionHashes, publicActionsL1, publicActionsL2, walletActionsL1, walletActionsL2, isSuperGameType } = require('viem/op-stack'); const PRIVATE_KEY = process.env.TUTORIAL_PRIVATE_KEY; const account = privateKeyToAccount(PRIVATE_KEY); const publicClientL1 = createPublicClient({ chain: sepolia, transport: http("https://ethereum-sepolia-rpc.publicnode.com"), }).extend(publicActionsL1()) const walletClientL1 = createWalletClient({ account, chain: sepolia, transport: http("https://ethereum-sepolia-rpc.publicnode.com"), }).extend(walletActionsL1()); const publicClientL2 = createPublicClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io"), }).extend(publicActionsL2()); const walletClientL2 = createWalletClient({ account, chain: optimismSepolia, transport: http("https://sepolia.optimism.io"), }).extend(walletActionsL2()); const l1Balance = await publicClientL1.getBalance({ address: account.address }); console.log(`L1 Balance: ${formatEther(l1Balance)} ETH`); async function depositETH() { const depositArgs = await publicClientL2.buildDepositTransaction({ mint: parseEther("0.01"), to: account.address, }); const depositHash = await walletClientL1.depositTransaction(depositArgs); console.log(`Deposit transaction hash on L1: ${depositHash}`); const depositReceipt = await publicClientL1.waitForTransactionReceipt({ hash: depositHash }); console.log('L1 transaction confirmed:', depositReceipt); const [l2Hash] = getL2TransactionHashes(depositReceipt); console.log(`Corresponding L2 transaction hash: ${l2Hash}`); const l2Receipt = await publicClientL2.waitForTransactionReceipt({ hash: l2Hash, }); console.log('L2 transaction confirmed:', l2Receipt); console.log('Deposit completed successfully!'); } ``` ## Withdraw ETH You just bridged some ETH from L1 to L2. Nice! Now you’re going to repeat the process in reverse to bridge some ETH from L2 to L1. In addition to the method described in [Bridging ETH](/app-developers/guides/bridging/standard-bridge#bridging-eth), you can also withdraw ETH using the example approach shown below. Uses `buildInitiateWithdrawal` to create the withdrawal parameters. Converts the withdrawal amount to `wei` and specifies the recipient on L1. ```js theme={null} //Add the same imports used in DepositETH function const withdrawalArgs = await publicClientL1.buildInitiateWithdrawal({ value: parseEther('0.005'), to: account.address, }); ``` This sends the withdrawal transaction on L2, which initiates the withdrawal process on L2 and logs a transaction hash for tracking the withdrawal. ```js theme={null} const withdrawalHash = await walletClientL2.initiateWithdrawal(withdrawalArgs); console.log(`Withdrawal transaction hash on L2: ${withdrawalHash}`); ``` Wait one hour (max) for the L2 Output containing the transaction to be proposed, and log the receipt, which contains important details like the block number etc. ```js theme={null} const withdrawalReceipt = await publicClientL2.waitForTransactionReceipt({ hash: withdrawalHash }); const withdrawalBlock = await publicClientL2.getBlock({ blockNumber: withdrawalReceipt.blockNumber }); const respectedGameType = await publicClientL1.readContract({ abi: [{ inputs: [], name: 'respectedGameType', outputs: [{ type: 'uint32' }], stateMutability: 'view', type: 'function' }], address: publicClientL2.chain.contracts.portal[publicClientL1.chain.id].address, functionName: 'respectedGameType' }); const proveContext = isSuperGameType(Number(respectedGameType)) ? { l2Timestamp: withdrawalBlock.timestamp } : {}; console.log('L2 transaction confirmed:', withdrawalReceipt); ``` Next, is to prove to the bridge on L1 that the withdrawal happened on L2. To achieve that, you first need to wait until the withdrawal is ready to prove. ```js theme={null} const { game, withdrawal } = await publicClientL1.waitToProve({ ...proveContext, receipt: withdrawalReceipt, targetChain: walletClientL2.chain }); ``` Build parameters to prove the withdrawal on the L2. ```js theme={null} const proveArgs = await publicClientL2.buildProveWithdrawal({ game, withdrawal, }); ``` Once the withdrawal is ready to be proven, you'll send an L1 transaction to prove that the withdrawal happened on L2. ```js theme={null} const proveHash = await walletClientL1.proveWithdrawal(proveArgs); const proveReceipt = await publicClientL1.waitForTransactionReceipt({ hash: proveHash }); ``` Before a withdrawal transaction can be finalized, you will need to wait for the finalization period. This can only happen after the fault proof period has elapsed. On OP Mainnet, this takes 7 days. ```js theme={null} const awaitWithdrawal = await publicClientL1.waitToFinalize({ targetChain: walletClientL2.chain, withdrawalHash: withdrawal.withdrawalHash, }); ``` We're currently testing fault proofs on OP Sepolia, so withdrawal times reflect Mainnet times. ```js theme={null} const finalizeHash = await walletClientL1.finalizeWithdrawal({ targetChain: walletClientL2.chain, withdrawal, }); ``` ```js theme={null} const finalizeReceipt = await publicClientL1.waitForTransactionReceipt({ hash: finalizeHash }); ``` ```js theme={null} //Add the same imports used in DepositETH function const withdrawalArgs = await publicClientL1.buildInitiateWithdrawal({ value: parseEther('0.005'), to: account.address, }); const withdrawalHash = await walletClientL2.initiateWithdrawal(withdrawalArgs); console.log(`Withdrawal transaction hash on L2: ${withdrawalHash}`); const withdrawalReceipt = await publicClientL2.waitForTransactionReceipt({ hash: withdrawalHash }); const withdrawalBlock = await publicClientL2.getBlock({ blockNumber: withdrawalReceipt.blockNumber }); const respectedGameType = await publicClientL1.readContract({ abi: [{ inputs: [], name: 'respectedGameType', outputs: [{ type: 'uint32' }], stateMutability: 'view', type: 'function' }], address: publicClientL2.chain.contracts.portal[publicClientL1.chain.id].address, functionName: 'respectedGameType' }); const proveContext = isSuperGameType(Number(respectedGameType)) ? { l2Timestamp: withdrawalBlock.timestamp } : {}; console.log('L2 transaction confirmed:', withdrawalReceipt); const { game, withdrawal } = await publicClientL1.waitToProve({ ...proveContext, receipt: withdrawalReceipt, targetChain: walletClientL2.chain }); const proveArgs = await publicClientL2.buildProveWithdrawal({ game, withdrawal, }); const proveHash = await walletClientL1.proveWithdrawal(proveArgs); const proveReceipt = await publicClientL1.waitForTransactionReceipt({ hash: proveHash }); const awaitWithdrawal = await publicClientL1.waitToFinalize({ targetChain: walletClientL2.chain, withdrawalHash: withdrawal.withdrawalHash, }); const finalizeHash = await walletClientL1.finalizeWithdrawal({ targetChain: walletClientL2.chain, withdrawal, }); const finalizeReceipt = await publicClientL1.waitForTransactionReceipt({ hash: finalizeHash }); ``` Recommend checking with [getWithdrawalStatus](https://viem.sh/op-stack/actions/getWithdrawalStatus) before the `waitToProve` and `waitToFinalize` actions. ```js theme={null} const status = await publicClientL1.getWithdrawalStatus({ ...proveContext, receipt: withdrawalReceipt, targetChain: walletClientL2.chain }) console.log(`Withdrawal status: ${status}`) ``` ## Submitting Arbitrary L2 Transactions from L1 EOAs can submit any transaction on L1 that needs to be executed on L2. This also makes it possible for users to interact with contracts on L2 even when the [Sequencer is down](/op-stack/transactions/forced-transaction). If the caller is a contract on L1, you need to pay attention to [Address Aliasing](https://specs.optimism.io/protocol/deposits.html#address-aliasing). If you have just completed the [Bridging ERC-20 tokens to OP Mainnet](/app-developers/tutorials/bridging/cross-dom-bridge-erc20) tutorial, you can try initiating an ERC-20 transfer transaction on L1 that will be executed on L2. `encodeFunctionData` and `erc20Abi` can be imported from Viem. ```js theme={null} const oneToken = parseEther('1') // L2 faucet token contract const to = "0xD08a2917653d4E460893203471f0000826fb4034" const data = encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [ "0x000000000000000000000000000000000000dEaD", // recipient oneToken / 2n, ], }); const args = await publicClientL2.buildDepositTransaction({ account, data, to, }); ``` ## Use `OptimismPortal` to Send Arbitrary Messages on L1 from L2 The `L2ToL1MessagePasser` contract’s `initiateWithdrawal` function accepts a `_target` address and `_data` bytes. These are passed to a CALL opcode on L1 when `finalizeWithdrawalTransaction` is executed after the challenge period. This means that, by design, the `OptimismPortal` contract can be used to send arbitrary transactions on L1, with the `OptimismPortal` acting as the `msg.sender`. ## Important Considerations * The purpose of this tutorial is to introduce deposited transactions and withdrawals. You should first consider whether the [standard bridge](/app-developers/guides/bridging/standard-bridge) and the [messenger](/app-developers/guides/bridging/messaging) meet your use case requirements. * When working with deposited transactions, consider the implications of [Address Aliasing](https://specs.optimism.io/protocol/deposits.html#address-aliasing). * When working with withdrawals, consider that [OptimismPortal can send arbitrary messages on L1](https://specs.optimism.io/protocol/withdrawals.html#optimismportal-can-send-arbitrary-messages-on-l1). * Challenge period: The 7-day withdrawal challenge period is crucial for security. * Gas costs: Withdrawals involve transactions on both L2 and L1, each incurring gas fees. * Private key handling: Use secure key management practices in real applications. * RPC endpoint security: Keep your API key (or any RPC endpoint) secure. # Communicating between OP Stack and Ethereum in Solidity Source: https://docs.optimism.io/app-developers/tutorials/bridging/cross-dom-solidity Learn how to write Solidity contracts on OP Stack and Ethereum that can talk to each other. This tutorial explains how to write Solidity contracts on OP Stack and Ethereum that can talk to each other. Here you'll use a contract on OP Stack that can set a "greeting" variable on a contract on Ethereum, and vice-versa. This is a simple example, but the same technique can be used to send any kind of message between the two chains. You won't actually be deploying any smart contracts as part of this tutorial. Instead, you'll reuse existing contracts that have already been deployed to OP Stack and Ethereum. Later in the tutorial you'll learn exactly how these contracts work so you can follow the same pattern to deploy your own contracts. Just looking to bridge tokens between OP Stack and Ethereum? Check out the tutorial on [Bridging ERC-20 Tokens to OP Stack With viem](./cross-dom-bridge-erc20). ## Message passing basics OP Stack uses a smart contract called the `CrossDomainMessenger` to pass messages between OP Stack and Ethereum. Both chains have a version of this contract (the `L1CrossDomainMessenger` and the `L2CrossDomainMessenger`). Messages sent from Ethereum to OP Stack are automatically relayed behind the scenes. Messages sent from OP Stack to Ethereum must be explicitly relayed with a second transaction on Ethereum. Read more about message passing in the guide to [Sending Data Between L1 and L2](/app-developers/guides/bridging/messaging). ## Dependencies * [node](https://nodejs.org/en/) * [pnpm](https://pnpm.io/installation) ## Get ETH on Sepolia and OP Sepolia This tutorial explains how to send messages from Sepolia to OP Sepolia. You will need to get some ETH on both of these testnets. ## Review the contracts You're about to use two contracts that have already been deployed to Sepolia and OP Sepolia, the `Greeter` contracts. You can review the source code for the L1 `Greeter` contract [here on Etherscan](https://sepolia.etherscan.io/address/0x31A6Dd971306bb72f2ffF771bF30b1B98dB8B2c5#code). You can review the source code for the L2 `Greeter` contract [here on Etherscan](https://testnet-explorer.optimism.io/address/0x5DE8a2957eddb140567fF90ba5d57bc9769f3055#code). Both contracts have exactly the same source code. Feel free to review the source code for these two contracts now if you'd like. This tutorial will explain how these contracts work in detail later on in the [How It Works](#how-it-works) section below. ## Interact with the L1 Greeter You're first going to use the L1 `Greeter` contract to set the greeting on the L2 `Greeter` contract. You'll send a transaction directly to the L1 `Greeter` contract which will ask the `L1CrossDomainMessenger` to send a message to the L2 `Greeter` contract. After just a few minutes, you'll see the corresponding greeting set on the L2 `Greeter` contract. Sending a message to the L2 `Greeter` contract via the L1 `Greeter` contract requires that you call the `sendGreeting` function. For simplicity, you'll interact with the contract directly on Etherscan. Open up the [L1 `Greeter` contract on Sepolia Etherscan](https://sepolia.etherscan.io/address/0x31A6Dd971306bb72f2ffF771bF30b1B98dB8B2c5#writeContract) and click the "Connect to Web3" button. Put a greeting into the field next to the "sendGreeting" function and click the "Write" button. You can use any greeting you'd like. It will take a few minutes for your message to reach L2. Feel free to take a quick break while you wait. You can use viem to programmatically check the status of any message between L1 and L2. Later on in this tutorial you'll learn how to use viem and the `waitToProve` function to wait for various message statuses. This same function can be used to wait for a message to be relayed from L1 to L2. After a few minutes, you should see the greeting on the L2 `Greeter` contract change to the greeting you set. Open up the [L2 `Greeter` contract on OP Sepolia Etherscan](https://testnet-explorer.optimism.io/address/0x5DE8a2957eddb140567fF90ba5d57bc9769f3055#readContract) and click the "Read Contract" button. Paste your address into the field next to the "greeting" function and click the "Query" button. You should see the message you sent from L1. Haven't seen your message yet? You might need to wait a little longer. L2 transactions triggered on L1 are typically processed within one minute but can occasionally be slightly delayed. ## Interact with the L2 Greeter Now you're going to use the L2 `Greeter` contract to set the greeting on the L1 `Greeter` contract. You'll send a transaction directly to the L2 `Greeter` contract which will ask the `L2CrossDomainMessenger` to send a message to the L1 `Greeter` contract. Unlike the previous step, you'll need to relay the message from L2 to L1 yourself. You'll do this by sending two transactions on Sepolia, one proving transaction and one relaying transaction. Just like before, sending a message to the L1 `Greeter` contract via the L2 `Greeter` contract requires that you call the `sendGreeting` function. Open up the [L2 `Greeter` contract on OP Sepolia Etherscan](https://testnet-explorer.optimism.io/address/0x5DE8a2957eddb140567fF90ba5d57bc9769f3055#writeContract) and click the "Connect to Web3" button. Put a greeting into the field next to the "sendGreeting" function and click the "Write" button. You can use any greeting you'd like. Copy the transaction hash from the transaction you just sent. You'll need this for the next few steps. Feel free to keep this tab open so you can easily copy the transaction hash later. You're going to use viem to prove and relay your message to L1. ```bash theme={null} mkdir cross-dom cd cross-dom pnpm init pnpm add viem@^2.51.0 ``` Set your private key and transaction hash as environment variables. ```bash theme={null} export TUTORIAL_PRIVATE_KEY=0x... export TUTORIAL_TRANSACTION_HASH=0x... ``` Start a Node.js REPL with `node` and paste the following script to monitor, prove, and finalize the cross-domain message: ```js theme={null} const { createPublicClient, http, createWalletClient } = require('viem'); const { optimismSepolia, sepolia } = require('viem/chains'); const { publicActionsL1, publicActionsL2, walletActionsL1, walletActionsL2, getWithdrawals, isSuperGameType } = require('viem/op-stack'); const { privateKeyToAccount } = require('viem/accounts'); const l1Provider = createPublicClient({ chain: sepolia, transport: http('https://eth-sepolia.g.alchemy.com/v2/your-key') }).extend(publicActionsL1()); const l2Provider = createPublicClient({ chain: optimismSepolia, transport: http('https://opt-sepolia.g.alchemy.com/v2/your-key') }).extend(publicActionsL2()); const account = privateKeyToAccount(process.env.TUTORIAL_PRIVATE_KEY); const l1Wallet = createWalletClient({ account, chain: sepolia, transport: http('https://eth-sepolia.g.alchemy.com/v2/your-key') }).extend(walletActionsL1()); const l2Wallet = createWalletClient({ account, chain: optimismSepolia, transport: http('https://opt-sepolia.g.alchemy.com/v2/your-key') }).extend(walletActionsL2()); const receipt = await l2Provider.getTransactionReceipt({ hash: process.env.TUTORIAL_TRANSACTION_HASH }); const withdrawalBlock = await l2Provider.getBlock({ blockNumber: receipt.blockNumber }); const respectedGameType = await l1Provider.readContract({ abi: [{ inputs: [], name: 'respectedGameType', outputs: [{ type: 'uint32' }], stateMutability: 'view', type: 'function' }], address: l2Provider.chain.contracts.portal[l1Provider.chain.id].address, functionName: 'respectedGameType' }); const proveContext = isSuperGameType(Number(respectedGameType)) ? { l2Timestamp: withdrawalBlock.timestamp } : {}; console.log('Waiting for message to be provable...'); await l1Provider.getWithdrawalStatus({ ...proveContext, receipt, targetChain: l2Provider.chain }); console.log('Proving message...'); const { game, withdrawal } = await l1Provider.waitToProve({ ...proveContext, receipt, targetChain: l2Provider.chain }); const proveArgs = await l2Provider.buildProveWithdrawal({ account, game, withdrawal }); await l1Wallet.proveWithdrawal(proveArgs); console.log('Waiting for message to be relayable...'); await l1Provider.waitToFinalize({ targetChain: l2Provider.chain, withdrawalHash: withdrawal.withdrawalHash }); console.log('Relaying message...'); await l1Wallet.finalizeWithdrawal({ targetChain: l2Wallet.chain, withdrawal }); console.log('Message relayed!'); ``` After finalization, open the [L1 `Greeter` contract on Sepolia Etherscan](https://sepolia.etherscan.io/address/0x31A6Dd971306bb72f2ffF771bF30b1B98dB8B2c5#readContract). Confirm that the greeting has been updated to the message you sent from L2. ## How it works Congratulations! You've successfully sent a message from L1 to L2 and from L2 to L1. This section explains how the `Greeter` contracts work so you can follow the same pattern to deploy your own contracts. Luckily, both `Greeter` contracts are exactly the same so it's easy to see how everything comes together. ### The Messenger variable The `Greeter` contract has a `MESSENGER` variable that keeps track of the `CrossDomainMessenger` contract on the current chain. Check out the [Contract Addresses page](/op-mainnet/network-information/op-addresses) to see the addresses of the `CrossDomainMessenger` contracts on whatever network you'll be using. ```solidity theme={null} address public immutable MESSENGER; ``` ### The other Greeter variable The `Greeter` contract also has an `OTHER_GREETER` variable that keeps track of the `Greeter` contract on the other chain. On L1, this variable is set to the address of the L2 `Greeter` contract, and vice-versa. ```solidity theme={null} address public immutable OTHER_GREETER; ``` ### The Greetings mapping The `Greeter` contract keeps track of the different greetings that users have sent inside a `greetings` mapping. By using a mapping, this contract can keep track of greetings from different users at the same time. ```solidity theme={null} mapping(address => string) public greetings; ``` ### The Constructor The `Greeter` has a simple constructor that sets the `MESSENGER` and `OTHER_GREETER` variables. ```solidity theme={null} constructor(address messenger, address otherGreeter) { MESSENGER = messenger; OTHER_GREETER = otherGreeter; } ``` ### The sendGreeting function The `sendGreeting` function is the most important function in the `Greeter` contract. This is what you called earlier to send messages in both directions. All this function does is use the `sendMessage` function found within the `CrossDomainMessenger` contract to send a message to the `Greeter` contract on the other chain. ```solidity theme={null} function sendGreeting(string calldata newGreeting) external payable { ICrossDomainMessenger(MESSENGER).sendMessage( OTHER_GREETER, abi.encodeWithSelector(Greeter.setGreeting.selector, msg.sender, newGreeting), 100_000 ); } ``` ### The setGreeting function The `setGreeting` function is the function that actually sets the greeting. This function is called by the `CrossDomainMessenger` contract on the other chain. It checks explicitly that the function can only be called by the `CrossDomainMessenger` contract. It also checks that the `CrossChainMessenger` says that the message came from the `Greeter` contract on the other chain. Finally, it sets the greeting in the `greetings` mapping. ```solidity theme={null} function setGreeting(address sender, string calldata newGreeting) external { require(msg.sender == MESSENGER, "Only messenger"); require( ICrossDomainMessenger(MESSENGER).xDomainMessageSender() == OTHER_GREETER, "Only remote greeter" ); greetings[sender] = newGreeting; } ``` The two `require` statements in this function are important. Without them, anyone could call this function and set the greeting to whatever they want. You can follow a similar pattern in your own smart contracts. ## Conclusion You just learned how you can write Solidity contracts on Sepolia and OP Sepolia that can talk to each other. You can follow the same pattern to write contracts that can talk to each other on Ethereum and OP Stack. ```solidity theme={null} interface ICrossDomainMessenger { function sendMessage(address target, bytes calldata message, uint32 gasLimit) external; function xDomainMessageSender() external view returns (address); } ``` This sort of cross-chain communication is useful for a variety of reasons. For example, the [Standard Bridge](/app-developers/guides/bridging/standard-bridge) contracts use this same system to bridge ETH and ERC-20 tokens between Ethereum and OP Stack. One cool way to take advantage of cross-chain communication is to do most of your heavy lifting on OP Stack and then send a message to Ethereum only when you have important results to share. This way you can take advantage of the low gas costs on OP Stack while still being able to use Ethereum when you need it. # Deposit transactions Source: https://docs.optimism.io/app-developers/tutorials/bridging/deposit-transactions Learn about using deposit transactions with `supersim`. Supersim supports [deposit transactions](/op-stack/bridging/deposit-flow). It uses a very lightweight solution without the `op-node` derivation pipeline by listening directly to the `TransactionDeposited` events on the `OptimismPortal` contract and simply forwarding the transaction to the applicable L2. The execution engine used with Supersim must support the Optimism [deposit transaction type](https://specs.optimism.io/protocol/deposits.html#the-deposited-transaction-type). ## `OptimismPortal` When starting Supersim, the L1 contracts for each L2 chain are emitted as output to the console. The `L1CrossDomainMessenger`, `L1StandardBridge`, and `OptimismPortal` can be used to initiate deposits in the same manner as one would on a production network like OP Mainnet or Base. ```bash theme={null} Chain Configuration ----------------------- L1: Name: Local ChainID: 900 RPC: http://127.0.0.1:8545 LogPath: ... L2: Predeploy Contracts Spec ( https://specs.optimism.io/protocol/predeploys.html ) * Name: OPChainA ChainID: 901 RPC: http://127.0.0.1:9545 LogPath: ... L1 Contracts: - OptimismPortal: 0x37a418800d0c812A9dE83Bc80e993A6b76511B57 - L1CrossDomainMessenger: 0xcd712b03bc6424BF45cE6C29Fc90FFDece228F6E - L1StandardBridge: 0x8d515eb0e5F293B16B6bBCA8275c060bAe0056B0 ... ``` If running Supersim in fork mode, the production contracts will be used for each of the forked networks. ```bash theme={null} Chain Configuration ----------------------- L1: Name: mainnet ChainID: 1 RPC: http://127.0.0.1:8545 LogPath: ... L2: Predeploy Contracts Spec ( https://specs.optimism.io/protocol/predeploys.html ) * Name: op ChainID: 10 RPC: http://127.0.0.1:9545 LogPath: ... L1 Contracts: - OptimismPortal: 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed - L1CrossDomainMessenger: 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 - L1StandardBridge: 0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1 * Name: mode ChainID: 34443 RPC: http://127.0.0.1:9546 LogPath: ... L1 Contracts: - OptimismPortal: 0x8B34b14c7c7123459Cf3076b8Cb929BE097d0C07 - L1CrossDomainMessenger: 0x95bDCA6c8EdEB69C98Bd5bd17660BaCef1298A6f - L1StandardBridge: 0x735aDBbE72226BD52e818E7181953f42E3b0FF21 ... ``` ## Sample Deposit Flow We'll run through a sample deposit directly with the `OptimismPortal` using cast. ```bash theme={null} supersim ``` ```bash theme={null} ... * Name: OPChainA ChainID: 901 ... L1 Contracts: - OptimismPortal: 0x37a418800d0c812A9dE83Bc80e993A6b76511B57 ... ``` We'll be using the first pre-funded account to send this deposit of 1 ether ```bash theme={null} cast send 0x37a418800d0c812A9dE83Bc80e993A6b76511B57 --value 1ether --rpc-url http://localhost:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` ```bash theme={null} INFO [11-28|13:56:06.756] OptimismPortal#depositTransaction chain.id=901 l2TxHash=0x592d6e13016751332115df1fce59904176bfe447854196ed1b97ee00f14be469 ``` ## Next steps * See the [transaction guides](/app-developers/guides/transactions/estimates) for more detailed information. * Questions about Interop? Check out collection of [interop guides](/op-stack/interop/explainer) or check out this [OP Stack interop design video walk-thru](https://www.youtube.com/watch?v=FKc5RgjtGes). * For more info about how OP Stack interoperability works under the hood, [check out the specs](https://specs.optimism.io/interop/overview.html?utm_source=op-docs\&utm_medium=docs). # Replaying a failed deposit Source: https://docs.optimism.io/app-developers/tutorials/bridging/replay-failed-deposit Learn how deposit replays work by deliberately failing a deposit against a test contract on OP Sepolia and then replaying it with more gas, end to end. When a deposit transaction fails on L2 — usually because it ran out of gas or the L2 state didn't allow it to succeed — the message isn't lost. `L2CrossDomainMessenger` records it as a failed message, and you can replay it later, optionally with more gas. In this tutorial, you'll make a deposit fail on purpose against a test contract, then replay it successfully, so you can see the full failure-and-replay cycle end to end. For the concepts behind deposits and why replays are possible, see [Deposit flow](/op-stack/bridging/deposit-flow). ## Before you begin * [Foundry](https://book.getfoundry.sh/getting-started/installation) installed (this tutorial uses `cast`). * A test account private key, funded with a small amount of test ETH on both **Ethereum Sepolia** (L1) and **OP Sepolia** (L2). * An L1 (Ethereum Sepolia) RPC URL — e.g. a free [Infura](https://infura.io) key or another provider. **L1 vs L2 network clarification** This tutorial involves **two different networks**: * **L1**: Ethereum Sepolia testnet (`https://sepolia.infura.io/v3/YOUR_KEY`) * **L2**: OP Sepolia testnet (`https://sepolia.optimism.io`) You'll send transactions on L1 that trigger actions on L2. Make sure you're using the correct RPC URLs for each step. ## Trigger and replay a failed deposit To see how replays work, you can use [this contract on OP Sepolia](https://testnet-explorer.optimism.io/address/0xEF60cF6C6D0C1c755be104843bb72CDa3D778630#code). 1. Call `stopChanges`, using this Foundry command: ```sh theme={null} PRIV_KEY= export ETH_RPC_URL=https://sepolia.optimism.io GREETER=0xEF60cF6C6D0C1c755be104843bb72CDa3D778630 cast send --private-key $PRIV_KEY $GREETER "stopChanges()" ``` 2. Verify that `getStatus()` returns false, meaning changes are not allowed, and see the value of `greet()` using Foundry. Note that Foundry returns false as zero. ```sh theme={null} cast call $GREETER "greet()" | cast --to-ascii ; cast call $GREETER "getStatus()" ``` 3. Get the calldata. You can use this Foundry command: ```sh theme={null} cast calldata "setGreeting(string)" "testing" ``` Or just use this value: ``` 0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000774657374696e6700000000000000000000000000000000000000000000000000 ``` 4. Send a greeting change as a deposit from L1 (Ethereum Sepolia) to L2 (OP Sepolia). Use these commands: ```sh theme={null} # L1 = Ethereum Sepolia # Get a free Infura key at https://infura.io or use the public RPC below L1_RPC=https://sepolia.infura.io/v3/YOUR_INFURA_KEY L1XDM_ADDRESS=0x5086d1eef304eb5284a0f6720f79403b4e9be294 FUNC="sendMessage(address,bytes,uint32)" CALLDATA=`cast calldata "setGreeting(string)" "testing"` cast send --rpc-url $L1_RPC --private-key $PRIV_KEY $L1XDM_ADDRESS $FUNC $GREETER $CALLDATA 10000000 ``` The transaction will be successful on **L1 (Ethereum Sepolia)**, but then emit a fail event on **L2 (OP Sepolia)**. 5. The next step is to find the hash of the failed relay. There are several ways to do this: **Method A: Using Etherscan Internal Transactions** Look in [the internal transactions of the destination contract](https://testnet-explorer.optimism.io/address/0xEF60cF6C6D0C1c755be104843bb72CDa3D778630#internaltx), and select the latest one that appears as a failure. It should be a call to `L2CrossDomainMessenger` at address `0x420...007`. **Method B: Using Contract Events (if internal transactions aren't visible)** If you can't see internal transactions on Etherscan, check the [L2CrossDomainMessenger contract events](https://testnet-explorer.optimism.io/address/0x4200000000000000000000000000000000000007#events) and look for `FailedRelayedMessage` events with your contract address. **Method C: Using cast to query failed messages** ```sh theme={null} # First, you need the message hash. You can derive it from the L1 transaction, or check events L2XDM_ADDRESS=0x4200000000000000000000000000000000000007 # Replace MSG_HASH with the actual message hash from the FailedRelayedMessage event cast call $L2XDM_ADDRESS "failedMessages(bytes32)" $MSG_HASH ``` If the latest internal transaction is a success, it probably means your transaction hasn't relayed yet. Wait until it is, that may take a few minutes. 6. Get the transaction information using Foundry. **Wait for the failed relay transaction** Make sure you wait for the deposit to be processed on L2 and fail before proceeding. This can take 2-5 minutes. You should see a failed transaction in one of the methods from step 5. ```sh theme={null} TX_HASH= L2XDM_ADDRESS=0x4200000000000000000000000000000000000007 REPLAY_DATA=`cast tx $TX_HASH input` ``` 7. Call `startChanges()` to allow changes using this Foundry command: ```sh theme={null} cast send --private-key $PRIV_KEY $GREETER "startChanges()" ``` Don't do this prematurely If you call `startChanges()` too early, it will happen when the message is relayed to L2, and then the initial deposit will be successful and there will be no need to replay it. 8. Verify that `getStatus()` returns true, meaning changes are not allowed, and see the value of `greet()`. Foundry returns true as one. ```sh theme={null} cast call $GREETER "greet()" | cast --to-ascii ; cast call $GREETER "getStatus()" ``` 9. Now send the replay transaction. ```sh theme={null} cast send --private-key $PRIV_KEY --gas-limit 10000000 $L2XDM_ADDRESS $REPLAY_DATA ``` Why do we need to specify the gas limit? The gas estimation mechanism tries to find the minimum gas limit at which the transaction would be successful. However, `L2CrossDomainMessenger` does not revert when a replay fails due to low gas limit, it just emits a failure message. The gas estimation mechanism considers that a success. To get a gas estimate, you can use this command: ```sh theme={null} cast estimate --from 0x0000000000000000000000000000000000000001 $L2XDM_ADDRESS $REPLAY_DATA ``` That address is a special case in which the contract does revert. 10. Verify the greeting has changed: ```sh theme={null} cast call $GREETER "greet()" | cast --to-ascii ; cast call $GREETER "getStatus()" ``` ## Debugging To debug deposit transactions, you can ask the L2 cross domain messenger for the state of the transaction. 1. Look on Etherscan to see the `FailedRelayedMessage` event. Set `MSG_HASH` to that value. 2. To check if the message is listed as failed, run this: ```sh theme={null} cast call $L2XDM_ADDRESS "failedMessages(bytes32)" $MSG_HASH ``` To check if it is listed as successful, run this: ```sh theme={null} cast call $L2XDM_ADDRESS "successfulMessages(bytes32)" $MSG_HASH ``` ## Next steps * Read [Deposit flow](/op-stack/bridging/deposit-flow) to understand how deposits are processed across L1 and L2 under the hood. * Learn about [sending data between L1 and L2](/app-developers/guides/bridging/messaging) from your contracts. # Create an L2 token for the Standard Bridge Source: https://docs.optimism.io/app-developers/tutorials/bridging/standard-bridge-standard-token Learn how to create a standard or custom L2 representation of an L1 ERC-20 token that works with the Standard Bridge on an OP Stack chain. In this tutorial, you'll create an L2 representation of an L1 ERC-20 token that works with the Standard Bridge system on an OP Stack chain. This tutorial is meant for developers who already have an existing ERC-20 token on Ethereum and want to create a bridged representation of that token on layer 2. By the end, you'll have an L2 token contract deployed on OP Sepolia that the Standard Bridge can mint and burn. This tutorial does not cover the bridging itself: once your L2 token exists, follow [Bridging ERC-20 tokens with viem](./cross-dom-bridge-erc20) to move tokens between L1 and L2. The Standard Bridge supports two kinds of L2 tokens, and this tutorial covers both: * A **standard token** deployed through the [`OptimismMintableERC20Factory`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol). Tokens created by this factory contract are compatible with the Standard Bridge system and include basic logic for deposits, transfers, and withdrawals. Choose this path if you don't need any specialized logic in your L2 token. * A **custom token** that implements the [`IOptimismMintableERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/universal/IOptimismMintableERC20.sol) interface itself. A custom token allows you to do things like trigger extra logic whenever a token is deposited. Choose this path if you need specialized behavior like that. Both paths share the same setup and fork at the [Create an L2 ERC-20 token](#create-an-l2-erc-20-token) section, where each path has its own tab. The Standard Bridge **does not** support [**fee on transfer tokens**](https://github.com/d-xo/weird-erc20#fee-on-transfer) or [**rebasing tokens**](https://github.com/d-xo/weird-erc20#balance-modifications-outside-of-transfers-rebasingairdrops) because they can cause bridge accounting errors. ## About OptimismMintableERC20s The Standard Bridge system requires that L2 representations of L1 tokens implement the [`IOptimismMintableERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/universal/IOptimismMintableERC20.sol) interface. This interface is a superset of the standard ERC-20 interface and includes functions that allow the bridge to properly verify deposits/withdrawals and mint/burn tokens as needed. Your L2 token contract must implement this interface in order to be bridged using the Standard Bridge system. This tutorial will show you how to deploy a basic standardized ERC-20 token through the [`OptimismMintableERC20Factory`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol), or how to write a custom token that implements the interface itself. ## Dependencies * [cast](https://book.getfoundry.sh/getting-started/installation), used on the standard-token path to deploy through the factory * A web browser with a wallet extension, used on the custom-token path to deploy with [Remix](https://remix.ethereum.org) ## Get ETH on Sepolia and OP Sepolia This tutorial explains how to create a bridged ERC-20 token on OP Sepolia. You will need to get some ETH on both of these testnets. ## Get an L1 ERC-20 token address You will need an L1 ERC-20 token for this tutorial. If you already have an L1 ERC-20 token deployed on Sepolia, you can skip this step. Otherwise, you can use the testing token located at [`0x5589BB8228C07c4e15558875fAf2B859f678d129`](https://sepolia.etherscan.io/address/0x5589BB8228C07c4e15558875fAf2B859f678d129) that includes a `faucet()` function that can be used to mint tokens. ## Create an L2 ERC-20 token Once you have an L1 ERC-20 token, you can create a corresponding L2 ERC-20 token on OP Sepolia. Pick the tab that matches the kind of token you want to create. You can deploy your L2 ERC-20 token using the [`OptimismMintableERC20Factory`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol). All tokens created by the factory implement the `IOptimismMintableERC20` interface and are compatible with the Standard Bridge system. You need a private key in order to sign transactions. Set your private key as an environment variable with the `export` command. Make sure this private key corresponds to an address that has ETH on . Want to create a new wallet for this tutorial? If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) installed you can run `cast wallet new` in your terminal to create a new wallet and get the private key. ```bash theme={null} export TUTORIAL_PRIVATE_KEY=0x... ``` You'll need an RPC URL in order to connect to OP Sepolia. Set your RPC URL as an environment variable with the `export` command. ```bash theme={null} export TUTORIAL_RPC_URL=https://sepolia.optimism.io ``` You'll need to know the address of your L1 ERC-20 token in order to create a bridged representation of it on OP Sepolia. Set your L1 ERC-20 token address as an environment variable with the `export` command. ```bash theme={null} # Replace this with your L1 ERC-20 token if not using the testing token! export TUTORIAL_L1_ERC20_ADDRESS=0x5589BB8228C07c4e15558875fAf2B859f678d129 ``` You can now deploy your L2 ERC-20 token using the [`OptimismMintableERC20Factory`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol). Use the `cast` command to trigger the deployment function on the factory contract. This example command creates a token with the name "My Standard Demo Token" and the symbol "L2TKN". The resulting L2 ERC-20 token address is printed to the console. ```bash theme={null} cast send 0x4200000000000000000000000000000000000012 "createOptimismMintableERC20(address,string,string)" $TUTORIAL_L1_ERC20_ADDRESS "My Standard Demo Token" "L2TKN" --private-key $TUTORIAL_PRIVATE_KEY --rpc-url $TUTORIAL_RPC_URL --json | jq -r '.logs[0].topics[2]' | cast parse-bytes32-address ``` This path uses [Remix](https://remix.ethereum.org) so you can easily deploy a token without a framework like [Hardhat](https://hardhat.org) or [Foundry](https://getfoundry.sh). You can follow the same general process within your favorite framework if you prefer. In this section, you'll be creating an ERC-20 token that can be deposited but cannot be withdrawn. This is just one example of the endless ways in which you could customize your L2 token. You will need to add the OP Sepolia network to your wallet in order to follow this path. You can use [this website](https://chainid.link?network=op-sepolia) to connect your wallet to OP Sepolia. Navigate to [Remix](https://remix.ethereum.org) in your browser. Click the 📄 ("Create new file") button to create a new empty Solidity file. You can name this file whatever you'd like, for example `MyCustomL2Token.sol`. Copy the following example contract into your new file: ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity 0.8.20; // Import the standard ERC20 implementation from OpenZeppelin import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @title ILegacyMintableERC20 * @notice Legacy interface for the StandardL2ERC20 contract. */ interface ILegacyMintableERC20 { function mint(address _to, uint256 _amount) external; function burn(address _from, uint256 _amount) external; function l1Token() external view returns (address); function l2Bridge() external view returns (address); } /** * @title IOptimismMintableERC20 * @notice Interface for the OptimismMintableERC20 contract. */ interface IOptimismMintableERC20 { function remoteToken() external view returns (address); function bridge() external view returns (address); function mint(address _to, uint256 _amount) external; function burn(address _from, uint256 _amount) external; } /** * @title Simplified Semver for tutorial * @notice Simple contract to track semantic versioning */ contract Semver { string public version; // Simple function to convert uint to string for version numbers function toString(uint256 value) internal pure returns (string memory) { // This function handles numbers from 0 to 999 which is sufficient for versioning if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } constructor(uint256 major, uint256 minor, uint256 patch) { version = string(abi.encodePacked( toString(major), ".", toString(minor), ".", toString(patch) )); } } /** * @title MyCustomL2Token * @notice A custom L2 token based on OptimismMintableERC20 that can be deposited * from L1 to L2, but cannot be withdrawn from L2 to L1. */ contract MyCustomL2Token is IOptimismMintableERC20, ILegacyMintableERC20, ERC20, Semver { /// @notice Address of the corresponding token on the remote chain. address public immutable REMOTE_TOKEN; /// @notice Address of the StandardBridge on this network. address public immutable BRIDGE; /// @notice Emitted whenever tokens are minted for an account. /// @param account Address of the account tokens are being minted for. /// @param amount Amount of tokens minted. event Mint(address indexed account, uint256 amount); /// @notice Emitted whenever tokens are burned from an account. /// @param account Address of the account tokens are being burned from. /// @param amount Amount of tokens burned. event Burn(address indexed account, uint256 amount); /// @notice A modifier that only allows the bridge to call modifier onlyBridge() { require(msg.sender == BRIDGE, "MyCustomL2Token: only bridge can mint and burn"); _; } /// @param _bridge Address of the L2 standard bridge. /// @param _remoteToken Address of the corresponding L1 token. /// @param _name ERC20 name. /// @param _symbol ERC20 symbol. constructor( address _bridge, address _remoteToken, string memory _name, string memory _symbol ) ERC20(_name, _symbol) Semver(1, 0, 0) { REMOTE_TOKEN = _remoteToken; BRIDGE = _bridge; } /// @notice Allows the StandardBridge on this network to mint tokens. /// @param _to Address to mint tokens to. /// @param _amount Amount of tokens to mint. function mint( address _to, uint256 _amount ) external virtual override(IOptimismMintableERC20, ILegacyMintableERC20) onlyBridge { _mint(_to, _amount); emit Mint(_to, _amount); } /// @notice Burns tokens from an account. /// @dev This function always reverts to prevent withdrawals to L1. /// @param _from Address to burn tokens from. /// @param _amount Amount of tokens to burn. function burn( address _from, uint256 _amount ) external virtual override(IOptimismMintableERC20, ILegacyMintableERC20) onlyBridge { // Instead of calling _burn(_from, _amount), we revert // This makes it impossible to withdraw tokens back to L1 revert("MyCustomL2Token: withdrawals are not allowed"); // Note: The following line would normally execute but is unreachable // _burn(_from, _amount); // emit Burn(_from, _amount); } /// @notice ERC165 interface check function. /// @param _interfaceId Interface ID to check. /// @return Whether or not the interface is supported by this contract. function supportsInterface(bytes4 _interfaceId) external pure virtual returns (bool) { bytes4 iface1 = type(IERC165).interfaceId; // Interface corresponding to the legacy L2StandardERC20 bytes4 iface2 = type(ILegacyMintableERC20).interfaceId; // Interface corresponding to the updated OptimismMintableERC20 bytes4 iface3 = type(IOptimismMintableERC20).interfaceId; return _interfaceId == iface1 || _interfaceId == iface2 || _interfaceId == iface3; } /// @notice Legacy getter for the remote token. Use REMOTE_TOKEN going forward. function l1Token() public view override returns (address) { return REMOTE_TOKEN; } /// @notice Legacy getter for the bridge. Use BRIDGE going forward. function l2Bridge() public view override returns (address) { return BRIDGE; } /// @notice Getter for REMOTE_TOKEN. function remoteToken() public view override returns (address) { return REMOTE_TOKEN; } /// @notice Getter for BRIDGE. function bridge() public view override returns (address) { return BRIDGE; } } ``` Take a moment to review the example contract. It's closely based on the official [`OptimismMintableERC20`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol) contract with one key modification: The `burn` function has been modified to always revert, making it impossible to withdraw tokens back to L1. Since the bridge needs to burn tokens when users want to withdraw them to L1, this means that users will not be able to withdraw tokens from this contract. Here's the key part of the contract that prevents withdrawals: ```solidity theme={null} /// @notice Burns tokens from an account. /// @dev This function always reverts to prevent withdrawals to L1. /// @param _from Address to burn tokens from. /// @param _amount Amount of tokens to burn. function burn( address _from, uint256 _amount ) external virtual override(IOptimismMintableERC20, ILegacyMintableERC20) onlyBridge { // Instead of calling _burn(_from, _amount), we revert // This makes it impossible to withdraw tokens back to L1 revert("MyCustomL2Token: withdrawals are not allowed"); // Note: The following line would normally execute but is unreachable // _burn(_from, _amount); // emit Burn(_from, _amount); } ``` Save the file to automatically compile the contract. If you've disabled auto-compile, you'll need to manually compile the contract by clicking the "Solidity Compiler" tab (this looks like the letter "S") and press the blue "Compile" button. Make sure you're using Solidity compiler version 0.8.20, the exact version the example contract's `pragma solidity 0.8.20;` requires. Open the deployment tab (this looks like an Ethereum logo with an arrow pointing left). Make sure that your environment is set to "Injected Provider", your wallet is connected to OP Sepolia, and Remix has access to your wallet. Then, select the `MyCustomL2Token` contract from the deployment dropdown and deploy it with the following parameters: ```text theme={null} _bridge: "0x4200000000000000000000000000000000000010" // L2 Standard Bridge address _remoteToken: "" // Your L1 token address _name: "My Custom L2 Token" // Your token name _symbol: "MCL2T" // Your token symbol ``` Note: The L2 Standard Bridge address is a predefined address on all OP Stack chains, so it will be the same on OP Sepolia and OP Mainnet. ## Bridge some tokens Now that you have an L2 ERC-20 token, you can bridge some tokens from L1 to L2. Check out the tutorial on [Bridging ERC-20 tokens with viem](./cross-dom-bridge-erc20) to learn how to bridge your L1 ERC-20 to L2s using viem. If you deployed the custom example token from this tutorial, remember that the withdrawal step will *not* work for it: the example contract's `burn` function always reverts, which is exactly what that example was meant to demonstrate. ## Add to the Superchain Token List The [Superchain Token List](https://github.com/ethereum-optimism/ethereum-optimism.github.io#readme) is a common list of tokens deployed on chains within the Optimism Superchain. This list is used by services like the [Superchain Bridges UI](https://app.optimism.io/bridge?utm_source=op-docs\&utm_medium=docs). If you want your OP Mainnet token to be included in this list, take a look at the [review process and merge criteria](https://github.com/ethereum-optimism/ethereum-optimism.github.io#review-process-and-merge-criteria). # Deploy a contract to OP Sepolia Source: https://docs.optimism.io/app-developers/tutorials/deploy-a-contract Deploy your first smart contract to an OP Stack chain and interact with it using Foundry. This tutorial walks you through deploying your first smart contract to an OP Stack chain from scratch. You'll deploy a small `Greeter` contract to the OP Sepolia testnet with [Foundry](https://getfoundry.sh/), then read from and write to it from the command line. OP Stack chains are [EVM equivalent](/op-stack/protocol/differences), so the workflow here is the same one you'd use on Ethereum: the only OP-specific detail is the RPC endpoint and chain ID you point at. By the end you'll have a live contract on OP Sepolia and the commands to interact with any contract you deploy later. This tutorial uses the OP Sepolia testnet, so you won't spend real funds. The same steps work on any OP Stack chain — swap in that chain's RPC URL and fund your account on that network. ## Dependencies * [Foundry](https://book.getfoundry.sh/getting-started/installation) — installed in the first step below. * A terminal with `curl` available (preinstalled on macOS and most Linux distributions). ## Install Foundry Foundry is a toolkit for Ethereum development. This tutorial uses two of its command-line tools: `forge` (to compile and deploy) and `cast` (to send transactions and read state). ```bash theme={null} curl -L https://foundry.paradigm.xyz | bash ``` This installs `foundryup`, Foundry's version manager. Follow the on-screen instructions to add it to your `PATH` (you may need to open a new terminal). ```bash theme={null} foundryup ``` ### Verify the install Confirm `forge` and `cast` are available: ```bash theme={null} forge --version cast --version ``` Each command should print a version string. If the command isn't found, revisit the `PATH` instructions from `foundryup` and open a new terminal. ## Create a project and contract ```bash theme={null} mkdir first-contract cd first-contract forge init ``` `forge init` scaffolds a new project with `src/`, `test/`, and `script/` directories. Replace the contents of `src/Greeter.sol` with the following. This is a variation on [Hardhat's Greeter contract](https://github.com/matter-labs/hardhat-zksync/blob/main/examples/upgradable-example/contracts/Greeter.sol): it stores a greeting string, exposes it through `greet()`, and lets anyone update it through `setGreeting()`. ```solidity theme={null} //SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Greeter { string greeting; event SetGreeting( address indexed sender, // msg.sender string greeting ); function greet() public view returns (string memory) { return greeting; } function setGreeting(string memory _greeting) public { greeting = _greeting; emit SetGreeting(msg.sender, _greeting); } } ``` ```bash theme={null} forge build ``` ### Verify the build `forge build` should report a successful compilation and write artifacts to the `out/` directory. If compilation fails, check that `src/Greeter.sol` matches the code above exactly. ## Configure OP Sepolia and your account You need two things to deploy: an RPC endpoint for OP Sepolia and a private key to sign the deployment transaction. Create a fresh key for this tutorial rather than reusing a key that holds real funds. ```bash theme={null} cast wallet new ``` This prints an `Address` and a `Private key`. Save both somewhere safe. Export the OP Sepolia RPC URL and the private key you just created. These variables are read by the `forge` and `cast` commands in the rest of the tutorial. ```bash theme={null} export L2_RPC_URL=https://sepolia.optimism.io export PRIVATE_KEY=0x...your-private-key... export ACCOUNT_ADDRESS=$(cast wallet address --private-key $PRIVATE_KEY) ``` `https://sepolia.optimism.io` is a public, rate-limited endpoint suited to development and testing. For a full list of endpoints and production providers, see the [OP Stack RPC directory](/app-developers/reference/rpc-providers). For OP Sepolia's chain ID (`11155420`) and other network parameters, see [Connecting to OP Mainnet](/op-mainnet/network-information/connecting-to-op#op-sepolia). ## Fund your account Deploying a contract costs gas, so your account needs testnet ETH on OP Sepolia. Use the [Superchain Faucet](https://console.optimism.io/faucet?utm_source=op-docs\&utm_medium=docs) to send OP Sepolia ETH to your `ACCOUNT_ADDRESS`. ### Verify your balance Check that the faucet funds have arrived before deploying: ```bash theme={null} cast balance --ether $ACCOUNT_ADDRESS --rpc-url $L2_RPC_URL ``` The command prints your balance in ETH. Wait until it's greater than `0` before continuing. ## Deploy the contract Deploy `Greeter` to OP Sepolia and capture the resulting contract address. ```bash theme={null} CONTRACT_ADDRESS=$(forge create \ --rpc-url $L2_RPC_URL \ --private-key $PRIVATE_KEY \ Greeter \ --broadcast \ | awk '/Deployed to:/ {print $3}') echo "Deployed to: $CONTRACT_ADDRESS" ``` The `forge create` command compiles (if needed), signs, and broadcasts the deployment transaction. Its output includes a `Deployed to:` line; the `awk` command extracts that address into the `CONTRACT_ADDRESS` variable so you can reuse it in the next step. Run `forge create` on its own (without the `awk` pipe) if you want to see the full output — the deployer address, the new contract address, and the transaction hash. ### Verify the deployment Confirm the contract exists on-chain by fetching its bytecode: ```bash theme={null} cast code $CONTRACT_ADDRESS --rpc-url $L2_RPC_URL ``` A deployed contract returns a long hex string. If it returns `0x`, the deployment didn't land — re-check your balance and rerun the deploy step. ## Interact with the contract Now read from and write to your live contract using `cast`. ```bash theme={null} cast call --rpc-url $L2_RPC_URL $CONTRACT_ADDRESS "greet()" | cast --to-ascii ``` The greeting starts empty, so this returns an empty string. This sends a transaction that calls `setGreeting()`: ```bash theme={null} cast send \ --private-key $PRIVATE_KEY \ --rpc-url $L2_RPC_URL \ $CONTRACT_ADDRESS \ "setGreeting(string)" "Hello from OP Sepolia" ``` ```bash theme={null} cast call --rpc-url $L2_RPC_URL $CONTRACT_ADDRESS "greet()" | cast --to-ascii ``` This now returns `Hello from OP Sepolia`, confirming your write landed on-chain. ## View your contract on the block explorer Open an [OP Sepolia block explorer](/app-developers/tools-sdks/block-explorers) and search for your `CONTRACT_ADDRESS` to see the deployment transaction and the `setGreeting` call you just sent. Publishing (verifying) your contract's source code on the explorer is optional but recommended, because it lets anyone read and interact with the contract from the explorer UI. ## Next steps * Learn the broader conventions in [Building apps on OP Stack chains](/app-developers/guides/building-apps). * Understand [the differences between Ethereum and OP Stack chains](/op-stack/protocol/differences). * Try a cross-chain tutorial next, such as [bridging ERC-20 tokens](/app-developers/tutorials/bridging/cross-dom-bridge-erc20). **Running your app in production** A production application depends on infrastructure your team does not run: RPC endpoints that hold up under real traffic (the public endpoints are rate-limited and not built for production), bridges your users rely on, and a chain whose operator keeps sequencing, upgrades, and incident response going around the clock. These docs cover building and testing. If your application is growing toward dedicated blockspace of its own, [OP Enterprise](https://optimism.io/op-enterprise?utm_source=docs\&utm_medium=docs\&utm_campaign=op-enterprise) offers managed and supported paths to running a chain. These docs stay the reference for what you build either way. OP Enterprise is Optimism's managed offering. # First steps Source: https://docs.optimism.io/app-developers/tutorials/development/supersim/first-steps Take your first steps with Supersim. `supersim` allows testing multichain features **locally**. Previously, testing multichain features required complex docker setups or using a testnet. To see it in practice, this tutorial walks you through sending some ETH from the L1 to the L2. ## Deposit ETH from the L1 into the L2 (L1 to L2 message passing) Grab the balance of the sender account on L2: ```sh theme={null} cast balance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://127.0.0.1:9545 ``` You can use two different methods to complete this action: `OptimismPortal` or `L1StandardBridge`. #### First method: `OptimismPortal` * Send the Ether to `OptimismPortal` contract of the respective L2 (on chain 900) For chain 901, the contract is `0x37a418800d0c812A9dE83Bc80e993A6b76511B57`. * Initiate a bridge transaction on the L1: ```sh theme={null} cast send 0x37a418800d0c812A9dE83Bc80e993A6b76511B57 --value 0.1ether --rpc-url http://127.0.0.1:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` #### Second method: `L1StandardBridge` * Call `bridgeETH` function on the `L1StandardBridgeProxy` / `L1StandardBridge` contract of the respective L2 on L1 (chain 900) For chain 901, the contract is `0x8d515eb0e5F293B16B6bBCA8275c060bAe0056B0`. * Initiate a bridge transaction on the L1: ```sh theme={null} cast send 0x8d515eb0e5F293B16B6bBCA8275c060bAe0056B0 "bridgeETH(uint32 _minGasLimit, bytes calldata _extraData)" 50000 0x --value 0.1ether --rpc-url http://127.0.0.1:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` Verify that the ETH balance of the sender has increased on the L2: ```sh theme={null} cast balance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://127.0.0.1:9545 ``` ## Send an interoperable ERC20 token from chain 901 to 902 (L2 to L2 message passing) In a typical L2 to L2 cross-chain transfer, two transactions are required: 1. Send transaction on the source chain – This initiates the token transfer on Chain 901. 2. Relay message transaction on the destination chain – This relays the transfer details to Chain 902. To simplify this process, you can use the `--interop.autorelay` flag. This flag automatically triggers the relay message transaction once the initial send transaction is completed on the source chain, improving the developer experience by removing the need to manually send the relay message. ```sh theme={null} supersim --interop.autorelay ``` Run the following command to mint 1000 test ERC20 tokens to the recipient address: ```sh theme={null} cast send 0x420beeF000000000000000000000000000000001 "mint(address _to, uint256 _amount)" 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 1000 --rpc-url http://127.0.0.1:9545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` Send the tokens from Chain 901 to Chain 902 using the following command: ```sh theme={null} cast send 0x4200000000000000000000000000000000000028 "sendERC20(address _token, address _to, uint256 _amount, uint256 _chainId)" 0x420beeF000000000000000000000000000000001 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 1000 902 --rpc-url http://127.0.0.1:9545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` In a few seconds, you should see the RelayedMessage on chain 902: ```sh theme={null} # example INFO [08-30|14:30:14.698] SuperchainTokenBridge#RelayERC20 token=0x420beeF000000000000000000000000000000001 from=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 to=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 amount=1000 source=901 ``` Verify that the balance of the test ERC20 on chain 902 has increased: ```sh theme={null} cast balance --erc20 0x420beeF000000000000000000000000000000001 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://127.0.0.1:9546 ``` With the steps above, you've now successfully completed both an L1 to L2 ETH bridge and an L2 to L2 interoperable ERC20 token transfer, all done locally using `supersim`. This approach simplifies multichain testing, allowing you to focus on development without the need for complex setups or relying on external testnets. ## Next steps * Learn how to start Supersim in [vanilla (non-forked) mode](/app-developers/reference/tools/supersim/vanilla) or [forked mode](/app-developers/reference/tools/supersim/fork). * Explore the Supersim [included contracts](/app-developers/reference/tools/supersim/included-contracts) being used to help replicate the OP Stack environment. # Install Supersim Source: https://docs.optimism.io/app-developers/tutorials/development/supersim/installation Learn how to install Supersim and start it in vanilla mode. This page provides installation instructions for `supersim`. `supersim` requires `anvil`, which is installed alongside the Foundry toolchain. Follow the [Foundry toolchain](https://book.getfoundry.sh/getting-started/installation) guide for detailed instructions. Either download precompiled binaries or install using Homebrew: * Precompiled binaries: Download the executable for your platform from the [GitHub releases page](https://github.com/ethereum-optimism/supersim/releases). * Homebrew: Install [Homebrew](https://brew.sh/) (OS X, Linux), and then run: ```sh theme={null} brew tap ethereum-optimism/tap brew install supersim ``` Start `supersim` in vanilla mode by running: ```sh theme={null} supersim ``` Vanilla mode will start 3 chains, with the OP Stack contracts already deployed. * (1) L1 Chain * Chain 900 * (2) L2 Chains * Chain 901 * Chain 902 ## Next steps * Continue to the [First Steps](/app-developers/tutorials/development/supersim/first-steps) tutorial to try L1 to L2 message passing. * Explore [Supersim](/app-developers/tools-sdks/supersim) features, particularly in [vanilla mode](/app-developers/reference/tools/supersim/vanilla), which starts 3 chains (L1 and L2). # Making crosschain contract calls (ping pong) Source: https://docs.optimism.io/app-developers/tutorials/interoperability/contract-calls Understand how the CrossChainPingPong example contract uses the L2ToL2CrossDomainMessenger to make crosschain contract calls, and the design choices behind it. OP Stack interop is in active development. Some features may be experimental. This page explains the design of the `CrossChainPingPong.sol` example contract and how it integrates the `L2ToL2CrossDomainMessenger` to make crosschain contract calls. For more info, view the [source code](https://github.com/ethereum-optimism/supersim/blob/main/contracts/src/pingpong/CrossChainPingPong.sol). ## High level overview `CrossChainPingPong.sol` implements a cross-chain ping-pong game using the `L2ToL2CrossDomainMessenger`. * Players hit a **virtual ball** back and forth between allowed L2 chains. The game starts with a serve * from a designated start chain, and each hit increases the rally count. The contract tracks the last hitter's address, chain ID, and the current rally count. ### Diagram ```mermaid theme={null} sequenceDiagram participant Chain1 as Chain 1 participant Chain2 as Chain 2 Note over Chain1: 🚀 Game Starts (starting chain) Note over Chain1: 🏓 Hit Ball Chain1->>Chain2: 📤 Send PingPongBall {rallyCount: 1, lastHitter: Chain1} Chain1-->>Chain1: Emit BallSent event activate Chain2 Note over Chain2: 📥 Receive Ball Chain2-->>Chain2: Emit BallReceived event Note over Chain2: 🏓 Hit Ball Chain2->>Chain1: 📤 Send PingPongBall {rallyCount: 2, lastHitter: Chain2} Chain2-->>Chain2: Emit BallSent event deactivate Chain2 activate Chain1 Note over Chain1: 📥 Receive Ball Chain1-->>Chain1: Emit BallReceived event Note over Chain1,Chain2: Game continues... ``` ### Flow * Deployed on all participating chains * Utilizes CREATE2 with the same parameter, `_serverChainId`, resulting in the same address and initial state. * Call `hitBallTo` on the chain with the ball, specifying a destination chain. * Contract uses `L2ToL2CrossDomainMessenger` to send the ball data to the specified chain. * The reference to the ball is deleted from the serving chain. * `L2ToL2CrossDomainMessenger` on destination chain calls `receiveBall`. * Contract verifies the message sender and origin. * Ball data is stored, indicating its presence on this chain. * Any user on the chain currently holding the ball calls `hitBallTo` to send it to another chain. * Contract updates the `PingPongBall` data (increment rally count, update last hitter). * Process repeats from step 2. ## Walkthrough Here's an explanation of the functions in the contract, with a focus on how it interacts with `L2ToL2CrossChainMessenger`. ### Initialize contract state #### Constructor Setup ```solidity theme={null} constructor(uint256 _serverChainId) { if (block.chainid == _serverChainId) { ball = PingPongBall(1, block.chainid, msg.sender); } } ``` If the starting chain, initialize the ball allowing it to be hittable. #### Reliance on CREATE2 for cross chain consistency While not explicitly mentioned in the code, this contract's design implicitly assumes the use of CREATE2 for deployment. Here's why CREATE2 is crucial for this setup: * **Predictable Addresses**: CREATE2 enables deployment at the same address on all chains, crucial for cross-chain message verification: ```solidity theme={null} if (messenger.crossDomainMessageSender() != address(this)) revert InvalidCrossDomainSender(); ``` * **Self-referential Messaging**: The contract sends messages to itself on other chains: ```solidity theme={null} messenger.sendMessage(_toChainId, address(this), _message); ``` This requires `address(this)` to be consistent across chains. * **Initialization State Considerations**: The starting chain id is part of the initcode, meaning a deployment with a differing value would result in a different address via CREATE2. This is a nice feature as there's an implicit agreement on the starting chain from the address. Without CREATE2, you would need to: * Manually track contract addresses for each chain. * Implement a more complex initialization process to register contract addresses across chains. * Potentially redesign the security model that relies on address matching. ### Hit the ball `hitBallTo`: This function is used to hit the ball, when present, to another chain #### Hitting constraints ```solidity theme={null} function hitBallTo(uint256 _toChainId) public { if (ball.lastHitterAddress == address(0)) revert BallNotPresent(); if (_toChainId == block.chainid) revert InvalidDestination(); ... } ``` * The `ball` contract variable is populated on the chain, indicating its presence * The destination must be a different chain ### Define receiving handler ```solidity theme={null} modifier onlyCrossDomainCallback() { if (msg.sender != address(messenger)) revert CallerNotL2ToL2CrossDomainMessenger(); if (messenger.crossDomainMessageSender() != address(this)) revert InvalidCrossDomainSender(); _; } function receiveBall(PingPongBall memory _ball) onlyCrossDomainCallback() external { // Hold reference to the ball ball = _ball; emit BallReceived(messenger.crossDomainMessageSource(), block.chainid, _ball); } ``` * The handler simply stores reference to the received ball * The handler can only be invocable by the cross chain messenger * Since the contract is self-referential, the cross chain sender must be the same contract address ### Hit the ball cross-chain ```solidity theme={null} function hitBallTo(uint256 _toChainId) public { ... // Construct a new ball PingPongBall memory newBall = PingPongBall(ball.rallyCount + 1, block.chainid, msg.sender); // Delete current reference delete ball; // Send to the destination messenger.sendMessage(_toChainId, address(this), abi.encodeCall(this.receiveBall, (newBall))); emit BallSent(block.chainid, _toChainId, newBall); } ``` * Populate a new ball with updated properties * Delete reference to the current ball so it's no longer hittable * Invoke the contract on the destination chain matching the `receiveBall` handler defined in (2). ## Takeaways This is just one of many patterns to use the `L2ToL2CrossDomainMessenger` in your contract to power cross chain calls. Key points to remember: * **Simple Message Passing**: This design sends simple messages between identical contracts on different chains. Each message contains only the essential game state (rally count, last hitter). More complex systems might involve multiple contracts, intermediary relayers. * **Cross Chain Sender Verification**: Always verify the sender of cross-chain messages. This includes checking both the immediate caller (the messenger) and the original sender on the source chain. * **Cross Chain Contract Coordination**: This design uses CREATE2 for consistent contract addresses across chains, simplifying cross-chain verification. Alternative approaches include: * Beacon proxy patterns for upgradeable contracts * Post-deployment setup where contract addresses are specified after deployment # Deploying crosschain event composability (contests) Source: https://docs.optimism.io/app-developers/tutorials/interoperability/event-contests Understand how the Contests example composes with cross-chain events, using the CrossL2Inbox to consume events emitted by contracts on any OP Stack chain. OP Stack interop is in active development. Some features may be experimental. We showcase cross chain composability through the implementation of contests. Leveraging the same underlying mechanism powering [TicTacToe](/app-developers/tutorials/interoperability/event-reads), these contests can permissionlessly integrate with the events emitted by any contract on OP Stack chains. See the [frontend documentation](https://github.com/ethereum-optimism/supersim/tree/main/examples/contests) for how the contests UI is presented to the user. ## How it works Unlike [TicTacToe](/app-developers/tutorials/interoperability/event-reads) which is deployed on every participating chain, the contests are deployed on a single L2, behaving like an application-specific OP Stack chain rather than a horizontally scaled app. [Contests.sol](https://github.com/ethereum-optimism/supersim/blob/main/contracts/src/contests/Contests.sol) contains the implementation of the contests. We won't go into the details of the implementation here, but instead focus on how the contests can leverage cross chain event reading to compose with other contracts on OP Stack chains. The system predeploy that enables pulling in validated cross-chain events is the [CrossL2Inbox](https://specs.optimism.io/interop/predeploys.html?utm_source=op-docs\&utm_medium=docs#crossl2inbox). ```solidity theme={null} contract ICrossL2Inbox { function validateMessage(Identifier calldata _id, bytes32 _msgHash) external view; } ``` The two contest options are detailed below: [BlockHash contest](#blockhash-contest) and [TicTacToe contest](#tictactoe-contest). #### BlockHash contest With the existence of an event that emits the blockhash and height of a block, we can create a contest on the parity of the blockhash being even or odd. ```solidity theme={null} contract BlockHashEmitter { event BlockHash(uint256 blockHeight, bytes32 blockHash); function emitBlockHash(uint256 _blockHeight) external { bytes32 hash = blockhash(_blockHeight); require(hash != bytes32(0)); emit BlockHash(_blockHeight, hash); } } ``` Integrating this emitter into a contest is extremely simple. The `BlockHashContestFactory` is a simple factory that creates a new contest for a given chain and block height. #### TicTacToe contest A contest for TicTacToe is created on an accepted game between two players, captured by the emitted `AcceptedGame` event. When decoding the event, the game is uniquely identified by the chain it was created on, `chainId`, and the associated `gameId`. These identifying properties of the game are used to create the resolver for the game. ```solidity theme={null} contract TicTacToeContestFactory { Contests public contests; TicTacToe public tictactoe; function newContest(Identifier calldata _id, bytes calldata _data) public payable { // Validate Log require(_id.origin == address(tictactoe), "not an event from the TicTacToe contract"); CrossL2Inbox(Predeploys.CROSS_L2_INBOX).validateMessage(_id, keccak256(_data)); bytes32 selector = abi.decode(_data[:32], (bytes32)); require(selector == TicTacToe.AcceptedGame.selector, "incorrect event"); // Decode the event data (uint256 chainId, uint256 gameId, address creator,) = abi.decode(_data[32:], (uint256, uint256, address, address)); IContestResolver resolver = new TicTacToeGameResolver(contests, tictactoe, chainId, gameId, creator); contests.newContest{ value: msg.value }(resolver, msg.sender); } } ``` A contest is identified by and has its outcome determined by the `IContestResolver` instance. The resolver starts in the `UNDECIDED` state, updated into `YES` or `NO` when resolving itself with the contest. ```solidity theme={null} enum ContestOutcome { UNDECIDED, YES, NO } interface IContestResolver { function outcome() external returns (ContestOutcome); } ``` #### Resolve BlockHash contest When live, **anyone** can resolve the BlockHash contest by simply providing the right `BlockHash` event to the deployed resolver. ```solidity theme={null} contract BlockHashContestFactory { Contests public contests; BlockHashEmitter public emitter; // Same emitter deployed on every chain function newContest(uint256 _chainId, uint256 _blockNumber) public payable { IContestResolver resolver = new BlockHashResolver(contests, emitter, _chainId, _blockNumber); contests.newContest{ value: msg.value }(resolver, msg.sender); } } contract BlockHashResolver is IContestResolver { Contests public contests; ContestOutcome public outcome; BlockHashEmitter public emitter; // The target chain & block height uint256 public chainId; uint256 public blockNumber; function resolve(Identifier calldata _id, bytes calldata _data) external { require(outcome == ContestOutcome.UNDECIDED); // Validate Log require(_id.origin == address(emitter), "not an event from the emitter"); require(_id.chainId == chainId, "must match target chain"); CrossL2Inbox(Predeploys.CROSS_L2_INBOX).validateMessage(_id, keccak256(_data)); bytes32 selector = abi.decode(_data[:32], (bytes32)); require(selector == BlockHashEmitter.BlockHash.selector, "incorrect event"); // Event should correspond to the right contest uint256 dataBlockNumber = abi.decode(_data[32:64], (uint256)); require(dataBlockNumber == blockNumber, "must match target block height"); // Resolve the contest (yes if odd, no if even) bytes32 blockHash = abi.decode(_data[64:], (bytes32)); outcome = uint256(blockHash) % 2 != 0 ? ContestOutcome.YES : ContestOutcome.NO; contests.resolveContest(this); } } ``` #### Resolve TicTacToe contest When live, **anyone** can resolve the TicTacToe contest by providing the `GameWon` or `GameDraw` event of the associated game from the TicTacToe contract. ```solidity theme={null} contract TicTacToeGameResolver is IContestResolver { Contests public contests; ContestOutcome public outcome; TicTacToe public tictactoe; // @notice Game for this resolver Game public game; constructor(Contests _contest, TicTacToe _tictactoe, uint256 _chainId, uint256 _gameId, address _creator) { contests = _contest; tictactoe = _tictactoe; game = Game({chainId: _chainId, gameId: _gameId, creator: _creator}); outcome = ContestOutcome.UNDECIDED; } // @notice resolve this game by providing the game ending event function resolve(Identifier calldata _id, bytes calldata _data) external { // Validate Log require(_id.origin == address(tictactoe)); CrossL2Inbox(Predeploys.CROSS_L2_INBOX).validateMessage(_id, keccak256(_data)); // Ensure this is a finalizing event bytes32 selector = abi.decode(_data[:32], (bytes32)); require(selector == TicTacToe.GameWon.selector || selector == TicTacToe.GameDraw.selector, "event not a game outcome"); // Event should correspond to the right game (uint256 _chainId, uint256 gameId, address winner,,) = abi.decode(_data[32:], (uint256, uint256, address, uint8, uint8)); require(_chainId == game.chainId && gameId == game.gameId); // Resolve based on if the creator has won (non-draw) outcome = winner == game.creator && selector != TicTacToe.GameDraw.selector ? ContestOutcome.YES : ContestOutcome.NO; contests.resolveContest(this); } } ``` ## Takeaways * Leveraging superchain interop, contracts in the superchain can compose with each other in a similar fashion to how they would on a single chain. No restrictions are placed on the kinds of events a contract can consume via the `CrossL2Inbox`. * In this example, the `BlockHashContestFactory` and `TicTacToeContestFactory` can be seen as just starting points for the `Contests` app chain. As more contracts and apps are created in the superchain, developers can compose with them in a similar fashion without needing to change the `Contests` contract at all. # Making cross-chain event reads (tic-tac-toe) Source: https://docs.optimism.io/app-developers/tutorials/interoperability/event-reads Understand how a horizontally scalable TicTacToe implementation uses CrossL2Inbox event reads to coordinate gameplay across interop chains. OP Stack interop is in active development. Some features may be experimental. This page explains a horizontally scalable implementation of TicTacToe. This [implementation](https://github.com/ethereum-optimism/supersim/blob/main/contracts/src/tictactoe/TicTacToe.sol) allows players to play each other from any chain without cross-chain calls, instead relying on cross-chain event reading. Since OP Stack interop can allow for event reading with a 1-block latency, the experience is the **same as a single-chain implementation**. Check out the [frontend documentation](https://github.com/ethereum-optimism/supersim/tree/main/examples/tictactoe) to see how the game UI is presented to the player. ## How it works We use events to define the ordering of a game with players only maintaining a local view. By default, a chain is also a part of its own interoperable dependency set, which means players on the same chain can also play each other **with no code changes**! The system predeploy that enables pulling in validated cross-chain events is the [CrossL2Inbox](https://specs.optimism.io/interop/predeploys.html?utm_source=op-docs\&utm_medium=docs#crossl2inbox). ```solidity theme={null} contract ICrossL2Inbox { function validateMessage(Identifier calldata _id, bytes32 _msgHash) external view; } ``` This contract relies on a **CREATE2** deployment to ensure a consistent address across all chains, used to assert the origin of the pulled in game event. A game is uniquely identified by the chain it was started from with a unique nonce. This identifier is included in all event fields such that each player can uniquely reference it locally. To start a game, a player invokes `newGame` which broadcasts a `NewGame` event that any opponent **on any chain** can react to. ```solidity theme={null} event NewGame(uint256 chainId, uint256 gameId, address player); function newGame() external { emit NewGame(block.chainid, nextGameId, msg.sender); nextGameId++; } ``` When a `NewGame` event is observed, any player can declare their intent to play via `acceptGame`, referencing the `NewGame` event. An `AcceptedGame` event is emitted to signal to the creator that a game is ready to begin. ```solidity theme={null} event AcceptedGame(uint256 chainId, uint256 gameId, address opponent, address player); function acceptGame(ICrossL2Inbox.Identifier calldata _newGameId, bytes calldata _newGameData) external { if (_newGameId.origin != address(this)) revert IdOriginNotTicTacToe(); ICrossL2Inbox(Predeploys.CROSS_L2_INBOX).validateMessage(_newGameId, keccak256(_newGameData)); bytes32 selector = abi.decode(_newGameData[:32], (bytes32)); if (selector != NewGame.selector) revert DataNotNewGame(); ... emit AcceptedGame(chainId, gameId, game.opponent, game.player); } ``` To prepare for the game, the event data is decoded and a local view of this game is stored. ```solidity theme={null} (uint256 chainId, uint256 gameId, address opponent) = abi.decode(_newGameData[32:], (uint256, uint256, address)); if (opponent == msg.sender) revert SenderIsOpponent(); // Record Game Metadata (no moves) Game storage game = games[chainId][gameId][msg.sender]; game.player = msg.sender; game.opponent = opponent; game.gameId = gameId; game.lastOpponentId = _newGameId; game.movesLeft = 9; emit AcceptedGame(chainId, gameId, game.opponent, game.player); ``` As `AcceptedGame` events are emitted, the player must pick one opponent to play. The opponent's `AcceptedGame` event is used to instantiate the game and play the starting move via the `MovePlayed` event. ```solidity theme={null} event MovePlayed(uint256 chainId, uint256 gameId, address player, uint8 _x, uint8 _y); function startGame(ICrossL2Inbox.Identifier calldata _acceptedGameId, bytes calldata _acceptedGameData, uint8 _x, uint8 _y) external { if (_acceptedGameId.origin != address(this)) revert IdOriginNotTicTacToe(); ICrossL2Inbox(Predeploys.CROSS_L2_INBOX).validateMessage(_acceptedGameId, keccak256(_acceptedGameData)); bytes32 selector = abi.decode(_acceptedGameData[:32], (bytes32)); if (selector != AcceptedGame.selector) revert DataNotAcceptedGame(); ... emit MovePlayed(chainId, gameId, game.player, _x, _y); ``` The event fields contain the information required to perform the necessary validation. * The game identifier for lookup * The caller is the appropriate player * The player is accepting from the same starting chain ```solidity theme={null} (uint256 chainId, uint256 gameId, address player, address opponent) = // player, opponent swapped in local view abi.decode(_acceptedGameData[32:], (uint256, uint256, address, address)); // The accepted game was started from this chain, from the sender if (chainId != block.chainid) revert GameChainMismatch(); if (msg.sender != player) revert SenderNotPlayer(); // Game has not already been started with an opponent. Game storage game = games[chainId][gameId][msg.sender]; if (game.opponent != address(0)) revert GameStarted(); // Store local view of this game ... // Locally record the move by the player with 1 game.moves[_x][_y] = 1; game.lastOpponentId = _acceptedGameId; emit MovePlayed(chainId, gameId, game.player, _x, _y); ``` Once a game is started, players can continually make moves by invoking `makeMove`, reacting to a `MovePlayed` event of their opponent. ```solidity theme={null} function makeMove(ICrossL2Inbox.Identifier calldata _movePlayedId, bytes calldata _movePlayedData, uint8 _x, uint8 _y) external { if (_movePlayedId.origin != address(this)) revert IdOriginNotTicTacToe(); ICrossL2Inbox(Predeploys.CROSS_L2_INBOX).validateMessage(_movePlayedId, keccak256(_movePlayedData)); bytes32 selector = abi.decode(_movePlayedData[:32], (bytes32)); if (selector != MovePlayed.selector) revert DataNotMovePlayed(); } ``` Similar to `acceptGame`, validation is performed and the move of their opponent is first locally recorded. * The game identifier for lookup * The caller is the player for this game * The opponent event corresponds to the same game * Ordering is enforced by ensuring that the supplied event is always forward progressing. ```solidity theme={null} (uint256 chainId, uint256 gameId,, uint8 oppX, uint8 oppY) = abi.decode(_movePlayedData[32:], (uint256, uint256, address, uint8, uint8)); // Game was instantiated for this player & the move is for the same game Game storage game = games[chainId][gameId][msg.sender]; if (game.player != msg.sender) revert GameNotExists(); if (game.gameId != gameId) revert GameNotExists(); // The move played event is forward progressing from the last observed event if (_movePlayedId.chainId != game.lastOpponentId.chainId) revert IdChainMismatch(); if (_movePlayedId.blockNumber <= game.lastOpponentId.blockNumber) revert MoveNotForwardProgressing(); game.lastOpponentId = _movePlayedId; // Mark the opponents move game.moves[oppX][oppY] = 2; game.movesLeft--; ``` When a move is played we check if the game has been drawn or won, determining the subsequent event to emit. The `makeMove` function is only callable when an opponent has a new `MovePlayed` event. Therefore, if the game is won or drawn, it cannot be progressed any further by the opponent. ```solidity theme={null} // Make the players move game.moves[_x][_y] = 1; game.movesLeft--; // Determine the status of the game if (_isGameWon(game)) { emit GameWon(chainId, gameId, game.player, _x, _y); } else if (game.movesLeft == 0) { emit GameDraw(chainId, gameId, game.player, _x, _y); } else { emit MovePlayed(chainId, gameId, game.player, _x, _y); } ``` ## Takeaways Leveraging superchain interop, we can build new types of horizontally scalable contracts that do not rely on hub/spoke messaging with relayers. * As new chains are added to the superchain, this contract can be installed by anyone and immediately playable with no necessary code changes. The frontend simply needs to react the addition of a new chain. * The concept of a "chain" can be completely abstracted away from the user. When connecting their wallet, the frontend can simply pick the chain which the user has funds on with the lowest gas fees. * Event reading enables a new level of composability for cross-chain interactions. Imagine [contests](/app-developers/tutorials/interoperability/event-contests) contract that resolves based on the outcome of a TicTacToe game via the `GameWon` or `GameLost` event without the need for a trusted oracle, nor permission or native integration with the TicTacToe contract. # Relay transactions manually Source: https://docs.optimism.io/app-developers/tutorials/interoperability/manual-relay Learn to relay transactions directly by sending the correct transaction. OP Stack interop is in active development. Some features may be experimental. Messages are relayed automatically in the interop devnet. ## Overview Learn to relay transactions directly by sending the correct transaction. **Prerequisite technical knowledge** * Familiarity with blockchain concepts * Familiarity with [Foundry](https://book.getfoundry.sh/getting-started/installation), especially `cast` **What you'll learn** * How to use `cast` to relay transactions when autorelay does not work * How to relay transactions using JavaScript **Development environment requirements** * Unix-like operating system (Linux, macOS, or WSL for Windows) * Node.js version 16 or higher * Git for version control * Supersim environment configured and running * Foundry tools installed (forge, cast, anvil) ### What you'll build * A program to relay messages using [the JavaScript library](https://www.npmjs.com/package/@eth-optimism/viem) * A shell script to relay messages using [`cast`](https://book.getfoundry.sh/cast/) ## Setup These steps are necessary to run the tutorial, regardless of whether you are using `cast` or the JavaScript API. This exercise needs to be done on Supersim.\ You cannot use the devnets because you cannot disable autorelay on them. 1. Follow [Install Supersim](/app-developers/tutorials/development/supersim/installation). 2. Run Supersim *without* `--interop.relay`. ```sh theme={null} ./supersim ``` The results of this step are similar to what the [message passing tutorial](/app-developers/tutorials/interoperability/message-passing) would produce if you did not have autorelay on. Execute this script: ```sh theme={null} #! /bin/sh # full shell script preserved here... # (Greeter.sol, GreetingSender.sol, sendAndRelay.sh setup) # ... ``` This script installs `Greeter.sol` on chain B and `GreetingSender.sol` on chain A.\ These smart contracts let us send a message from chain A that needs to be relayed to chain B. Then, the script creates `./manual-relay/sendAndRelay.sh` to manually relay a message from chain A to chain B.\ That script is [explained below](#manual-relay-using-cast). Finally, this script writes out some parameter setting lines that should be executed on the main shell before you continue.\ With a fresh Supersim running, these should be: ```sh theme={null} GREETER_A_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3 GREETER_B_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3 PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` ## Manual relay using the API Use a [Node](https://nodejs.org/en) project. 1. Initialize a new Node project. ```sh theme={null} mkdir -p manual-relay/offchain cd manual-relay/offchain npm init -y npm install --save-dev viem @eth-optimism/viem mkdir src ``` 2. Export environment variables: ```sh theme={null} export GREETER_A_ADDRESS GREETER_B_ADDRESS PRIVATE_KEY ``` Create a file `manual-relay.mjs` with: ```javascript theme={null} import { createWalletClient, http, publicActions, getContract, } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { supersimL2A, supersimL2B } from '@eth-optimism/viem/chains' import { walletActionsL2, publicActionsL2 } from '@eth-optimism/viem' import { readFileSync } from 'fs'; const greeterData = JSON.parse(readFileSync('../onchain/out/Greeter.sol/Greeter.json')) const greetingSenderData = JSON.parse(readFileSync('../onchain/out/Greeter.sol/Greeter.json')) const account = privateKeyToAccount(process.env.PRIVATE_KEY) const walletA = createWalletClient({ chain: supersimL2A, transport: http(), account }).extend(publicActions) .extend(publicActionsL2()) // .extend(walletActionsL2()) const walletB = createWalletClient({ chain: supersimL2B, transport: http(), account }).extend(publicActions) // .extend(publicActionsL2()) .extend(walletActionsL2()) const greeter = getContract({ address: process.env.GREETER_B_ADDRESS, abi: greeterData.abi, client: walletB }) const greetingSender = getContract({ address: process.env.GREETER_A_ADDRESS, abi: greetingSenderData.abi, client: walletA }) const txnBHash = await greeter.write.setGreeting( ["Greeting directly to chain B"]) await walletB.waitForTransactionReceipt({hash: txnBHash}) const greeting1 = await greeter.read.greet() console.log(`Chain B Greeting: ${greeting1}`) const txnAHash = await greetingSender.write.setGreeting( ["Greeting through chain A"]) const receiptA = await walletA.waitForTransactionReceipt({hash: txnAHash}) const greeting2 = await greeter.read.greet() console.log(`Greeting before the relay transaction: ${greeting2}`) const sentMessages = await walletA.interop.getCrossDomainMessages({ logs: receiptA.logs, }) const sentMessage = sentMessages[0] // We only sent 1 message const relayMessageParams = await walletA.interop.buildExecutingMessage({ log: sentMessage.log, }) const relayMsgTxnHash = await walletB.interop.relayCrossDomainMessage(relayMessageParams) const receiptRelay = await walletB.waitForTransactionReceipt({ hash: relayMsgTxnHash, }) const greeting3 = await greeter.read.greet() console.log(`Greeting after the relay transaction: ${greeting3}`) ``` ```javascript theme={null} import { supersimL2A, supersimL2B } from '@eth-optimism/viem/chains' import { walletActionsL2, publicActionsL2 } from '@eth-optimism/viem' ``` Run JavaScript program: ```sh theme={null} node manual-relay.mjs ``` To see what messages were relayed by a specific transaction: ```javascript theme={null} import { decodeRelayedL2ToL2Messages } from '@eth-optimism/viem' const decodedRelays = decodeRelayedL2ToL2Messages({ receipt: receiptRelay }) console.log(decodedRelays) console.log(decodedRelays.successfulMessages[0].log) ``` ## Manual relay using `cast` You can see an example of how to manually relay using `cast` in `manual-relay/sendAndRelay.sh`.\ It is somewhat complicated, so the setup creates one that is tailored to your environment. Run the script: ```sh theme={null} ./manual-relay/sendAndRelay.sh ``` Here is the detailed explanation: 1. Configuration parameters ```sh theme={null} #! /bin/sh PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 USER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 URL_CHAIN_A=http://localhost:9545 URL_CHAIN_B=http://localhost:9546 GREETER_A_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3 GREETER_B_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3 CHAIN_ID_B=902 ``` This is the configuration. The greeter addresses are identical because the nonce for the user address has an identical nonce on both chains. 2. Send a message that needs to be relayed ```sh theme={null} cast send -q --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A $$" ``` Send a message from chain A to chain B. The `$$` is the process ID, so if you rerun the script you'll see that the information changes. 3. Find the log entry to relay ```sh theme={null} cast logs "SentMessage(uint256,address,uint256,address,bytes)" --rpc-url $URL_CHAIN_A | tail -14 > log-entry ``` Whenever `L2ToL2CrossDomainMessenger` sends a message to a different blockchain, it emits a [`SendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L83-L91) event. Extract only the latest `SendMessage` event from the logs. ```yaml theme={null} - address: 0x4200000000000000000000000000000000000023 blockHash: 0xcd0be97ffb41694faf3a172ac612a23f224afc1bfecd7cb737a7a464cf5d133e blockNumber: 426 data: 0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064a41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001948656c6c6f2066726f6d20636861696e2041203131333030370000000000000000000000000000000000000000000000000000000000000000000000 logIndex: 0 removed: false topics: [ 0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320 0x0000000000000000000000000000000000000000000000000000000000000386 0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3 0x0000000000000000000000000000000000000000000000000000000000000000 ] transactionHash: 0x1d6f2e5e2c8f3eb055e95741380ca36492f784b9782848b66b66c65c5937ff3a transactionIndex: 0 ``` 4. Manipulate the log entry to obtain information ```sh theme={null} TOPICS=`cat log-entry | grep -A4 topics | awk '{print $1}' | tail -4 | sed 's/0x//'` TOPICS=`echo $TOPICS | sed 's/ //g'` ``` Consolidate the log topics into a single hex string. ```sh theme={null} ORIGIN=0x4200000000000000000000000000000000000023 BLOCK_NUMBER=`cat log-entry | awk '/blockNumber/ {print $2}'` LOG_INDEX=`cat log-entry | awk '/logIndex/ {print $2}'` TIMESTAMP=`cast block $BLOCK_NUMBER --rpc-url $URL_CHAIN_A | awk '/timestamp/ {print $2}'` CHAIN_ID_A=`cast chain-id --rpc-url $URL_CHAIN_A` SENT_MESSAGE=`cat log-entry | awk '/data/ {print $2}'` ``` Read additional fields from the log entry. ```sh theme={null} LOG_ENTRY=0x`echo $TOPICS$SENT_MESSAGE | sed 's/0x//'` ``` Consolidate the entire log entry. 5. Create the access list for the executing message ```sh theme={null} RPC_PARAMS=$(cat < OP Stack interop is in active development. Some features may be experimental. ## Overview This tutorial demonstrates how to implement cross-chain communication within the OP Stack ecosystem. You'll build a complete message passing system that enables different chains to interact with each other using the `L2ToL2CrossDomainMessenger` contract. **Prerequisite technical knowledge** * Intermediate Solidity programming * Basic TypeScript knowledge * Understanding of smart contract development * Familiarity with blockchain concepts **What you'll learn** * How to deploy contracts across different chains * How to implement cross-chain message passing * How to handle sender verification across chains * How to relay messages manually between chains **Development environment** * Unix-like operating system (Linux, macOS, or WSL for Windows) * Node.js version 16 or higher * Git for version control **Required tools** The tutorial uses these primary tools: * Foundry: For smart contract development * Supersim: For local blockchain simulation (optional) * TypeScript: For offchain code (for relaying messages manually) * Viem: For interactions with the chain from the offchain app ### What You'll Build * A `Greeter` contract that stores and updates a greeting * A `GreetingSender` contract that sends cross-chain messages to update the greeting * A TypeScript application to relay messages between chains This tutorial provides step-by-step instructions for implementing cross-chain messaging. For a conceptual overview, see the [Message Passing Explainer](/app-developers/guides/interoperability/message-passing). In this tutorial, you will learn how to use the [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol) contract to pass messages between interoperable blockchains. ## Setting up your development environment * Foundry for smart contract development (required in all cases) * Supersim for local blockchain simulation (optional) ```sh theme={null} forge --version ./supersim --version ``` ## Implementing onchain message passing (in Solidity) The implementation consists of three main components: 1. **Greeter Contract**: Deployed on `Chain B`, receives and stores messages. 2. **GreetingSender Contract**: Deployed on `Chain A`, initiates cross-chain messages. 1) If you are using [Supersim](/app-developers/tools-sdks/supersim), go to the directory where Supersim is installed and start it with autorelay. ```sh theme={null} ./supersim --interop.autorelay ``` If you are using [the devnets](/app-developers/guides/building-apps), just skip this step. Supersim creates three `anvil` blockchains: | Role | ChainID | RPC URL | | -------- | ------: | ---------------------------------------------- | | L1 | 900 | [http://127.0.0.1:8545](http://127.0.0.1:8545) | | OPChainA | 901 | [http://127.0.0.1:9545](http://127.0.0.1:9545) | | OPChainB | 902 | [http://127.0.0.1:9546](http://127.0.0.1:9546) | These are the three networks involved in the devnet: | Role | ChainID | RPC URL | | ------------ | --------: | -------------------------------------------------------------------------------- | | L1 (Sepolia) | 11155111 | [https://eth-sepolia.public.blastapi.io](https://eth-sepolia.public.blastapi.io) | | ChainA | 420120000 | [https://interop-alpha-0.optimism.io](https://interop-alpha-0.optimism.io) | | ChainB | 420120001 | [https://interop-alpha-1.optimism.io](https://interop-alpha-1.optimism.io) | 2) In a separate shell, store the configuration in environment variables. Set these parameters for Supersim. ```sh theme={null} PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 USER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 URL_CHAIN_A=http://127.0.0.1:9545 URL_CHAIN_B=http://127.0.0.1:9546 INTEROP_BRIDGE=0x4200000000000000000000000000000000000028 ``` For Devnet, specify in `PRIVATE_KEY` the private key you used for the setup script and then these parameters. ```sh theme={null} USER_ADDRESS=`cast wallet address --private-key $PRIVATE_KEY` URL_CHAIN_A=https://interop-alpha-0.optimism.io URL_CHAIN_B=https://interop-alpha-1.optimism.io INTEROP_BRIDGE=0x4200000000000000000000000000000000000028 ``` To verify that the chains are running, check the balance of `$USER_ADDRESS`. ```sh theme={null} cast balance --ether $USER_ADDRESS --rpc-url $URL_CHAIN_A cast balance --ether $USER_ADDRESS --rpc-url $URL_CHAIN_B ``` 1. Create a new Foundry project. ```sh theme={null} mkdir onchain-code cd onchain-code forge init ``` 2. In `src/Greeter.sol` put this file. This is a variation on [Hardhat's Greeter contract](https://github.com/matter-labs/hardhat-zksync/blob/main/examples/upgradable-example/contracts/Greeter.sol). ```solidity theme={null} //SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Greeter { string greeting; event SetGreeting( address indexed sender, // msg.sender string greeting ); function greet() public view returns (string memory) { return greeting; } function setGreeting(string memory _greeting) public { greeting = _greeting; emit SetGreeting(msg.sender, _greeting); } } ``` 3. Deploy the `Greeter` contract to Chain B and store the resulting contract address in the `GREETER_B_ADDRESS` environment variable. ```sh theme={null} GREETER_B_ADDRESS=`forge create --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY Greeter --broadcast | awk '/Deployed to:/ {print $3}'` ``` The command that deploys the contract is: ```sh theme={null} forge create --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY Greeter --broadcast ``` The command output gives us the deployer address, the address of the new contract, and the transaction hash: ``` Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 Deployed to: 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 Transaction hash: 0xf155d360ec70ee10fe0e02d99c16fa5d6dc2a0e79b005fec6cbf7925ff547dbf ``` The [`awk`](https://www.tutorialspoint.com/awk/index.htm) command looks for the line that has `Deployed to:` and writes the third word in that line, which is the address. ```sh theme={null} awk '/Deployed to:/ {print $3}' ``` Finally, in UNIX (including Linux and macOS) when the command line includes backticks, the shell executes the code between the backticks and puts the output, in this case the contract address, in the command. So we get. ```sh theme={null} GREETER_B_ADDRESS= ``` Run these commands to verify the contract works. The first and third commands retrieve the current greeting, while the second command updates it. ```sh theme={null} cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii cast send --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "setGreeting(string)" Hello$$ cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii ``` 4. Install the Optimism Solidity libraries into the project. ```sh theme={null} cd lib npm install @eth-optimism/contracts-bedrock cd .. echo @eth-optimism/=lib/node_modules/@eth-optimism/ >> remappings.txt ``` 5. Create `src/GreetingSender.sol`. ```solidity theme={null} //SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Predeploys } from "@eth-optimism/contracts-bedrock/src/libraries/Predeploys.sol"; import { IL2ToL2CrossDomainMessenger } from "@eth-optimism/contracts-bedrock/src/L2/IL2ToL2CrossDomainMessenger.sol"; import { Greeter } from "src/Greeter.sol"; contract GreetingSender { IL2ToL2CrossDomainMessenger public immutable messenger = IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER); address immutable greeterAddress; uint256 immutable greeterChainId; constructor(address _greeterAddress, uint256 _greeterChainId) { greeterAddress = _greeterAddress; greeterChainId = _greeterChainId; } function setGreeting(string calldata greeting) public { bytes memory message = abi.encodeCall( Greeter.setGreeting, (greeting) ); messenger.sendMessage(greeterChainId, greeterAddress, message); } } ``` ```solidity theme={null} function setGreeting(string calldata greeting) public { bytes memory message = abi.encodeCall( Greeter.setGreeting, (greeting) ); messenger.sendMessage(greeterChainId, greeterAddress, message); } ``` This function encodes a call to `setGreeting` and sends it to a contract on another chain. `abi.encodeCall(Greeter.setGreeting, (greeting))` constructs the [calldata](https://docs.soliditylang.org/en/latest/internals/layout_in_calldata.html) by encoding the function selector and parameters. The encoded message is then passed to `messenger.sendMessage`, which forwards it to the destination contract (`greeterAddress`) on the specified chain (`greeterChainId`). This ensures that `setGreeting` is executed remotely with the provided `greeting` value (as long as there is an executing message to relay it). 6. Deploy `GreetingSender` to chain A. ```sh theme={null} CHAIN_ID_B=`cast chain-id --rpc-url $URL_CHAIN_B` GREETER_A_ADDRESS=`forge create --rpc-url $URL_CHAIN_A --private-key $PRIVATE_KEY --broadcast GreetingSender --constructor-args $GREETER_B_ADDRESS $CHAIN_ID_B | awk '/Deployed to:/ {print $3}'` ``` Send a greeting from chain A to chain B. ```sh theme={null} cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii cast send --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A" sleep 4 cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii ``` The `sleep` call is because it can take up to two seconds until the transaction is included in chain A, and then up to two seconds until the relay transaction is included in chain B. ## Sender information Run this command to view the events to see who called `setGreeting`. ```sh theme={null} cast logs --rpc-url $URL_CHAIN_B 'SetGreeting(address,string)' ``` The sender information is stored in the second event topic. However, for cross-chain messages, this value corresponds to the local `L2ToL2CrossDomainMessenger` contract address (`4200000000000000000000000000000000000023`), making it ineffective for identifying the original sender. In this section we change `Greeter.sol` to emit a separate event in it receives a cross domain message, with the sender's identity (address and chain ID). 1. Modify `src/Greeter.sol` to this code. ```solidity theme={null} //SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Predeploys } from "@eth-optimism/contracts-bedrock/src/libraries/Predeploys.sol"; interface IL2ToL2CrossDomainMessenger { function crossDomainMessageContext() external view returns (address sender_, uint256 source_); } contract Greeter { IL2ToL2CrossDomainMessenger public immutable messenger = IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER); string greeting; event SetGreeting( address indexed sender, // msg.sender string greeting ); event CrossDomainSetGreeting( address indexed sender, // Sender on the other side uint256 indexed chainId, // ChainID of the other side string greeting ); function greet() public view returns (string memory) { return greeting; } function setGreeting(string memory _greeting) public { greeting = _greeting; emit SetGreeting(msg.sender, _greeting); if (msg.sender == Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) { (address sender, uint256 chainId) = messenger.crossDomainMessageContext(); emit CrossDomainSetGreeting(sender, chainId, _greeting); } } } ``` ```solidity theme={null} interface IL2ToL2CrossDomainMessenger { function crossDomainMessageContext() external view returns (address sender_, uint256 source_); } ``` This definition isn't part of the [npmjs package](https://www.npmjs.com/package/@eth-optimism/contracts-bedrock) at writing, so we just add it here. ```solidity theme={null} if (msg.sender == Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) { (address sender, uint256 chainId) = messenger.crossDomainMessageContext(); emit CrossDomainSetGreeting(sender, chainId, _greeting); } ``` If we see that we got a message from `L2ToL2CrossDomainMessenger`, we call [`L2ToL2CrossDomainMessenger.crossDomainMessageContext`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L118-L126). 2. Redeploy the contracts. Because the address of `Greeter` is immutable in `GreetingSender`, we need to redeploy both contracts. ```sh theme={null} GREETER_B_ADDRESS=`forge create --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY Greeter --broadcast | awk '/Deployed to:/ {print $3}'` GREETER_A_ADDRESS=`forge create --rpc-url $URL_CHAIN_A --private-key $PRIVATE_KEY --broadcast GreetingSender --constructor-args $GREETER_B_ADDRESS $CHAIN_ID_B | awk '/Deployed to:/ {print $3}'` ``` 1. Set the greeting through `GreetingSender`. ```sh theme={null} cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii cast send --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A, with a CrossDomainSetGreeting event" sleep 4 cast call --rpc-url $URL_CHAIN_B $GREETER_B_ADDRESS "greet()" | cast --to-ascii ``` 2. Read the log entries. ```sh theme={null} cast logs --rpc-url $URL_CHAIN_B 'CrossDomainSetGreeting(address,uint256,string)' echo $GREETER_A_ADDRESS echo 0x385=`echo 0x385 | cast --to-dec` echo 0x190a85c0=`echo 0x190a85c0 | cast --to-dec` ``` See that the second topic (the first indexed log parameter) is the same as `$GREETER_A_ADDRESS`. The third topic can be either `0x385=901`, which is the chain ID for supersim chain A, or `0x190a85c0=420120000`, which is the chain ID for devnet alpha 0. ## Next steps * Review the [OP Stack Interop Explainer](/op-stack/interop/explainer) for answers to common questions about interoperability. * Read the [Message Passing Explainer](/app-developers/guides/interoperability/message-passing) to understand what happens "under the hood". * Write a revolutionary app that uses multiple blockchains within the OP Stack ecosystem. # Estimating transaction costs on OP Stack Source: https://docs.optimism.io/app-developers/tutorials/transactions/sdk-estimate-costs Learn how to use viem to estimate the cost of a transaction on OP Stack. In this tutorial, you'll learn how to use [viem](https://viem.sh/op-stack/) to estimate the cost of a transaction on OP Mainnet. You'll learn how to estimate the [execution gas fee](/app-developers/transactions/fees#execution-gas-fee) and the [L1 data fee](/app-developers/transactions/fees#l1-data-fee) independently. You'll also learn how to estimate the total cost of the transaction all at once. Check out the full explainer on [OP Stack transaction fees](/app-developers/guides/transactions/fees) for more information on how OP Mainnet charges fees under the hood. ## Supported networks Viem supports any of the [OP Stack networks](/op-mainnet/network-information/connecting-to-op). The OP Stack networks are included in Viem by default. If you want to use a network that isn't included by default, you can add it to Viem's chain configurations. ## Dependencies * [node](https://nodejs.org/en/) * [pnpm](https://pnpm.io/installation) ## Create a demo project You're going to use the library for this tutorial. Since is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. ```bash theme={null} mkdir op-est-cost-tutorial cd op-est-cost-tutorial ``` ```bash theme={null} pnpm init ``` ```bash theme={null} pnpm add viem ``` ## Get ETH on OP Sepolia This tutorial explains how to estimate transaction costs on OP Sepolia. You will need to get some ETH on OP Sepolia in order to run the code in this tutorial. ## Add a private key to your environment You need a private key in order to sign transactions. Set your private key as an environment variable with the `export` command. Make sure this private key corresponds to an address that has ETH on . Want to create a new wallet for this tutorial? If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) installed you can run `cast wallet new` in your terminal to create a new wallet and get the private key. ```bash theme={null} export TUTORIAL_PRIVATE_KEY=0x... ``` ## Start the Node REPL You're going to use the Node REPL to interact with . To start the Node REPL, run the following command in your terminal: ```bash theme={null} node ``` This will bring up a Node REPL prompt that allows you to run JavaScript code. ## Set session variables You'll need a few variables throughout this tutorial. Let's set those up now. ```js theme={null} const { createPublicClient, createWalletClient, http, parseEther, parseGwei, formatEther } = require('viem'); const { privateKeyToAccount } = require('viem/accounts'); const { optimismSepolia } = require('viem/chains'); const { publicActionsL2, walletActionsL2 } = require('viem/op-stack'); ``` ```js theme={null} const privateKey = process.env.TUTORIAL_PRIVATE_KEY const account = privateKeyToAccount(privateKey) ``` ```js theme={null} const publicClient = createPublicClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io"), }).extend(publicActionsL2()) ``` ```js theme={null} const walletClientL2 = createWalletClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io"), }).extend(walletActionsL2()) ``` ## Estimate transaction costs You're now going to use the Viem to estimate the cost of a transaction on OP Mainnet. Here you'll estimate the cost of a simple transaction that sends a small amount of ETH from your address to the address `0x1000000000000000000000000000000000000000`. Viem makes it easy to create unsigned transactions so you can estimate the cost of a transaction before asking a user to sign it. Here you'll create an unsigned transaction that sends a small amount of ETH from your address to the address `0x1000000000000000000000000000000000000000`. ```js theme={null} const transaction = { account, to: '0x1000000000000000000000000000000000000000', value: parseEther('0.00069420'), gasPrice: await publicClient.getGasPrice() } ``` With Viem you can estimate the total cost of a transaction using the [estimateTotalFee](https://viem.sh/op-stack/actions/estimateTotalFee) method. ```js theme={null} const totalEstimate = await publicClient.estimateTotalFee(transaction) console.log(`Estimated Total Cost: ${formatEther(totalEstimate)} ETH`) ``` Now that you've estimated the total cost of the transaction, go ahead and send it to the network. This will make it possible to see the actual cost of the transaction to compare to your estimate. ```js theme={null} const txHash = await walletClientL2.sendTransaction(transaction) console.log(`Transaction Hash: ${txHash}`) const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash }) console.log('receipt', receipt); ``` Once you get back the transaction receipt, check the actual execution gas fee. You can do so by accessing the `gasUsed` and `effectiveGasPrice` from the transaction receipt. You can then multiply these values to get the actual L2 cost of the transaction ```js theme={null} const l2CostActual = receipt.gasUsed * receipt.effectiveGasPrice console.log(`Actual Execution Gas Fee: ${formatEther(l2CostActual)} ETH`) ``` You can also check the actual L1 data fee. ```js theme={null} const l1CostActual = receipt.l1Fee console.log(`Actual L1 Data Fee: ${formatEther(l1CostActual)} ETH`) ``` Sum these two together to get the actual total cost of the transaction. ```js theme={null} const totalActual = l2CostActual + l1CostActual console.log(`Actual Total Cost: ${formatEther(totalActual)} ETH`) ``` Finally, check the difference between the estimated total cost and the actual total cost. This will give you a sense of how accurate your estimate was. Estimates will never be entirely accurate, but they should be close! ```js theme={null} const difference = totalEstimate >= totalActual ? totalEstimate - totalActual : totalActual - totalEstimate console.log(`Estimation Difference: ${formatEther(difference)} ETH`) ``` Estimates will never be entirely accurate due to network conditions and gas price fluctuation, but they should be close to the actual costs. ## Next steps * Always estimate before sending: Estimating costs before sending a transaction helps prevent unexpected fees and failed transactions. * Account for gas price volatility: Gas prices can change rapidly. Consider adding a buffer to your estimates or implementing a gas price oracle for more accurate pricing. * Optimize transaction data: Minimize the amount of data in your transactions to reduce L1 data fees. * Monitor network conditions: Keep an eye on network congestion and adjust your estimates accordingly. * Use appropriate gas limits: Setting too low a gas limit can cause transactions to fail, while setting it too high can result in unnecessary costs. * Implement retry mechanisms: If a transaction fails due to underestimated gas, implement a retry mechanism with adjusted gas parameters. # Tracing deposits and withdrawals Source: https://docs.optimism.io/app-developers/tutorials/transactions/sdk-trace-txns Learn how to use the viem library to trace deposits and withdrawals between L1 and L2. In this tutorial, you'll learn how to use the [viem](https://viem.sh) library to trace a [Standard Bridge](/app-developers/guides/bridging/standard-bridge) deposit or withdrawal between L1 and L2. You'll specifically learn how to determine the status of a deposit or withdrawal and how to retrieve the transaction receipt for the executed transaction on L1 (for withdrawals) or L2 (for deposits). ## Dependencies * [node](https://nodejs.org/en/) * [pnpm](https://pnpm.io/installation) ## Create a demo project You're going to use the library for this tutorial. Since is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. ```bash theme={null} mkdir trace-trx cd trace-trx ``` ```bash theme={null} pnpm init ``` ```bash theme={null} pnpm add viem ``` ## Add RPC URLs to your environment You'll be using the `getTransactionReceipt` function from the viem library during this tutorial. This function uses event queries to retrieve the receipt for a deposit or withdrawal. Since this function uses large event queries, you'll need to use an RPC provider like [Alchemy](https://alchemy.com) that supports indexed event queries. Grab an L1 and L2 RPC URL for Sepolia and OP Sepolia, respectively. ```bash theme={null} export L1_RPC_URL="https://YOUR_L1_ SEPOLIA_RPC_URL_HERE" export L2_RPC_URL="https://YOUR_L2_OP_SEPOLIA_RPC_URL_HERE" ``` ## Start the Node REPL You're going to use the Node REPL to interact with . To start the Node REPL, run the following command in your terminal: ```bash theme={null} node ``` This will bring up a Node REPL prompt that allows you to run JavaScript code. ## Import dependencies You need to import some dependencies into your Node REPL session. ### Import viem ```js theme={null} const { createPublicClient, http } = require('viem'); const { optimismSepolia, sepolia } = require('viem/chains'); ``` ## Set session variables You'll need a few variables throughout this tutorial. Let's set those up now. ```js theme={null} const l1RpcUrl = process.env.L1_RPC_URL; const l2RpcUrl = process.env.L2_RPC_URL; ``` You'll be tracing a specific deposit in this tutorial. Deposit tracing is generally based on the transaction hash of the transaction that triggered the deposit. You can replace this transaction hash with your own if you'd like. ```js theme={null} const depositHash = '0x5896d6e4a47b465e0d925723bab838c62ef53468139a5e9ba501efd70f90cccb' ``` You'll also be tracing a specific withdrawal in this tutorial. Like with deposits, withdrawal tracing is generally based on the transaction hash of the transaction that triggered the withdrawal. You can replace this transaction hash with your own if you'd like. ```js theme={null} const withdrawalHash = '0x18b8b4022b8d9e380fd89417a2e897adadf31e4f41ca17442870bf89ad024f42' ``` ```js theme={null} const l1Client = createPublicClient({ chain: sepolia, transport: http(l1RpcUrl), }); const l2Client = createPublicClient({ chain: optimismSepolia, transport: http(l2RpcUrl), }); ``` ## Trace a Deposit You can use viem to trace a deposit. You can query for the deposit status using the transaction hash of the deposit. ```js theme={null} console.log('Grabbing deposit status...') const depositStatus = await l2Client.getTransactionReceipt({ hash: depositHash }); console.log(depositStatus); ``` Retrieve the transaction receipt for the deposit using the viem client. ```js theme={null} console.log('Grabbing deposit receipt...') const depositReceipt = await l2Client.getTransaction({ hash: depositHash }); console.log(depositReceipt); ``` You can directly query for the L2 transaction that executed the deposit. ```js theme={null} console.log('Grabbing deposit txn...') const depositTransaction = await l2Client.getTransaction({ hash: depositHash }); console.log(depositTransaction); ``` ## Trace a withdrawal You can use viem's functions to trace a withdrawal. Like deposits, withdrawals can have multiple statuses depending on where they are in the process. ```js theme={null} console.log('Grabbing withdrawal status...') const withdrawalStatus = await l1Client.getTransactionReceipt({ hash: withdrawalHash }); console.log(withdrawalStatus); ``` Retrieve the L1 transaction receipt for the withdrawal. ```js theme={null} console.log('Grabbing withdrawal receipt...') const withdrawalReceipt = await l1Client.getTransaction({ hash: withdrawalHash }); console.log(withdrawalReceipt); ``` Directly query for the L1 transaction that executed the withdrawal. ```js theme={null} console.log('Grabbing withdrawal txn...') const withdrawalTransaction = await l1Client.getTransaction({ hash: withdrawalHash }); console.log(withdrawalTransaction); ``` ## Next steps * Check out the tutorial on [bridging ERC-20 tokens with the @eth-optimism/viem package](/app-developers/tutorials/bridging/cross-dom-bridge-erc20) to learn how to create deposits and withdrawals. # Triggering OP Stack transactions from Ethereum Source: https://docs.optimism.io/app-developers/tutorials/transactions/send-tx-from-eth Learn how to force transaction inclusion without the OP Stack Sequencer using Viem. OP Stack currently uses a single-Sequencer block production model. This means that there is only one Sequencer active on the network at any given time. Single-Sequencer models are simpler than their highly decentralized counterparts but they are also more vulnerable to potential downtime. Sequencer downtime must not be able to prevent users from transacting on the network. As a result, OP Stack includes a mechanism for "forcing" transactions to be included in the blockchain. This mechanism involves triggering a transaction on OP Stack by sending a transaction on Ethereum. In this tutorial you'll learn how to trigger a transaction on OP Stack from Ethereum using Viem. You'll use the OP Sepolia testnet, but the same logic will apply to OP Stack. ## Dependencies * [node](https://nodejs.org/en/) * [pnpm](https://pnpm.io/installation) ## Create a demo project You're going to use the library for this tutorial. Since is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. ```bash theme={null} mkdir trigger-transaction cd trigger-transaction ``` ```bash theme={null} pnpm init ``` ```bash theme={null} pnpm add viem ``` ## Get ETH on Sepolia and OP Sepolia This tutorial explains how to bridge tokens from Sepolia to OP Sepolia. You will need to get some ETH on both of these testnets. ## Add a private key to your environment You need a private key in order to sign transactions. Set your private key as an environment variable with the `export` command. Make sure this private key corresponds to an address that has ETH on . Want to create a new wallet for this tutorial? If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) installed you can run `cast wallet new` in your terminal to create a new wallet and get the private key. ```bash theme={null} export TUTORIAL_PRIVATE_KEY=0x... ``` ## Start the Node REPL You're going to use the Node REPL to interact with . To start the Node REPL, run the following command in your terminal: ```bash theme={null} node ``` This will bring up a Node REPL prompt that allows you to run JavaScript code. ## Import dependencies You need to import some dependencies into your Node REPL session. ```js theme={null} const { createPublicClient, createWalletClient, http, parseEther, formatEther } = require('viem'); const { optimismSepolia, sepolia } = require('viem/chains'); const { privateKeyToAccount } = require('viem/accounts'); const { publicActionsL2, publicActionsL1, walletActionsL2, walletActionsL1, getL2TransactionHashes } = require ('viem/op-stack') ``` ## Set session variables You'll need a few variables throughout this tutorial. Let's set those up now. ```js theme={null} const privateKey = process.env.TUTORIAL_PRIVATE_KEY; const account = privateKeyToAccount(privateKey); ``` ```js theme={null} const l1PublicClient = createPublicClient({ chain: sepolia, transport: http("https://rpc.ankr.com/eth_sepolia") }).extend(publicActionsL1()) const l2PublicClient = createPublicClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io") }).extend(publicActionsL2()); const l1WalletClient = createWalletClient({ chain: sepolia, transport: http("https://rpc.ankr.com/eth_sepolia") }).extend(walletActionsL1()); ``` ## Check your initial balance You'll be sending a small amount of ETH as part of this tutorial. Quickly check your balance on OP Sepolia so that you know how much you had at the start of the tutorial. ```js theme={null} const initialBalance = await l2PublicClient.getBalance({ address }); console.log(`Initial balance: ${formatEther(initialBalance)} ETH`); ``` ## Trigger the transaction Now you'll use the `OptimismPortal` contract to trigger a transaction on OP Sepolia by sending a transaction on Sepolia. ```js theme={null} const optimismPortalAbi = [ { inputs: [ { internalType: 'uint256', name: '_gasLimit', type: 'uint256' }, { internalType: 'bytes', name: '_data', type: 'bytes' }, ], name: 'depositTransaction', outputs: [], stateMutability: 'payable', type: 'function', }, ]; ``` When sending transactions via the `OptimismPortal` contract it's important to always include a gas buffer. This is because the `OptimismPortal` charges a variable amount of gas depending on the current demand for L2 transactions triggered via L1. If you do not include a gas buffer, your transactions may fail. ```js theme={null} const optimismPortalAddress = '0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383'; const gasLimit = 100000n; const data = '0x'; const value = parseEther('0.000069420'); const gasEstimate = await l1PublicClient.estimateContractGas({ address: optimismPortalAddress, abi: optimismPortalAbi, functionName: 'depositTransaction', args: [gasLimit, data], value, account: account.address, }); ``` Now you'll send the transaction. Note that you are including a buffer of 20% on top of the gas estimate. ```js theme={null} const { request } = await l1PublicClient.simulateContract({ account, address: optimismPortalAddress, abi: optimismPortalAbi, functionName: 'depositTransaction', args: [gasLimit, data], value, gas: gasEstimate * 120n / 100n, // 20% buffer }) const l1TxHash = await l1WalletClient.writeContract(request) console.log(`L1 transaction hash: ${l1TxHash}`) ``` First you'll need to wait for the L1 transaction to be mined. ```js theme={null} const l1TxHash = await l1WalletClient.writeContract(request) ``` Now you'll need to wait for the corresponding L2 transaction to be included in a block. This transaction is automatically created as a result of your L1 transaction. Here you'll determine the hash of the L2 transaction and then wait for that transaction to be included in the L2 blockchain. ```js theme={null} const [l2Hash] = getL2TransactionHashes(l1TxHash) console.log(`Corresponding L2 transaction hash: ${l2Hash}`); const l2Receipt = await l2PublicClient.waitForTransactionReceipt({ hash: l2Hash, }); console.log('L2 transaction confirmed:', l2Receipt); ``` ## Check your updated balance You should have a little less ETH on OP Sepolia now. Check your balance to confirm. ```js theme={null} const finalBalance = await l2Wallet.getBalance() console.log(`Final balance: ${formatEther(finalBalance)} ETH`); ``` Make sure that the difference is equal to the amount you were expecting to send. ```js theme={null} const difference = initialBalance - finalBalance console.log(`Difference in balance: ${formatEther(difference)} ETH`); ``` ## Next steps You've successfully triggered a transaction on OP Sepolia by sending a transaction on Sepolia using Viem. Although this tutorial demonstrated the simple example of sending a basic ETH transfer from your L2 address via the OptimismPortal contract, you can use this same technique to trigger any transaction you want. You can trigger smart contracts, send ERC-20 tokens, and more. # Configure the batcher Source: https://docs.optimism.io/chain-operators/guides/configuration/batcher Learn how to configure the op-batcher for your chain, covering the batcher policy, cost tuning, multi-blob transactions, and sequencer throttling. The op-batcher posts L2 sequencer data to the L1, to make it available for verifiers. This guide walks through the policy constraints every OP Stack chain must respect and the settings with the biggest impact on cost and stability. For a catalogue of every CLI flag and environment variable, see the [batcher configuration reference](/chain-operators/reference/batcher-configuration). ## Batcher policy The batcher policy defines high-level constraints and responsibilities regarding how L2 data is posted to L1. Below are the [standard guidelines](/op-stack/protocol/superchain-registry#what-is-a-standard-chain) for configuring the batcher within the OP Stack. | Parameter | Description | Administrator | Requirement | Notes | | -------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Data Availability Type | Specifies whether the batcher uses **blobs**, **calldata**, or **auto** to post transaction data to L1. | Batch submitter address | Ethereum (Blobs or Calldata) | - Alternative data availability (Alt-DA) is not yet supported in the standard configuration.
- The sequencer can switch at will between blob transactions and calldata, with no restrictions, because both are fully secured by L1. | | Batch Submission Frequency | Determines how frequently the batcher submits aggregated transaction data to L1 (via the batcher transaction). | Batch submitter address | Must target **1,800 L1 blocks** (6 hours on Ethereum, assuming 12s L1 block time) or lower | - Batches must be posted before the sequencing window closes (commonly 12 hours by default).
- Leave a buffer for L1 network congestion and data size to ensure that each batch is fully committed in a timely manner. | * **Data Availability Types**: * **Calldata** is generally simpler but can be more expensive on mainnet Ethereum, depending on gas prices. * **Blobs** are typically lower cost when your chain has enough transaction volume to fill large chunks of data. * The `op-batcher` can toggle between these approaches by setting the `--data-availability-type=` flag or with the `OP_BATCHER_DATA_AVAILABILITY_TYPE` env variable. Setting this flag to `auto` will allow the batcher to automatically switch between `calldata` and `blobs` based on the current L1 gas price. * **Batch Submission Frequency** (`OP_BATCHER_MAX_CHANNEL_DURATION` and related flags): * Standard OP Chains frequently target a maximum channel duration between 1–6 hours. * Your chain should never exceed your L2's sequencing window (commonly 12 hours). * If targeting a longer submission window (e.g., 5 or 6 hours), be aware that the [safe head](https://specs.optimism.io/glossary.html#safe-l2-head) can stall up to that duration. Include these high-level "policy" requirements when you set up or modify your `op-batcher` configuration. See the [batcher configuration reference](/chain-operators/reference/batcher-configuration), which explains each CLI flag and environment variable in depth. ## Recommendations ### Set your `OP_BATCHER_MAX_CHANNEL_DURATION` The default value inside `op-batcher`, if not specified, is still `0`, which means channel duration tracking is disabled. For very low throughput chains, this would mean to fill channels until close to the sequencing window and post the channel to `L1 SUB_SAFETY_MARGIN` L1 blocks before the sequencing window expires. To minimize costs, we recommend setting your `OP_BATCHER_MAX_CHANNEL_DURATION` to target 5 hours, with a value of `1500` L1 blocks. When non-zero, this parameter is the max time (in L1 blocks, which are 12 seconds each) between which batches will be submitted to the L1. If you have this set to 5 for example, then your batcher will send a batch to the L1 every 5\*12=60 seconds. When using blobs, because 130kb blobs need to be purchased in full, if your chain doesn't generate at least \~130kb of data in those 60 seconds, then you'll be posting only partially full blobs and wasting storage. * We do not recommend setting any values higher than targeting 5 hours, as batches have to be submitted within the sequencing window which defaults to 12 hours for OP chains, otherwise your chain may experience a 12 hour long chain reorg. 5 hours is the longest length of time we recommend that still sits snugly within that 12 hour window to avoid affecting stability. * If your chain fills up full blobs of data before the `OP_BATCHER_MAX_CHANNEL_DURATION` elapses, a batch will be submitted anyways - (e.g. even if the OP Mainnet batcher sets an `OP_BATCHER_MAX_CHANNEL_DURATION` of 5 hours, it will still be submitting batches every few minutes) While setting an`OP_BATCHER_MAX_CHANNEL_DURATION` of `1500` results in the cheapest fees, it also means that your [safe head](https://specs.optimism.io/glossary.html#safe-l2-head) can stall for up to 5 hours. * This will negatively impact apps on your chain that rely on the safe head for operation. While many apps can likely operate simply by following the unsafe head, often Centralized Exchanges or third party bridges wait until transactions are marked safe before processing deposits and withdrawal. * Thus a larger gap between posting batches can result in significant delays in the operation of certain types of high-security applications. ### Configure your batcher to use multiple blobs When there's blob congestion, running with high blob counts can backfire, because you will have a harder time getting blobs included and then fees will bump, which always means a doubling of the priority fees. The `op-batcher` has the capabilities to send multiple blobs per single blob transaction. This is accomplished by the use of multi-frame channels, see the [specs](https://specs.optimism.io/protocol/derivation.html?utm_source=op-docs\&utm_medium=docs#frame-format) for more technical details on channels and frames. A minimal batcher configuration (with env vars) to enable 6-blob batcher transactions is: ``` - OP_BATCHER_BATCH_TYPE=1 # span batches, optional - OP_BATCHER_DATA_AVAILABILITY_TYPE=blobs - OP_BATCHER_TARGET_NUM_FRAMES=6 # 6 blobs per tx - OP_BATCHER_TXMGR_MIN_BASEFEE=2.0 # 2 gwei, might need to tweak, depending on gas market - OP_BATCHER_TXMGR_MIN_TIP_CAP=2.0 # 2 gwei, might need to tweak, depending on gas market - OP_BATCHER_RESUBMISSION_TIMEOUT=240s # wait 4 min before bumping fees ``` This enables blob transactions and sets the target number of frames to 6, which translates to 6 blobs per transaction. The minimum tip cap and base fee are also lifted to 2 gwei because it is uncertain how easy it will be to get 6-blob transactions included and slightly higher priority fees should help. The resubmission timeout is increased to a few minutes to give more time for inclusion before bumping the fees because current transaction pool implementations require a doubling of fees for blob transaction replacements. Multi-blob transactions are particularly useful for medium to high-throughput chains, where enough transaction volume exists to fill up 6 blobs in a reasonable amount of time. To determine what number of blobs is right for your chain, estimate the compressed batch data your chain produces per channel duration and divide by blob capacity (about 130 KB); [Size your channels](/use-cases/tune-batcher-costs#step-4-size-your-channels) in the Tune batcher costs guide walks through this estimate and the matching fee scalar configuration. Please also refer to the [Post batch data as blobs](/chain-operators/guides/features/blobs) guide for chain operators. ### Set your `--batch-type=1` to use span batches Span batches reduce the overhead of OP Stack chains, introduced in the Delta network upgrade. This is beneficial for sparse and low-throughput OP Stack chains. The overhead is reduced by representing a span of consecutive L2 blocks in a more efficient manner, while preserving the same consistency checks as regular batch data. For step-by-step instructions, including how to confirm Delta is active first, see [Enable span batches](/chain-operators/guides/features/enable-span-batches). ## Batcher sequencer throttling This feature is a batcher-driven sequencer-throttling control loop. This is to avoid sudden spikes in L1 DA-usage consuming too much available gas and causing a backlog in batcher transactions. The batcher can throttle the sequencer's data throughput instantly when it sees too much batcher data built up. There are two throttling knobs: 1. Transaction throttling, which skips individual transactions whose estimated compressed L1 DA usage goes over a certain threshold, and 2. Block throttling, which caps a block's estimated total L1 DA usage and leads to not including transactions during block building that would move the block's L1 DA usage past a certain threshold. **Feature requirements** * This feature is enabled by default and requires the sequencer's `op-reth` node to expose the `miner_setMaxDASize` RPC (enable the `miner` namespace, below). It can be disabled by setting `--throttle.unsafe-da-bytes-lower-threshold` (env var `OP_BATCHER_THROTTLE_UNSAFE_DA_BYTES_LOWER_THRESHOLD`) to 0, which is the only flag you need to change to turn throttling off. The sequencer's `op-reth` node has to be updated first, before updating the batcher, so that the required RPC is available at the time of the batcher restart. * It is required to upgrade to `op-conductor/v0.2.0` if you are using conductor's leader-aware rpc proxy feature. This conductor release includes support for proxying the `miner_setMaxDASize` RPC. **Configuration** Note that this feature requires the batcher to correctly follow the sequencer at all times, or it would set throttling parameters on a non-sequencer EL client. That means, active sequencer follow mode has to be enabled correctly by listing all the possible sequencers in the L2 rollup and EL endpoint flags. The batcher is configured for throttling by default with the parameters described below (and corresponding flags which allow the defaults to be overridden): * Backlog of pending block bytes beyond which the batcher will enable throttling on the sequencer via `--throttle.unsafe-da-bytes-lower/upper-threshold` (env var `OP_BATCHER_THROTTLE_UNSAFE_DA_BYTES_LOWER/UPPER_THRESHOLD`): 3\_200\_000 and 12\_800\_000 (batcher backlog of 3.2MB to 12.8MB of data to batch). Disable throttling by setting the lower threshold to `0`. The upper threshold sets the level where the maximum throttling intensity is reached. * Individual tx size throttling via `--throttle.tx-size-lower/upper-limit` (env var `OP_BATCHER_THROTTLE_TX_SIZE_LOWER/UPPER_LIMIT`): 150 and 20\_000. This is the limit on the estimated compressed size of a transaction when throttling is at maximum/minimum intensity respectively. * Block size throttling via `--throttle.block-size-lower/upper-limit` (env var `OP_BATCHER_THROTTLE_BLOCK_SIZE_LOWER/UPPER_LIMIT`): 2\_000 and 130\_000. This is the limit on the estimated compressed size of a block when throttling is at maximum/minimum intensity respectively. * Throttler controller type via `--throttle.controller-type` (env var `OP_BATCHER_THROTTLE_CONTROLLER_TYPE`): `quadratic` by default. This determines how transaction and block size limits are interpolated when throttling is at intermediate intensity. For full details, see the [readme](https://github.com/ethereum-optimism/optimism/blob/develop/op-batcher/readme.md). If the batcher at startup has throttling enabled and the sequencer's `op-reth` node to which it's talking doesn't have the `miner_setMaxDASize` RPC enabled, it will fail with an error message like: ``` lvl=warn msg="Served miner_setMaxDASize" reqid=1 duration=11.22µs err="the method miner_setMaxDASize does not exist/is not available" In this case, make sure the miner API namespace is enabled for the correct transport protocol (HTTP or WS), see next paragraph. ``` The `miner_setMaxDASize` RPC has to be enabled by adding the `miner` namespace to `op-reth`'s API flags: ``` --http.api=web3,debug,eth,txpool,net,miner --ws.api=web3,debug,eth,txpool,net,miner ``` It is recommended to add it to both HTTP and WS. ## Example configuration This is a basic example of a batcher configuration. Optimal batcher configuration is going to differ for each chain, however you can see some of the most important variables configured below: ``` OP_BATCHER_WAIT_NODE_SYNC: true OP_BATCHER_CHECK_RECENT_TXS_DEPTH: 5 OP_BATCHER_POLL_INTERVAL: "5s" OP_BATCHER_BATCH_TYPE: "1" # span OP_BATCHER_COMPRESSION_ALGO: brotli-10 OP_BATCHER_DATA_AVAILABILITY_TYPE: auto OP_BATCHER_MAX_CHANNEL_DURATION: "150" # up to 30 min to fill blobs OP_BATCHER_TARGET_NUM_FRAMES: "5" # 5 blobs, can go to 6 with Pectra activated on L1 OP_BATCHER_SUB_SAFETY_MARGIN: "300" # 1h safety margin to prevent seq window elapse OP_BATCHER_NUM_CONFIRMATIONS: "4" OP_BATCHER_NETWORK_TIMEOUT: "10s" OP_BATCHER_TXMGR_MIN_BASEFEE: "2.0" OP_BATCHER_TXMGR_MIN_TIP_CAP: "2.0" OP_BATCHER_TXMGR_FEE_LIMIT_MULTIPLIER: 16 # allow up to 4 doublings OP_BATCHER_MAX_PENDING_TX: "10" OP_BATCHER_RESUBMISSION_TIMEOUT: "180s" # wait 3 min before bumping fees OP_BATCHER_ACTIVE_SEQUENCER_CHECK_DURATION: 5s ``` Lower throughput chains, which aren't filling up channels before the `MAX_CHANNEL_DURATION` is hit, may save gas by increasing the `MAX_CHANNEL_DURATION`. See the [recommendations section](#set-your--op_batcher_max_channel_duration). # Chain Operator Configurations Source: https://docs.optimism.io/chain-operators/guides/configuration/getting-started Learn how to configure an OP Stack chain. OP Stack chains can be configured for the Chain Operator's needs. Each component of the stack has its own considerations. See the following for documentation for details on configuring each piece. Deploying your OP Stack contracts requires creating a deployment configuration JSON file. This defines the behavior of your network at its genesis. * **Important Notes:** * The Rollup Configuration sets parameters for the L1 smart contracts upon deployment. These parameters govern the behavior of your chain and are critical to its operation. * Be aware that many of these values cannot be changed after deployment or require a complex process to update. Carefully consider and validate all settings during configuration to avoid issues later. * [Rollup Deployment Configuration reference](/chain-operators/reference/rollup-deployment-configuration) The batcher is the service that submits the L2 Sequencer data to L1, to make it available for verifiers. These configurations determine the batcher's behavior. * [Batcher Configuration Documentation](/chain-operators/guides/configuration/batcher) The proposer is the service that submits the output roots to the L1. These configurations determine the proposer's behavior. * [Proposer Configuration Documentation](/chain-operators/guides/configuration/proposer) The rollup node has a wide array of configurations for both the consensus and execution clients. * [Consensus Client Configuration](/node-operators/guides/configuration/consensus-clients) * [Execution Client Configuration](/node-operators/guides/configuration/execution-clients) # How to configure challenger for your chain Source: https://docs.optimism.io/chain-operators/guides/configuration/op-challenger-config-guide Learn how to configure challenger for your OP Stack chain. This guide provides step-by-step instructions for setting up the configuration and monitoring options for `op-challenger`. The challenger is a critical fault proofs component that monitors dispute games and challenges invalid claims to protect your OP Stack chain. See the [op-challenger explainer](/op-stack/fault-proofs/challenger) for a general overview of this fault proofs feature. The challenger is responsible for: * Monitoring dispute games created by the fault proof system * Challenging invalid claims in dispute games * Defending valid state transitions * Resolving games when possible For the complete catalog of flags, environment variables, and defaults, see the [challenger configuration reference](/chain-operators/reference/challenger-configuration). **From the Karst upgrade, `cannon-kona` is the respected fault-proof game type, replacing op-program.** Configure `op-challenger` with the `cannon-kona` trace type and a kona-client absolute prestate. A challenger still running the `cannon` / op-program trace type past Karst will not defend your chain. **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. ## Prerequisites ### Essential requirements Before configuring your challenger, complete the following steps: * L1 contracts deployed with dispute game factory * Fault proof system active on your chain * Access to your chain's contract addresses * [Generate an absolute prestate](/chain-operators/tutorials/absolute-prestate#generating-the-absolute-prestate) for your network version - This is critical as the challenger will refuse to interact with games if it doesn't have the matching prestate * L1 RPC endpoint (Ethereum, Sepolia, etc.) * L1 Beacon node endpoint (for blob access) * L2 archive node with debug API enabled * Rollup node (op-node) with historical data * `rollup.json` - Rollup configuration file * `genesis-l2.json` - L2 genesis file * `prestate.json` - The absolute prestate file generated in step 1 ### Software requirements * Git (for cloning repositories) * Go 1.21+ (if building from source) * Docker and Docker Compose (optional but recommended) * Access to a funded Ethereum account for challenger operations ### Finding the current stable releases To ensure you're using the latest compatible versions of OP Stack components, always check the official releases page: [OP Stack releases page](https://github.com/ethereum-optimism/optimism/releases) This guide is verified against the following versions: * **op-challenger** — `op-challenger/v1.9.4` (look for the latest `op-challenger/v*`). * **op-reth** — `v2.2.5` (look for the latest [op-reth release](https://github.com/ethereum-optimism/optimism/releases?q=op-reth)). op-reth is both the sequencer's execution client and the archive node the challenger reads withdrawal proofs from. * **kona-client** — the absolute prestate is built from a tagged `kona-client/v*` release (e.g. `kona-client/v1.6.0-rc.1`). Use the tag matching the prestate registered on your chain; for governance-approved upgrades the version is named in the upgrade notice. See the [kona-client prestate tutorial](/chain-operators/tutorials/kona-custom-prestate). Always check the release notes to ensure you're using compatible versions with your chain's deployment. Using the op-challenger and kona-client versions named in the upgrade notice (or the latest matching releases) is the supported path. ## Software installation For challenger deployment, you can either build from source (recommended for better control and debugging) or use Docker for a containerized setup. ### Build and configure Building from source gives you full control over the binaries and is the preferred approach for production deployments. **Clone and build op-challenger** ```bash theme={null} # Clone the optimism monorepo git clone https://github.com/ethereum-optimism/optimism.git cd optimism # Check out the latest release of op-challenger git checkout op-challenger/v1.9.4 # Generate the embedded superchain config bundle (initializes the # superchain-registry submodule; op-challenger embeds this file at compile time) just build-superchain-go # Install dependencies and build just op-challenger # Build the Cannon VM binary used to run dispute traces just cannon # Binaries will be available at ./op-challenger/bin/op-challenger # and ./cannon/bin/cannon ``` **Build kona-host** The challenger also needs `kona-host`, the pre-image oracle server for the `cannon-kona` game type. Build it from the kona-client release tag matching the absolute prestate registered on your chain (see [Finding the current stable releases](#finding-the-current-stable-releases)), so the server matches the `kona-client` build committed on chain: ```bash theme={null} # In a checkout of the tag your prestate was built from cd rust cargo build --release --bin kona-host # Binary will be available at ./rust/target/release/kona-host ``` ### Verify installation Check that you have properly installed the challenger component: ```bash theme={null} # Make sure you're in the optimism directory ./op-challenger/bin/op-challenger --help # You should see the challenger help output with available commands and flags ``` ## Configuration setup After building the binaries, create your challenger working directory: ```bash theme={null} # Create challenger directory (this should be at the same level as optimism directory) mkdir challenger-node cd challenger-node # Create necessary subdirectories mkdir scripts mkdir challenger-data # Verify the optimism directory is accessible # Directory structure should look like: # /optimism/ (contains the built binaries) # /challenger-node/ (your working directory) ``` ```bash theme={null} # Copy configuration files to your challenger directory # Adjust paths based on your deployment setup cp /path/to/your/rollup.json . cp /path/to/your/genesis-l2.json . ``` You'll need to gather several pieces of information before creating your configuration. Here's where to get each value: **L1 network access:** * L1 RPC URL: Your L1 node endpoint (Infura, Alchemy, or self-hosted) * L1 Beacon URL: Beacon chain API endpoint for blob access **L2 network access:** * L2 RPC URL: Your op-reth archive node endpoint * Rollup RPC URL: Your op-node endpoint with historical data **Challenger wallet:** * Private key for challenger operations (must be funded) **Network configuration:** * Game factory address from your contract deployment * Network identifier (e.g., op-sepolia, op-mainnet, or custom) Copy and paste in your terminal, to create your env file. ```bash theme={null} # Create .env file with your actual values cat > .env << 'EOF' # L1 Configuration - Replace with your actual RPC URLs L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY # L2 Configuration - Replace with your actual node endpoints L2_RPC_URL=http://localhost:8545 ROLLUP_RPC_URL=http://localhost:8547 L1_BEACON=http://sepolia-cl-1:5051 # Wallet configuration - Choose either mnemonic + HD path OR private key MNEMONIC="test test test test test test test test test test test junk" HD_PATH="m/44'/60'/0'/0/0" # PRIVATE_KEY=0xYOUR_ACTUAL_PRIVATE_KEY # Alternative to mnemonic # Network configuration NETWORK=op-sepolia GAME_FACTORY_ADDRESS=0xYOUR_GAME_FACTORY_ADDRESS # Trace configuration (cannon-kona is the respected game type from the Karst upgrade) TRACE_TYPE=permissioned,cannon-kona # Data directory DATADIR=./challenger-data # Cannon VM binary (shared by cannon and cannon-kona; built from the optimism repo) CANNON_BIN=/cannon/bin/cannon # Configuration files CANNON_ROLLUP_CONFIG= CANNON_L2_GENESIS= # kona executable used as the pre-image oracle server, and the kona-client absolute prestate CANNON_KONA_SERVER= CANNON_KONA_PRESTATE= EOF ``` **Important:** Replace ALL placeholder values (`YOUR_ACTUAL_*`) with your real configuration values. * This is the HTTP provider URL for a standard L1 node, can be a full node. `op-challenger` will be sending many requests, so chain operators need a node that is trusted and can easily handle many transactions. * Note: Challenger has a lot of money, and it will spend it if it needs to interact with games. That might risk not defending games or challenging games correctly, so chain operators should really trust the nodes being pointed at Challenger. * This is needed just to get blobs from. * In some instances, chain operators might need a blob archiver or L1 consensus node configured not to prune blobs: * If the chain is proposing regularly, a blob archiver isn't needed. There's only a small window in the blob retention period that games can be played. * If the chain doesn't post a valid output root in 18 days, then a blob archiver running a challenge game is needed. If the actor gets pushed to the bottom of the game, it could lose if it's the only one protecting the chain. * This needs to be an `op-reth` archive node, with `debug` enabled. * Technically doesn't need to go to bedrock, but needs to have access to the start of any game that is still in progress. * The withdrawal-proof data the challenger reads via `eth_getProof` is served by op-reth's historical-proofs store. Enable it with `--proofs-history --proofs-history.storage-version v2`, set a persistent `--proofs-history.storage-path`, and size `--proofs-history.window` to cover the dispute game window (≥ 28 days). On permissioned chains, `--rpc.eth-proof-window` bounds how far back `eth_getProof` will serve. See [Running op-reth with historical proofs](/node-operators/tutorials/reth-historical-proofs). * **Seed the proofs storage once before starting the node with `--proofs-history`**, or op-reth refuses to start (the `proofs-history` ExEx panics with `Proofs storage not initialized`). With the node stopped, run `op-reth proofs init --chain --datadir --proofs-history.storage-path --proofs-history.storage-version v2`. It snapshots the chain's current state to seed the sidecar; the ExEx then indexes forward as the node syncs. Initialize at (or near) genesis so the whole fault-proof window is covered — a node seeded at the current tip only serves proofs for blocks after that point. * This needs to be an `op-node` archive node because challenger needs access to output roots from back when the games start. See below for important configuration details: 1. Safe Head Database (SafeDB) Configuration for op-node: * The `op-node` behind the `op-conductor` must have the SafeDB enabled to ensure it is not stateless. * To enable SafeDB, set the `--safedb.path` value in your configuration. This specifies the file path used to persist safe head update data. * Example Configuration: ```bash theme={null} --safedb.path # Replace with your actual path ``` If this path is not set, the SafeDB feature will be disabled. **Never restore the SafeDB from a snapshot.** The SafeDB records the safe head as derived from L1, and a snapshot may not reflect the actual on-chain derivation state. If the SafeDB is out of sync with L1, `op-challenger` will act on an incorrect safe head and may incorrectly attack valid outputs. `op-challenger` cannot detect this condition — the data it receives appears normal. If you suspect the SafeDB was restored from a snapshot or is otherwise corrupted, delete it and resync from a snapshot that is at least 30 days old — `op-node` does not backfill the SafeDB, so it will only populate it going forward from that point. A 30-day-old snapshot provides enough history to cover the 28-day dispute game window. 2. Ensuring Historical Data Availability: * Both `op-node` and `op-reth` must have data from the start of the games to maintain network consistency and allow nodes to reference historical state and transactions. * For `op-node`: Configure it to maintain a sufficient history of blockchain data locally or use an archive node. * For `op-reth`: Similarly, configure to store or access historical data. * Example Configuration: ```bash theme={null} op-node \ --rollup-rpc \ --safedb.path ``` Replace `` with the URL of your archive node and `` with the desired path for storing SafeDB data. * Chain operators must specify a private key or use something else (like `op-signer`). * This uses the same transaction manager arguments as `op-node` , batcher, and proposer, so chain operators can choose one of the following options: * a mnemonic * a private key * `op-signer` endpoints * This identifies the L2 network `op-challenger` is running for, e.g., `op-sepolia` or `op-mainnet`. * When using the `--network` flag, the `--game-factory-address` will be automatically pulled from the [`superchain-registry`](https://github.com/ethereum-optimism/superchain-registry/blob/main/chainList.json). * When the trace is generated, challenger needs the rollup config and the L2 genesis file. Both files are automatically loaded when a registry `--network` is used, but custom networks must specify both the L2 genesis and rollup config. * For custom networks not in the [`superchain-registry`](https://github.com/ethereum-optimism/superchain-registry/blob/main/chainList.json), the `--game-factory-address` and rollup must be specified, as follows: ```bash theme={null} --cannon-kona-rollup-config rollup.json \ --cannon-kona-l2-genesis genesis-l2.json \ # use this if running challenger outside of the docker image --cannon-kona-server ./kona \ # version of kona-client deployed on chain # if you use the wrong one, you will lose the game # if you deploy your own contracts, you specify the hash, the root of the json file # OP Mainnet uses tagged versions of kona-client # build with: just reproducible-prestate-kona # challenger verifies that onchain --cannon-kona-prestate ./prestate.json \ # load the game factory address from system config or superchain registry # point the game factory address at the dispute game factory proxy --game-factory-address ``` These options vary based on which `--network` is specified. Chain operators always need to specify a way to load prestates and must also specify the `--cannon-kona-server` whenever the docker image isn't being used. * This is a directory that `op-challenger` can write to and store whatever data it needs. It will manage this directory to add or remove data as needed under that directory. * If running in docker, it should point to a docker volume or mount point, so the data isn't lost on every restart. The data can be recreated if needed but particularly if challenger has executed cannon as part of responding to a game it may mean a lot of extra processing. The prestate is effectively the version of `kona-client` that is deployed on chain (run inside the Cannon VM as the `cannon-kona` game type). And chain operators must use the right version. `op-challenger` will refuse to interact with games that have a different absolute prestate hash to avoid making invalid claims. If deploying your own contracts, chain operators must specify an absolute prestate hash taken from the `just reproducible-prestate-kona` command during contract deployment, which will also build the required prestate file. All governance approved releases use a tagged version of `kona-client`. These can be rebuilt by checking out the version tag and running `just reproducible-prestate-kona`. * There are two ways to specify the prestate to use: * `--cannon-kona-prestate`: specifies a path to a single kona-client absolute-prestate file * `--cannon-kona-prestates-url`: specifies a URL to load prestates from. This enables participating in games that use different prestates, for example due to a network upgrade. The prestates are stored in this directory named by their hash. * Example final URL for a prestate: * [https://example.com/prestates/0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808.json](https://example.com/prestates/0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808.json) * This file contains the cannon memory state. Challenger will refuse to interact with any games if it doesn't have the matching prestate. Check this [guide](/chain-operators/tutorials/absolute-prestate#generating-the-absolute-prestate) on how to generate a absolute prestate. ### Create challenger startup script Create `scripts/start-challenger.sh`: ```bash theme={null} #!/bin/bash source .env # Path to the challenger binary ../optimism/op-challenger/bin/op-challenger \ --trace-type permissioned,cannon-kona \ --l1-eth-rpc=$L1_RPC_URL \ --l2-eth-rpc=$L2_RPC_URL \ --l1-beacon=$L1_BEACON \ --rollup-rpc=$ROLLUP_RPC_URL \ --game-factory-address $GAME_FACTORY_ADDRESS \ --datadir=$DATADIR \ --cannon-bin=$CANNON_BIN \ --cannon-kona-rollup-config=$CANNON_ROLLUP_CONFIG \ --cannon-kona-l2-genesis=$CANNON_L2_GENESIS \ --cannon-kona-server=$CANNON_KONA_SERVER \ --cannon-kona-prestate=$CANNON_KONA_PRESTATE \ --mnemonic "$MNEMONIC" \ --hd-path "$HD_PATH" ``` ## Initializing and starting the challenger ### Start the challenger ```bash theme={null} # Make sure you're in the challenger-node directory cd challenger-node # Make script executable chmod +x scripts/start-challenger.sh # Start challenger ./scripts/start-challenger.sh ``` ### Verify challenger is running Monitor challenger logs to ensure it's operating correctly: ```bash theme={null} # Check challenger logs tail -f challenger-data/challenger.log # Or if running in foreground, monitor the output ``` The challenger should show logs indicating: * Successful connection to L1 and L2 nodes * Loading of prestates and configuration * Monitoring of dispute games ### Docker setup The Docker setup provides a containerized environment for running the challenger. This method uses the official Docker image that includes the embedded `kona` server and Cannon executable. First, create a `.env` file with your configuration values. This file will be used by Docker Compose to set up the environment variables: ```bash theme={null} # Create .env file with your actual values cat > .env << 'EOF' # L1 Configuration - Replace with your actual RPC URLs L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY L1_BEACON=http://sepolia-cl-1:5051 # L2 Configuration - Replace with your actual node endpoints L2_RPC_URL=http://localhost:8545 ROLLUP_RPC_URL=http://localhost:8547 # Wallet configuration - Choose either mnemonic + HD path OR private key MNEMONIC="test test test test test test test test test test test junk" HD_PATH="m/44'/60'/0'/0/0" # Network configuration NETWORK=op-sepolia GAME_FACTORY_ADDRESS=0xYOUR_GAME_FACTORY_ADDRESS EOF ``` **Important:** Replace ALL placeholder values (`YOUR_ACTUAL_*`) with your real configuration values. Each environment variable maps to a specific challenger configuration flag. Here's what each one does: * This is the HTTP provider URL for a standard L1 node, can be a full node. `op-challenger` will be sending many requests, so chain operators need a node that is trusted and can easily handle many transactions. * Note: Challenger has a lot of money, and it will spend it if it needs to interact with games. That might risk not defending games or challenging games correctly, so chain operators should really trust the nodes being pointed at Challenger. * This is needed just to get blobs from. * In some instances, chain operators might need a blob archiver or L1 consensus node configured not to prune blobs: * If the chain is proposing regularly, a blob archiver isn't needed. There's only a small window in the blob retention period that games can be played. * If the chain doesn't post a valid output root in 18 days, then a blob archiver running a challenge game is needed. If the actor gets pushed to the bottom of the game, it could lose if it's the only one protecting the chain. * This needs to be an `op-reth` archive node, with `debug` enabled. * Technically doesn't need to go to bedrock, but needs to have access to the start of any game that is still in progress. * The withdrawal-proof data the challenger reads via `eth_getProof` is served by op-reth's historical-proofs store. Enable it with `--proofs-history --proofs-history.storage-version v2`, set a persistent `--proofs-history.storage-path`, and size `--proofs-history.window` to cover the dispute game window (≥ 28 days). On permissioned chains, `--rpc.eth-proof-window` bounds how far back `eth_getProof` will serve. See [Running op-reth with historical proofs](/node-operators/tutorials/reth-historical-proofs). * **Seed the proofs storage once before starting the node with `--proofs-history`**, or op-reth refuses to start (the `proofs-history` ExEx panics with `Proofs storage not initialized`). With the node stopped, run `op-reth proofs init --chain --datadir --proofs-history.storage-path --proofs-history.storage-version v2`. It snapshots the chain's current state to seed the sidecar; the ExEx then indexes forward as the node syncs. Initialize at (or near) genesis so the whole fault-proof window is covered — a node seeded at the current tip only serves proofs for blocks after that point. * This needs to be an `op-node` archive node because challenger needs access to output roots from back when the games start. See below for important configuration details: 1. Safe Head Database (SafeDB) Configuration for op-node: * The `op-node` behind the `op-conductor` must have the SafeDB enabled to ensure it is not stateless. * To enable SafeDB, set the `--safedb.path` value in your configuration. This specifies the file path used to persist safe head update data. * Example Configuration: ```bash theme={null} --safedb.path # Replace with your actual path ``` If this path is not set, the SafeDB feature will be disabled. **Never restore the SafeDB from a snapshot.** The SafeDB records the safe head as derived from L1, and a snapshot may not reflect the actual on-chain derivation state. If the SafeDB is out of sync with L1, `op-challenger` will act on an incorrect safe head and may incorrectly attack valid outputs. `op-challenger` cannot detect this condition — the data it receives appears normal. If you suspect the SafeDB was restored from a snapshot or is otherwise corrupted, delete it and resync via consensus sync from a snapshot that is at least 30 days old — `op-node` does not backfill the SafeDB, so it will only populate it going forward from that point. A 30-day-old snapshot provides enough history to cover the 28-day dispute game window. 2. Ensuring Historical Data Availability: * Both `op-node` and `op-reth` must have data from the start of the games to maintain network consistency and allow nodes to reference historical state and transactions. * For `op-node`: Configure it to maintain a sufficient history of blockchain data locally or use an archive node. * For `op-reth`: Similarly, configure to store or access historical data. * Example Configuration: ```bash theme={null} op-node \ --rollup-rpc \ --safedb.path ``` Replace `` with the URL of your archive node and `` with the desired path for storing SafeDB data. * Chain operators must specify a private key or use something else (like `op-signer`). * This uses the same transaction manager arguments as `op-node` , batcher, and proposer, so chain operators can choose one of the following options: * a mnemonic * a private key * `op-signer` endpoints * This identifies the L2 network `op-challenger` is running for, e.g., `op-sepolia` or `op-mainnet`. * When using the `--network` flag, the `--game-factory-address` will be automatically pulled from the [`superchain-registry`](https://github.com/ethereum-optimism/superchain-registry/blob/main/chainList.json). * When the trace is generated, challenger needs the rollup config and the L2 genesis file. Both files are automatically loaded when a registry `--network` is used, but custom networks must specify both the L2 genesis and rollup config. * For custom networks not in the [`superchain-registry`](https://github.com/ethereum-optimism/superchain-registry/blob/main/chainList.json), the `--game-factory-address` and rollup must be specified, as follows: ```bash theme={null} --cannon-kona-rollup-config rollup.json \ --cannon-kona-l2-genesis genesis-l2.json \ # use this if running challenger outside of the docker image --cannon-kona-server ./kona \ # version of kona-client deployed on chain # if you use the wrong one, you will lose the game # if you deploy your own contracts, you specify the hash, the root of the json file # OP Mainnet uses tagged versions of kona-client # build with: just reproducible-prestate-kona # challenger verifies that onchain --cannon-kona-prestate ./prestate.json \ # load the game factory address from system config or superchain registry # point the game factory address at the dispute game factory proxy --game-factory-address ``` These options vary based on which `--network` is specified. Chain operators always need to specify a way to load prestates and must also specify the `--cannon-kona-server` whenever the docker image isn't being used. * This is a directory that `op-challenger` can write to and store whatever data it needs. It will manage this directory to add or remove data as needed under that directory. * If running in docker, it should point to a docker volume or mount point, so the data isn't lost on every restart. The data can be recreated if needed but particularly if challenger has executed cannon as part of responding to a game it may mean a lot of extra processing. The prestate is effectively the version of `kona-client` that is deployed on chain (run inside the Cannon VM as the `cannon-kona` game type). And chain operators must use the right version. `op-challenger` will refuse to interact with games that have a different absolute prestate hash to avoid making invalid claims. If deploying your own contracts, chain operators must specify an absolute prestate hash taken from the `just reproducible-prestate-kona` command during contract deployment, which will also build the required prestate file. All governance approved releases use a tagged version of `kona-client`. These can be rebuilt by checking out the version tag and running `just reproducible-prestate-kona`. * There are two ways to specify the prestate to use: * `--cannon-kona-prestate`: specifies a path to a single kona-client absolute-prestate file * `--cannon-kona-prestates-url`: specifies a URL to load prestates from. This enables participating in games that use different prestates, for example due to a network upgrade. The prestates are stored in this directory named by their hash. * Example final URL for a prestate: * [https://example.com/prestates/0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808.json](https://example.com/prestates/0x031e3b504740d0b1264e8cf72b6dde0d497184cfb3f98e451c6be8b33bd3f808.json) * This file contains the cannon memory state. Challenger will refuse to interact with any games if it doesn't have the matching prestate. Check this [guide](/chain-operators/tutorials/absolute-prestate#generating-the-absolute-prestate) on how to generate a absolute prestate. Create a `docker-compose.yml` file that defines the challenger service: ```yaml theme={null} version: '3.8' services: challenger: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:v1.9.4 user: "1000" volumes: - ./challenger-data:/data - ./rollup.json:/workspace/rollup.json:ro - ./genesis-l2.json:/workspace/genesis-l2.json:ro environment: - L1_RPC_URL=${L1_RPC_URL} - L1_BEACON=${L1_BEACON} - L2_RPC_URL=${L2_RPC_URL} - ROLLUP_RPC_URL=${ROLLUP_RPC_URL} - MNEMONIC=${MNEMONIC} - HD_PATH=${HD_PATH} - NETWORK=${NETWORK} - GAME_FACTORY_ADDRESS=${GAME_FACTORY_ADDRESS} command: - "op-challenger" - "--l1-eth-rpc=${L1_RPC_URL}" - "--l1-beacon=${L1_BEACON}" - "--l2-eth-rpc=${L2_RPC_URL}" - "--rollup-rpc=${ROLLUP_RPC_URL}" - "--selective-claim-resolution" - "--mnemonic=${MNEMONIC}" - "--hd-path=${HD_PATH}" - "--network=${NETWORK}" - "--game-factory-address=${GAME_FACTORY_ADDRESS}" - "--datadir=/data" - "--trace-type=cannon-kona" - "--cannon-kona-prestate=/workspace/prestate-proof.json" restart: unless-stopped ports: - "8548:8548" # If challenger exposes metrics endpoint ``` Start the challenger service and monitor its logs: ```bash theme={null} # Start the challenger service docker-compose up -d # View logs docker-compose logs -f challenger ``` ### Monitoring with op-dispute-mon Consider running [`op-dispute-mon`](/chain-operators/tools/chain-monitoring#dispute-mon) for enhanced security monitoring: * Provides visibility into all game statuses for the last 28 days * Essential for production challenger deployments ## Next steps * Read the [OP-Challenger Explainer](/op-stack/fault-proofs/challenger) for additional context and FAQ * Review the detailed [challenger specifications](https://specs.optimism.io/fault-proof/stage-one/honest-challenger-fdg.html) for implementation details * If you experience any problems, reach out to [developer support](https://github.com/ethereum-optimism/developers/discussions) # Proposer Configuration Source: https://docs.optimism.io/chain-operators/guides/configuration/proposer Reference for the op-proposer configuration options and the proposer policy constraints. This page lists all configuration options for op-proposer. The op-proposer posts output roots (proposals) to L1, making them available for verifiers. Withdrawals to L1 must reference an output root. If the chain is running permissioned fault proofs, only the [designated proposer](/op-stack/protocol/privileged-roles) can submit output roots. With [permissionless fault proofs](/op-stack/fault-proofs/explainer), anyone can make a proposal. ## Proposer policy The proposer policy defines high-level constraints and responsibilities regarding how L2 output roots are posted to L1. Below are the [standard guidelines](/op-stack/protocol/superchain-registry#what-is-a-standard-chain) for configuring the proposer within the OP Stack. | Parameter | Description | Administrator | Requirement | Notes | | ---------------- | ----------------------------------------------------------------------------------- | -------------- | ---------------------------------------------------------- | --------------------------------------------------------------- | | Output Frequency | Defines how frequently L2 output roots are submitted to L1 (via the output oracle). | L1 Proxy Admin | **43,200 L2 blocks** (24 hours at 2s block times) or lower | It cannot be set to 0 (there must be some cadence for outputs). | ### Example configuration ``` OP_PROPOSER_L1_ETH_RPC: YOUR_L1_RPC_URL_HERE OP_PROPOSER_ROLLUP_RPC: YOUR_CHAINS_RPC_URL_HERE OP_PROPOSER_GAME_FACTORY_ADDRESS: YOUR_CHAINS_GAME_FACTORY_ADDRESS_HERE OP_PROPOSER_PROPOSAL_INTERVAL: 5h OP_PROPOSER_WAIT_NODE_SYNC: true OP_PROPOSER_ALLOW_NON_FINALIZED: "false" OP_PROPOSER_POLL_INTERVAL: "20s" OP_PROPOSER_NUM_CONFIRMATIONS: "1" OP_PROPOSER_SAFE_ABORT_NONCE_TOO_LOW_COUNT: "3" OP_PROPOSER_RESUBMISSION_TIMEOUT: "30s" OP_PROPOSER_METRICS_ENABLED: "true" OP_PROPOSER_METRICS_ADDR: 0.0.0.0 OP_PROPOSER_METRICS_PORT: 7300 ``` Higher throughput chains can decrease the `proposal-interval` to allow users submit withdrawals more often. ## Flags Generated from [`op-proposer/v1.16.3`](https://github.com/ethereum-optimism/optimism/releases/tag/op-proposer%2Fv1.16.3) flag definitions. 54 flags: 1 required, 53 optional. ### Required flags | Flag | Description | Environment variable | | -------------- | ------------------------ | ------------------------ | | `--l1-eth-rpc` | HTTP provider URL for L1 | `OP_PROPOSER_L1_ETH_RPC` | ### Optional flags | Flag | Description | Default | Environment variable | | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------- | | `--active-sequencer-check-duration` | The duration between checks to determine the active sequencer endpoint. | `2m0s` | `OP_PROPOSER_ACTIVE_SEQUENCER_CHECK_DURATION` | | `--allow-non-finalized` | Allow the proposer to submit proposals for L2 blocks derived from non-finalized L1 blocks. | `false` | `OP_PROPOSER_ALLOW_NON_FINALIZED` | | `--fee-limit-multiplier` | The multiplier applied to fee suggestions to put a hard limit on fee increases | `5` | `OP_PROPOSER_TXMGR_FEE_LIMIT_MULTIPLIER` | | `--game-factory-address` | Address of the DisputeGameFactory contract | — | `OP_PROPOSER_GAME_FACTORY_ADDRESS` | | `--game-type` | Dispute game type to create via the configured DisputeGameFactory | `0` | `OP_PROPOSER_GAME_TYPE` | | `--hd-path` | The HD path used to derive the sequencer wallet from the mnemonic. The mnemonic flag must also be set. | — | `OP_PROPOSER_HD_PATH` | | `--l2-output-hd-path` | DEPRECATED:The HD path used to derive the l2output wallet from the mnemonic. The mnemonic flag must also be set. | — | `OP_PROPOSER_L2_OUTPUT_HD_PATH` | | `--log.color` | Color the log output if in terminal mode | `false` | `OP_PROPOSER_LOG_COLOR` | | `--log.format` | Format the log output. Supported formats: text, terminal, logfmt, logfmtms, json, jsonms | `text` | `OP_PROPOSER_LOG_FORMAT` | | `--log.level` | The lowest log level that will be output | `INFO` | `OP_PROPOSER_LOG_LEVEL` | | `--log.pid` | Show pid in the log | `false` | `OP_PROPOSER_LOG_PID` | | `--metrics.addr` | Metrics listening address | `"0.0.0.0"` | `OP_PROPOSER_METRICS_ADDR` | | `--metrics.enabled` | Enable the metrics server | `false` | `OP_PROPOSER_METRICS_ENABLED` | | `--metrics.port` | Metrics listening port | `7300` | `OP_PROPOSER_METRICS_PORT` | | `--mnemonic` | The mnemonic used to derive the wallets for either the service | — | `OP_PROPOSER_MNEMONIC` | | `--network-timeout` | Timeout for all network operations | `10s` | `OP_PROPOSER_NETWORK_TIMEOUT` | | `--num-confirmations` | Number of confirmations which we will wait after sending a transaction | `10` | `OP_PROPOSER_NUM_CONFIRMATIONS` | | `--poll-interval` | Delay between periodic checks on whether it is time to load an output root and propose it. | `12s` | `OP_PROPOSER_POLL_INTERVAL` | | `--pprof.addr` | pprof listening address | `"0.0.0.0"` | `OP_PROPOSER_PPROF_ADDR` | | `--pprof.enabled` | Enable the pprof server | `false` | `OP_PROPOSER_PPROF_ENABLED` | | `--pprof.path` | pprof file path. If it is a directory, the path is \{dir}/\{profileType}.prof | — | `OP_PROPOSER_PPROF_PATH` | | `--pprof.port` | pprof listening port | `6060` | `OP_PROPOSER_PPROF_PORT` | | `--pprof.type` | pprof profile type. One of cpu, heap, goroutine, threadcreate, block, mutex, allocs | — | `OP_PROPOSER_PPROF_TYPE` | | `--private-key` | The private key to use with the service. Must not be used with mnemonic. | — | `OP_PROPOSER_PRIVATE_KEY` | | `--proposal-interval` | Interval between submitting L2 output proposals when the dispute game factory address is set | `0s` | `OP_PROPOSER_PROPOSAL_INTERVAL` | | `--resubmission-timeout` | Duration we will wait before resubmitting a transaction to L1 | `48s` | `OP_PROPOSER_RESUBMISSION_TIMEOUT` | | `--rollup-rpc` | HTTP provider URL for the rollup node. A comma-separated list enables the active rollup provider. | — | `OP_PROPOSER_ROLLUP_RPC` | | `--rpc.addr` | rpc listening address | `"0.0.0.0"` | `OP_PROPOSER_RPC_ADDR` | | `--rpc.enable-admin` | Enable the admin API | `false` | `OP_PROPOSER_RPC_ENABLE_ADMIN` | | `--rpc.port` | rpc listening port | `8545` | `OP_PROPOSER_RPC_PORT` | | `--safe-abort-nonce-too-low-count` | Number of ErrNonceTooLow observations required to give up on a tx at a particular nonce without receiving confirmation | `3` | `OP_PROPOSER_SAFE_ABORT_NONCE_TOO_LOW_COUNT` | | `--signer.address` | Address the signer is signing requests for | — | `OP_PROPOSER_SIGNER_ADDRESS` | | `--signer.endpoint` | Signer endpoint the client will connect to | — | `OP_PROPOSER_SIGNER_ENDPOINT` | | `--signer.header` | Headers to pass to the remote signer. Format `key=value`. Value can contain any character allowed in a HTTP header. When using env vars, split with commas. When using flags one key value pair per flag. | — | `OP_PROPOSER_SIGNER_HEADER` | | `--signer.tls.ca` | tls ca cert path | `"tls/ca.crt"` | `OP_PROPOSER_SIGNER_TLS_CA` | | `--signer.tls.cert` | tls cert path | `"tls/tls.crt"` | `OP_PROPOSER_SIGNER_TLS_CERT` | | `--signer.tls.enabled` | Enable or disable TLS client authentication for the signer | `true` | `OP_PROPOSER_SIGNER_TLS_ENABLED` | | `--signer.tls.key` | tls key | `"tls/tls.key"` | `OP_PROPOSER_SIGNER_TLS_KEY` | | `--supernode-rpcs` | HTTP provider URLs for the supernode instances. Multiple URLs can be provided to automatically fail over. | — | `OP_PROPOSER_SUPERNODE_RPCS` | | `--txmgr.already-published-custom-errs` | List of custom RPC error messages that indicate that a transaction has already been published. | — | `OP_PROPOSER_TXMGR_ALREADY_PUBLISHED_CUSTOM_ERRS` | | `--txmgr.cell-proof-time` | Enables cell proofs in blob transactions for Fusaka (EIP-7742) compatibility from the provided unix timestamp. Should be set to the L1 Fusaka time. May be left blank for Ethereum Mainnet, Sepolia, Holesky, or Hoodi L1s. | `18446744073709551615` | `OP_PROPOSER_TXMGR_CELL_PROOF_TIME` | | `--txmgr.fee-limit-threshold` | The minimum threshold (in GWei) at which fee bumping starts to be capped. Allows arbitrary fee bumps below this threshold. | `100` | `OP_PROPOSER_TXMGR_FEE_LIMIT_THRESHOLD` | | `--txmgr.max-basefee` | Enforces a maximum base fee (in GWei) to assume when determining tx fees, `TxMgr` returns an error when exceeded. Disabled by default. | `0` | `OP_PROPOSER_TXMGR_MAX_BASEFEE` | | `--txmgr.max-retries` | Maximum number of times to resubmit a transaction to L1 on a transient error. Set to 0 to disable retries. | `10` | `OP_PROPOSER_TXMGR_MAX_RETRIES` | | `--txmgr.max-tip-cap` | Enforces a maximum tip cap (in GWei) to use when determining tx fees, `TxMgr` returns an error when exceeded. Disabled by default. | `0` | `OP_PROPOSER_TXMGR_MAX_TIP_CAP` | | `--txmgr.min-basefee` | Enforces a minimum base fee (in GWei) to assume when determining tx fees. 1 GWei by default. | `1` | `OP_PROPOSER_TXMGR_MIN_BASEFEE` | | `--txmgr.min-tip-cap` | Enforces a minimum tip cap (in GWei) to use when determining tx fees. 1 GWei by default. | `1` | `OP_PROPOSER_TXMGR_MIN_TIP_CAP` | | `--txmgr.not-in-mempool-timeout` | Timeout for aborting a tx send if the tx does not make it to the mempool. | `2m0s` | `OP_PROPOSER_TXMGR_TX_NOT_IN_MEMPOOL_TIMEOUT` | | `--txmgr.rebroadcast-interval` | Interval at which a published transaction will be rebroadcasted if it has not yet been mined. Should be less than ResubmissionTimeout to have an effect. | `12s` | `OP_PROPOSER_TXMGR_REBROADCAST_INTERVAL` | | `--txmgr.receipt-query-interval` | Frequency to poll for receipts | `12s` | `OP_PROPOSER_TXMGR_RECEIPT_QUERY_INTERVAL` | | `--txmgr.retry-interval` | Duration we will wait before resubmitting a transaction to L1 on a transient error. Values \<= 0 will result in retrying immediately. Should be less than ResubmissionTimeout to have an effect. | `1s` | `OP_PROPOSER_TXMGR_RETRY_INTERVAL` | | `--txmgr.send-timeout` | Timeout for sending transactions. If 0 it is disabled. | `0s` | `OP_PROPOSER_TXMGR_TX_SEND_TIMEOUT` | | `--wait-node-sync` | Indicates if, during startup, the proposer should wait for the rollup node to sync to the current L1 tip before proceeding with its driver loop. | `false` | `OP_PROPOSER_WAIT_NODE_SYNC` | # How to run an Alt-DA mode chain Source: https://docs.optimism.io/chain-operators/guides/features/alt-da-mode-guide Learn how to configure and run an Alt-DA mode chain within the OP Stack. The Alt-DA Mode feature is currently in Beta within the MIT-licensed OP Stack. Beta features are built and reviewed by core contributors, and provide developers with early access to highly requested configurations. These features may experience stability issues, and we encourage feedback from our early users. This guide provides a walkthrough for chain operators who want to run an Alt-DA Mode chain. See the [Alt-DA Mode Explainer](/op-stack/features/experimental/alt-da-mode) for a general overview of this OP Stack configuration. An Alt-DA Mode OP Stack chain enables a chain operator to post and read data to any alternative data availability layer that has built a functioning OP Stack DA Server. This page includes providers that meet specific [inclusion criteria](#inclusion-criteria), as outlined below. ## Prerequisite You should use at least the following compatible op\* versions when running your chain. * op-node/v1.9.1 * op-proposer/v1.9.1 * op-batcher/v1.9.1 * Latest version of op-reth (see the [execution clients guide](/node-operators/guides/configuration/execution-clients)) **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. DA Servers are not built or maintained by core contributors. DA servers are maintained by third parties and run at your own risk. Please reach out to the team who built the DA Server you are trying to run with any questions or issues. * Celestia's docs on how to run the [Celestia DA server](https://github.com/celestiaorg/op-plasma-celestia/blob/main/README.md) * EigenDA's docs on how to run the [EigenDA DA server](https://github.com/Layr-Labs/op-plasma-eigenda/blob/main/README.md) * Avail's docs on how to run the [AvailDA DA Server](https://docs.availproject.org/docs/build-with-avail/deploy-rollup-on-avail/Optimium) * 0gDA's docs on how to run the [0gDA DA Server](https://github.com/0glabs/0g-da-op-plasma) * Near DA's docs on how to run the [Near DA Server](https://github.com/Nuffle-Labs/data-availability/blob/84b484de98f58a91bf12c8abe8df27f5e753f63a/docs/OP-Alt-DA.md) * Spin up your OP chain as usual but set `--altda.enabled=true` and point both `op-batcher` and `op-node` to the DA server. * No configuration changes are required for your execution client (`op-reth`) or `op-proposer`. ``` Alt-DA (EXPERIMENTAL) --altda.da-server value ($OP_NODE_ALTDA_DA_SERVER) HTTP address of a DA Server --altda.enabled (default: false) ($OP_NODE_ALTDA_ENABLED) Enable Alt-DA mode --altda.verify-on-read (default: true) ($OP_NODE_ALTDA_VERIFY_ON_READ) Verify input data matches the commitments from the DA storage service ``` * Set `--altda.enabled=true` and `--altda.da-service=true`. * Provide the URL for `--altda.da-server=$DA_SERVER_HTTP_URL`. ``` --altda.da-server value ($OP_BATCHER_ALTDA_DA_SERVER) HTTP address of a DA Server --altda.da-service (default: false) ($OP_BATCHER_ALTDA_DA_SERVICE) Use DA service type where commitments are generated by the DA server --altda.enabled (default: false) ($OP_BATCHER_ALTDA_ENABLED) Enable Alt-DA mode --altda.verify-on-read (default: true) ($OP_BATCHER_ALTDA_VERIFY_ON_READ) Verify input data matches the commitments from the DA storage service ``` After completing steps 1-3 above, you will have an Alt-DA mode chain up and running. * Chain operators are not posting everything to Ethereum, just commitments, so chain operators will need to determine fee scalars values to charge users. The fee scalar values are network throughput dependent, so values will need to be adjusted by chain operators as needed. * Cost structure for Alt-DA Mode: The transaction data is split up into 128kb chunks and then submitted to your DA Layer. Then, 32 byte commitments are submitted (goes to batch inbox address) to L1 for each 128kb chunk. Then, figure out how much that costs relative to the number of transactions your chain is putting through. * Set scalar values inside the deploy config. The example below shows some possible fee scalar values, calculated assuming negligible DA Layer costs, but will need to be adjusted up or down based on network throughput - as a reminder of how to set your scalar values, see [this section](/chain-operators/guides/features/blobs#update-your-scalar-values-for-blobs) of the docs. ``` // Set in Deploy Config "gasPriceOracleBaseFeeScalar": 7663, // Approximate commitment tx base cost "gasPriceOracleBlobBaseFeeScalar": 0, // blobs aren't used for submitting the small data commitments ``` Some initial scalar values must be set early on in the deploy config in [Step 2](#configure-your-op-node). And then at a later point, chain operators can update the scalar values with an L1 transaction. ## For node operators (full and archive nodes) * Run a DA server as laid out in [Step 1](#setup-your-da-server) * Provide the same `--altda.enabled=true, --altda.da-server...` on `op-node` as listed in [Step 2](#configure-your-op-node) ## Inclusion criteria Alt DA teams who want to be featured on this page must meet the following criteria: * Functional [DA Server](https://specs.optimism.io/experimental/alt-da.html?utm_source=op-docs\&utm_medium=docs#da-server), maintained in your own repo * Supporting detailed documentation, to be referenced [here](#setup-your-da-server) * Functioning OP Stack devnet using your DA server with linked configuration, contract addresses, and RPC address ## Breaking changes: renaming Plasma Mode to Alt-DA Mode This feature has been renamed from Plasma Mode to Alt-DA Mode in the monorepo at: [0bb2ff5](https://github.com/ethereum-optimism/optimism/commit/0bb2ff57c8133f1e3983820c0bf238001eca119b). There are several breaking changes you should be aware of. These include changes to configuration file parameters, environment variables, and CLI commands. Before proceeding with the migration, ensure you are using [OP Stack v1.9.1](https://github.com/ethereum-optimism/optimism/releases/tag/v1.9.1) or later. ### Modify `rollup.json` config Update your `rollup.json` configuration file by replacing the old Plasma config with the new Alt-DA config. There are two possible formats for the old Plasma config: ### Legacy plasma config If your config looks like this: ```json theme={null} "use_plasma": true, "da_commitment_type": "GenericCommitment", "da_challenge_contract_address": "0xAAA", "da_challenge_window": 1000, "da_resolve_window": 2000, ``` ### Recent plasma config Or if it looks like this: ```json theme={null} "plasma_config": { "da_commitment_type": "GenericCommitment", "da_challenge_contract_address": "0xAAA", "da_challenge_window": 1000, "da_resolve_window": 2000 } ``` ### New Alt-DA config Replace either of the above configurations with: ```json theme={null} "alt_da": { "da_commitment_type": "GenericCommitment", "da_challenge_contract_address": "0xAAA", "da_challenge_window": 1000, "da_resolve_window": 2000 } ``` Only include fields in the new config that were present in your old config. ## Updating OP Stack runtime config parameters ### CLI parameters Update the following CLI parameters for both `op-node` and `op-batcher`: | Former CLI param | Current CLI param | | ------------------------- | ------------------------ | | `--plasma.enabled` | `--altda.enabled` | | `--plasma.da-server` | `--altda.da-server` | | `--plasma.verify-on-read` | `--altda.verify-on-read` | | `--plasma.da-service` | `--altda.da-service` | ### Environment variables #### op-node | Former env var | Current env var | | ------------------------------- | ------------------------------ | | `OP_NODE_PLASMA_ENABLED` | `OP_NODE_ALTDA_ENABLED` | | `OP_NODE_PLASMA_DA_SERVER` | `OP_NODE_ALTDA_DA_SERVER` | | `OP_NODE_PLASMA_VERIFY_ON_READ` | `OP_NODE_ALTDA_VERIFY_ON_READ` | | `OP_NODE_PLASMA_DA_SERVICE` | `OP_NODE_ALTDA_DA_SERVICE` | #### op-batcher | Former env var | Current env var | | ---------------------------------- | --------------------------------- | | `OP_BATCHER_PLASMA_ENABLED` | `OP_BATCHER_ALTDA_ENABLED` | | `OP_BATCHER_PLASMA_DA_SERVER` | `OP_BATCHER_ALTDA_DA_SERVER` | | `OP_BATCHER_PLASMA_VERIFY_ON_READ` | `OP_BATCHER_ALTDA_VERIFY_ON_READ` | | `OP_BATCHER_PLASMA_DA_SERVICE` | `OP_BATCHER_ALTDA_DA_SERVICE` | #### op-alt-da (formerly op-plasma) daserver | Former env var | Current env var | | ------------------------------------------ | -------------------------------------- | | `OP_PLASMA_DA_SERVER_ADDR` | `OP_ALTDA_SERVER_ADDR` | | `OP_PLASMA_DA_SERVER_PORT` | `OP_ALTDA_SERVER_PORT` | | `OP_PLASMA_DA_SERVER_FILESTORE_PATH` | `OP_ALTDA_SERVER_FILESTORE_PATH` | | `OP_PLASMA_DA_SERVER_GENERIC_COMMITMENT` | `OP_ALTDA_SERVER_GENERIC_COMMITMENT` | | `OP_PLASMA_DA_SERVER_S3_BUCKET` | `OP_ALTDA_SERVER_S3_BUCKET` | | `OP_PLASMA_DA_SERVER_S3_ENDPOINT` | `OP_ALTDA_SERVER_S3_ENDPOINT` | | `OP_PLASMA_DA_SERVER_S3_ACCESS_KEY_ID` | `OP_ALTDA_SERVER_S3_ACCESS_KEY_ID` | | `OP_PLASMA_DA_SERVER_S3_ACCESS_KEY_SECRET` | `OP_ALTDA_SERVER_S3_ACCESS_KEY_SECRET` | After making these changes, your system should be properly configured to use the new Alt-DA Mode. Remember to thoroughly test your configuration in testnet before going mainnet. ## Next steps * Additional questions? See the FAQ section in the [Alt-DA Mode Explainer](/op-stack/features/experimental/alt-da-mode#faqs). * For more detailed info on Alt-DA Mode, see the [specs](https://specs.optimism.io/experimental/alt-da.html?utm_source=op-docs\&utm_medium=docs). * If you experience any problems, please reach out to [developer support](https://github.com/ethereum-optimism/developers/discussions). # Post batch data as blobs Source: https://docs.optimism.io/chain-operators/guides/features/blobs Learn how to switch your chain's batcher to posting batch data as blobs. This guide walks you through how to switch to using blobs for your chain. This feature was introduced with the Ecotone network upgrade. ## Switch to using blobs The first step to switching to submit data with Blobs is to calculate the scalar values you wish to set for the formula to charge users fees. Your scalar values depend on the average transactions per day your chain is processing, the types of transactions that occur on your chain, the [`OP_BATCHER_MAX_CHANNEL_DURATION`](/chain-operators/guides/configuration/batcher#set-your--op_batcher_max_channel_duration) you have parameterized on your `op-batcher`, and the target margin you wish to charge users on top of your L1 costs. For a walkthrough of sizing the scalars against your measured batcher spend, see [Recover the spend with fee scalars](/use-cases/tune-batcher-costs#step-5-recover-the-spend-with-fee-scalars) in the Tune batcher costs guide. For more details on fee scalar, see [Transaction Fees, Ecotone section](/op-stack/transactions/fees#ecotone). #### Adjust fees to change margins As a chain operator, you may want to scale your scalar values up or down either because the throughput of your chain has changed and you are either filling significantly more or less of blobs, or because you wish to simply increase your margin to cover operational expenses. So, to increase or decrease your margin on L1 data costs, you would simply scale both the `l1baseFeeScalar` and the `l1blobBaseFeeScalar` by the same multiple. For example, if you wished to increase your margin on L1 data costs by \~10%, you would do: ``` newBaseFeeScalar = prevBaseFeeScalar * 1.1 newBlobBaseFeeScalar = prevBlobBaseFeeScalar * 1.1 ``` Once you have determined your ideal `BaseFeeScalar` and `BlobBaseFeeScalar`, you will need to apply those values for your chain. The first step is to encode both values into a single value to be set in your L1 Config: You can set your Scalar Values to send transaction to the L1 SystemConfigProxy.setGasConfigEcotone ```bash theme={null} cast send \ --private-key $GS_ADMIN_PRIVATE_KEY \ --rpc-url $ETH_RPC_URL \ \ "setGasConfigEcotone(uint32,uint32)" \ ``` Check that the gas price oracle on L2 returns the expected values for `baseFeeScalar` and `blobBaseFeeScalar` (wait \~1 minute): This is checked on L2, so ensure you are using an RPC URL for your chain. You'll also need to provide a `gas-price` to geth when making this call. ```shell theme={null} cast call 0x420000000000000000000000000000000000000F 'baseFeeScalar()(uint256)' --rpc-url YOUR_L2_RPC_URL ``` ```shell theme={null} cast call 0x420000000000000000000000000000000000000F 'blobBaseFeeScalar()(uint256)' --rpc-url YOUR_L2_RPC_URL ``` Now that the fee config has been updated, you should immediately configure your batcher! Your chain may be undercharging users during the time between updating the scalar values and updating the Batcher, so aim to do this immediately after. Steps to configure the batcher: * Configure `OP_BATCHER_DATA_AVAILABILITY_TYPE=blobs`. The batcher will have to be restarted for it to take effect. * Ensure your `OP_BATCHER_MAX_CHANNEL_DURATION` is properly set to maximize your fee savings. See [OP Batcher Max Channel Configuration](/chain-operators/guides/configuration/batcher#set-your--op_batcher_max_channel_duration) for more details. * Optionally, you can configure your batcher to support multi-blobs. See [Multi-Blob Batcher Configuration](/chain-operators/guides/configuration/batcher#configure-your-batcher-to-use-multiple-blobs) for more details. ## Switch back to using calldata As a chain operator, if the `blobBaseFee` is expensive enough and your chain is not processing enough transactions to meaningfully fill blobs within your configured batcher `OP_BATCHER_MAX_CHANNEL_DURATION`, you may wish to switch back to posting data to calldata. To judge whether your transactions will be cheaper as blobs or as calldata, compare the current blob base fee with the L1 base fee, or set `OP_BATCHER_DATA_AVAILABILITY_TYPE=auto` to let the batcher make the comparison automatically; see [Choose a data availability type](/use-cases/tune-batcher-costs#step-3-choose-a-data-availability-type) in the Tune batcher costs guide for the trade-offs. Chains can follow these steps to switch from blobs back to using calldata. If you are using calldata, then you can set your `BaseFeeScalar` similarly to how you would have set "scalar" prior to Ecotone, though with a 5-10% bump to compensate for the removal of the "overhead" component. For a walkthrough of sizing the scalars against your measured batcher spend, see [Recover the spend with fee scalars](/use-cases/tune-batcher-costs#step-5-recover-the-spend-with-fee-scalars) in the Tune batcher costs guide. Since the Pectra upgrade on L1, chains which exclusively use calldata DA need to scale up their BaseFeeScalar by 10/4. See [this notice](/notices/archive/pectra-changes). Chains can update their fees to increase or decrease their margin. If using calldata, then `BaseFeeScalar` should be scaled to achieve the desired margin. For example, to increase your L1 Fee margin by 10%: ``` BaseFeeScalar = BaseFeeScalar * 1.1 BlobBaseFeeScalar = 0 ``` To set your scalar values, follow the same process as laid out in [Update your Scalar values for Blobs](#update-your-scalar-values-for-blobs). Now that the fee config has been updated, you will want to immediately configure your batcher. Reminder, that your chain may be undercharging users during the time between updating the scalar values and updating the Batcher, so aim to do this immediately after. * Configure `OP_BATCHER_DATA_AVAILABILITY_TYPE=calldata`. The batcher will have to be restarted for it to take effect. * Ensure your `OP_BATCHER_MAX_CHANNEL_DURATION` is properly set to maximize savings. **NOTE:** While setting a high value here will lower costs, it will be less meaningful than for low throughput chains using blobs. See [OP Batcher Max Channel Configuration](/chain-operators/guides/configuration/batcher#set-your--op_batcher_max_channel_duration) for more details. ## Use auto DA mode in your batcher The batcher now supports automatically switching from blobs to calldata depending on which DA type is more affordable. This is an optimization which allows for a slightly better DA profit margin for your chain. To enable this mode, set `OP_BATCHER_DATA_AVAILABILITY_TYPE=auto`. ## Other considerations * For information on L1 Data Fee changes related to the Ecotone upgrade, visit the [Transaction Fees page](/op-stack/transactions/fees#ecotone). * If you want to enable archive nodes, you will need to access a blob archiver service. You can use [Optimism's](/op-mainnet/network-information/snapshots) or [run your own](/chain-operators/tools/explorer#create-an-archive-node). # Deploy a Custom Gas Token chain Source: https://docs.optimism.io/chain-operators/guides/features/custom-gas-token-guide Learn how to deploy a Custom Gas Token chain using OP Deployer. This guide provides instructions for chain operators who want to deploy a Custom Gas Token (CGT) chain. See the [Custom Gas Token overview](/op-stack/features/custom-gas-token) for a general understanding of this OP Stack feature. A Custom Gas Token chain enables you to use any asset as the native fee currency instead of ETH. This asset may be an existing L1 token, a representation of a token from another chain, or a newly defined asset (or new L2 token) created at genesis. Custom Gas Token v2 is a new implementation that is not compatible with legacy CGT chains. There is currently no migration path from legacy CGT to CGT v2, though one is planned to be put together. ## Prerequisites Before deploying a CGT chain, ensure you have: * **OP Deployer installed**: See [Install op-deployer](/chain-operators/tools/op-deployer/installation) for setup instructions * **L1 RPC endpoint**: Access to an Ethereum L1 node for deployment * **Funded deployer account**: ETH for L1 gas costs during deployment * **Token design**: Clear plan for your native asset (supply, distribution, bridging mechanism) * **Security audit**: Thorough review of any authorized minters or bridge contracts you plan to deploy ## Deployment steps Deploying a CGT chain follows the standard OP Stack deployment process with additional configuration for Custom Gas Token specific parameters. Create a new intent file using OP Deployer's [init command](/chain-operators/tools/op-deployer/usage/init): ```bash theme={null} op-deployer init \ --l1-chain-id \ --l2-chain-ids \ --intent-type custom ``` This creates an `intent.toml` file. Open your `intent.toml` file and add the Custom Gas Token configuration. Below is an example with CGT-specific fields: ```toml theme={null} configType = "custom" l1ChainID = 11155111 fundDevAccounts = false useInterop = false l1ContractsLocator = "tag://op-contracts/v6.0.0" l2ContractsLocator = "tag://op-contracts/v6.0.0" [superchainRoles] SuperchainProxyAdminOwner = "0xYourMultisigAddress" SuperchainGuardian = "0xYourMultisigAddress" Challenger = "0xYourMultisigAddress" [[chains]] id = "0x0000000000000000000000000000000000000000000000000000000000001234" baseFeeVaultRecipient = "0xYourFeeRecipientAddress" l1FeeVaultRecipient = "0xYourFeeRecipientAddress" sequencerFeeVaultRecipient = "0xYourFeeRecipientAddress" operatorFeeVaultRecipient = "0xYourFeeRecipientAddress" eip1559DenominatorCanyon = 0 eip1559Denominator = 0 eip1559Elasticity = 0 gasLimit = 60000000 operatorFeeScalar = 0 operatorFeeConstant = 0 minBaseFee = 0 daFootprintGasScalar = 0 [chains.roles] l1ProxyAdminOwner = "0xYourMultisigAddress" l2ProxyAdminOwner = "0xYourMultisigAddress" systemConfigOwner = "0xYourMultisigAddress" unsafeBlockSigner = "0xYourSequencerAddress" batcher = "0xYourBatcherAddress" proposer = "0xYourProposerAddress" challenger = "0xYourChallengerAddress" [chains.customGasToken] name = "My Custom Token" symbol = "MCT" initialLiquidity = "0x..." # optional, default: type(uint248).max liquidityControllerOwner = "0x..." # optional, default: L2ProxyAdminOwner ``` ### Key CGT configuration fields | Field | Description | Required | | -------------------------- | -------------------------------------------------------- | ----------------------------------------------- | | `name` | Name of the native asset (e.g., "My Custom Token") | Yes | | `symbol` | Symbol for the native asset (e.g., "MCT") | Yes | | `initialLiquiditySupply` | Initial supply minted to NativeAssetLiquidity at genesis | No, default: type(uint248).max | | `liquidityControllerOwner` | Manages the asset supply | No, `L2ProxyAdminOwner` will be used as default | **Fee parameter calculation is critical**: Your `minBaseFee` and `operatorFee` must accurately account for L1 gas costs and DA fees denominated in your custom token. If set too low, your chain may not cover operational costs. If set too high, users will pay excessive fees. **Decimal support**: CGT v2 currently supports only 18-decimal tokens. Support for other decimals may be added in future releases. Deploy your L1 contracts using OP Deployer's [apply command](/chain-operators/tools/op-deployer/usage/apply) ```bash theme={null} op-deployer apply \ --l1-rpc-url \ --private-key ``` This deploys all necessary L1 contracts including `SystemConfig` with the `isCustomGasToken` flag enabled, which instructs L1 contracts to reject ETH-value transactions. The deployment process will automatically deploy the CGT-specific predeploys (`NativeAssetLiquidity` and `LiquidityController`) during genesis initialization. Optionally you can use OP Deployer's [verify command](/chain-operators/tools/op-deployer/usage/verify) to verify your L1 contracts on Blockscout or Etherscan. After L1 deployment completes, initialize your L2 genesis with OP Deployer's [apply command](/chain-operators/tools/op-deployer/usage/apply): ```bash theme={null} op-deployer apply \ --deployment-target genesis ``` The genesis configuration is applied based on your `intent.toml`. Start your OP Stack services to start sequencing your CGT chain: * Sequencer Execution Client * Sequencer Consensus Client * Batcher * Proposer * Challenger Before going live, thoroughly test your CGT chain. The following are some key areas to check: **Verify flag alignment** * Check L1 SystemConfig.isCustomGasToken() returns true * Check L2 L1Block.isCustomGasToken() returns true * Verify both flags match **Test native asset operations** * Test minting native assets via authorized minter * Test burning native assets * Test fee payments in native token * Verify fee vault accumulation **Test ETH rejection** * Attempt ETH deposit via OptimismPortal (should fail) * Attempt ETH withdrawal via L2ToL1MessagePasser (should fail) * Verify ETH operations are properly blocked **Test bridge functionality** * Test deposits (L1 → L2 native asset minting) * Test withdrawals (L2 native → L1 token) * Verify proper locking/unlocking in liquidity contract ## Post-deployment considerations ### Supply management After deployment, you can: * **Withdraw excess liquidity**: If genesis created more supply than needed, withdraw and burn via `L2ToL1MessagePasser` * **Add new minters**: Authorize additional contracts to mint native assets as your ecosystem grows * **Revoke minters**: Remove authorization from compromised or deprecated contracts * **Implement rate limits**: Add safeguards to control minting velocity ### Fee parameter adjustments Monitor your chain's operational costs and adjust fee parameters as needed: * **minBaseFee**: Adjust based on L1 gas costs and your token's value, using `SystemConfig.setMinBaseFee()` * **operatorFee**: Adjust based on data availability costs, using `SystemConfig.setOperatorFeeScalars()` ### Developer documentation Create clear documentation for your users covering: * How to acquire native assets (bridge, DEX, faucet, etc.) * Bridge contract addresses and interfaces * Fee structure and token economics * Wallet configuration (RPC endpoints, chain ID, token metadata) ## Troubleshooting ### Flag mismatch errors **Symptom**: Transactions failing with "custom gas token mismatch" errors **Solution**: Verify that `SystemConfig.isCustomGasToken()` on L1 and `L1Block.isCustomGasToken()` on L2 return the same value. If mismatched, this indicates a critical configuration error. ### Fee parameter issues **Symptom**: Chain operator losing money on transaction costs or users complaining about excessive fees **Solution**: Review and recalculate your `minBaseFee` and `operatorFee` parameters based on: * Current L1 gas prices * Your token's market value or peg * Data availability costs * Target fee structure for users ### Liquidity depletion **Symptom**: Minting transactions failing due to insufficient liquidity **Solution**: * Check `NativeAssetLiquidity` balance * If depleted, this indicates an imbalance between minting and burning * Review bridge logic to ensure burns are occurring correctly * Consider increasing initial liquidity supply in future deployments ### Unauthorized minting attempts **Symptom**: Unauthorized addresses attempting to mint native assets **Solution**: * Review access control configuration on `LiquidityController` * Ensure only audited and secured contracts are authorized * Implement rate limiting if not already in place * Consider revoking and re-authorizing with additional safeguards ## Resources * [Custom Gas Token feature overview](/op-stack/features/custom-gas-token) * [OP Deployer documentation](/chain-operators/tools/op-deployer/overview) # Enable span batches Source: https://docs.optimism.io/chain-operators/guides/features/enable-span-batches Learn how to enable span batches on your OP Stack chain by confirming Delta activation and configuring the batch type on op-batcher. Span batches encode a span of consecutive L2 blocks in a single batch, reducing the overhead of batch submission. This is especially beneficial for sparse, low-throughput chains. The format was introduced in the Delta network upgrade, and chains opt into it through the `op-batcher` configuration. For background on what span batches are and why they exist, see [Span batches](/op-stack/features/span-batches). ## Before you begin Span batches are only valid once the Delta upgrade is active on your chain. The `op-node` derivation pipeline drops any span batch whose L1 origin predates Delta activation, logging `dropping span batch before Delta activation`. Do not enable span batches on the batcher before Delta is active on your chain. Verifier nodes will drop the span batches your batcher posts, so the data you pay to submit will not advance the safe chain. ## Enable span batches Delta activation is recorded as `delta_time` in your chain's rollup configuration (the `rollup.json` file passed to `op-node`). Delta is active once `delta_time` is set and the L2 block timestamp has passed that value. You can read it from the rollup configuration file directly, or query a running `op-node`: ```bash theme={null} cast rpc --rpc-url optimism_rollupConfig | jq .delta_time ``` If the result is a timestamp in the past, Delta is active. If it is `null`, Delta is not scheduled on your chain and must be activated first. For new chains, the `l2GenesisDeltaTimeOffset` deploy configuration parameter schedules Delta relative to genesis (`0` activates it at genesis) — see the [rollup deployment configuration reference](/chain-operators/reference/rollup-deployment-configuration). For Delta activation times on OP Mainnet and OP Sepolia, see [Network upgrades](/op-stack/protocol/network-upgrades). The `op-batcher` `--batch-type` flag (environment variable `OP_BATCHER_BATCH_TYPE`) selects the batch format: `0` for singular batches (the default) and `1` for span batches. Set it to `1` and restart the batcher: ```bash theme={null} --batch-type=1 ``` or, as an environment variable: ```bash theme={null} OP_BATCHER_BATCH_TYPE=1 ``` Optionally, `--max-blocks-per-span-batch` (`OP_BATCHER_MAX_BLOCKS_PER_SPAN_BATCH`) caps the number of L2 blocks added to a single span batch. The default is `0`, which means no maximum. See the [batcher configuration reference](/chain-operators/reference/batcher-configuration) for details on both flags. On startup, the batcher logs its channel configuration. Check the `Initialized channel-config` log line and confirm it reports `batch_type=1`: ```text theme={null} INFO [...] Initialized channel-config ... batch_type=1 ... ``` ## Revert to singular batches Singular batches remain valid after Delta, so you can switch back at any time by setting `--batch-type=0` (or unsetting `OP_BATCHER_BATCH_TYPE`, since `0` is the default) and restarting the batcher. ## Next steps * Learn what span batches are and how the format works in the [span batches explainer](/op-stack/features/span-batches). * Review the other batcher settings that affect cost and stability in [Configure the batcher](/chain-operators/guides/configuration/batcher). * Read the [span batches specification](https://specs.optimism.io/protocol/delta/span-batches.html?utm_source=op-docs\&utm_medium=docs) for the full format definition. # Set the DA Footprint Gas Scalar Source: https://docs.optimism.io/chain-operators/guides/features/setting-da-footprint Learn how to set a Data Availability (DA) Footprint on your OP-Stack Chain ## Overview | Parameter | Type | Default | Recommended | Units | | --------------------------------------------------------------------------------------------------------------- | ------ | ----------- | ----------- | ------------ | | `daFootprintGasScalar` | Number | `0` (`400`) | `400` | gas per byte | The default value of `0` is the same as setting the scalar to `400`. In order to effectively disable this feature, set the scalar to a very low value such as `1`. See the [specs for more detail](https://specs.optimism.io/protocol/jovian/l1-attributes.html). The `daFootprintGasScalar` controls the **Data Availability (DA) Footprint Block Limit** introduced in the [Jovian hardfork](https://docs.optimism.io/notices/upgrade-17), which caps the total amount of transaction data that can fit into a block based on a scaled estimate of its compressed size. The effective limit of estimated DA usage per block is `gasLimit / daFootprintGasScalar` bytes, so *increasing* the scalar *decreases* the limit, and vice versa. For how the DA footprint is calculated, why the limit exists, and how the default of `400` was chosen, see [How the DA footprint block limit works](/chain-operators/reference/da-footprint). ## Choose a value * If no limit is set, or the value 0 is set for the `daFootprintGasScalar` in the `SystemConfig`, the default value of `400` is used * In order to effectively disable this feature, set the scalar to a very low value such as `1`. * Setting the `daFootprintGasScalar` too high may exclude too many transactions from your blocks. * Setting the `daFootprintGasScalar` too low may prove ineffective at preventing batcher throttling or protecting against continuous DA heavy transactions. * When a chain's gas limit is changed, the DA footprint scales proportionally by design. However, if you want to retain the same absolute DA footprint limit, then you must also scale the `daFootprintGasScalar` accordingly. ## Update the `daFootprintGasScalar` The steps below explain how to update the `daFootprintGasScalar` parameter on-chain using the `SystemConfig` contract. The [SystemConfig](https://specs.optimism.io/protocol/system-config.html) contract stores configurable protocol parameters such as gas limits and fee settings.\ You can find its proxy address in the [state.json generated by op-deployer](https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/op-deployer-setup#deploy-l1-contracts). The [SystemConfig owner](/op-stack/protocol/privileged-roles) is the only address that can make these changes. To update the `daFootprintGasScalar`, call the following method on the `SystemConfig` contract: `setDAFootprintGasScalar(uint16 daFootprintGasScalar) external onlyOwner;` Example (using [cast](https://getfoundry.sh/cast/reference/cast/)) to double the scalar, so lower the effective DA usage limit by half: ```bash title="Cast" theme={null} cast send -r "setDAFootprintGasScalar(uint16)" 800 ``` After the transaction confirms, verify the current value by calling the following getter method on the `SystemConfig` contract: `function daFootprintGasScalar() external view returns (uint16);` Example (using [cast](https://getfoundry.sh/cast/reference/cast/)): ```bash title="cast" theme={null} cast call -r "daFootprintGasScalar()" ``` And on your L2 chain you can query the scalar at the [L1Block predeploy](https://specs.optimism.io/protocol/predeploys.html#l1block) to confirm the new scalar has been propagated to the chain: ```bash title="cast" theme={null} cast call -r 0x4200000000000000000000000000000000000015 "daFootprintGasScalar()" ``` ## Next steps * [How the DA footprint block limit works](/chain-operators/reference/da-footprint) — the calculation, the scalar's semantics, and the rationale for the default value. * [Fee parameters reference](/chain-operators/reference/fee-parameters) — the full set of fee-related `SystemConfig` parameters. ## References * [DA Footprint Configuration Spec](https://specs.optimism.io/protocol/jovian/system-config.html#da-footprint-configuration) * [Jovian Upgrade Spec](https://specs.optimism.io/protocol/jovian/overview.html) * [SystemConfig Contract Spec](https://specs.optimism.io/protocol/system-config.html) * [Design Doc](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/da-footprint-block-limit.md) # Set the Minimum Base Fee Source: https://docs.optimism.io/chain-operators/guides/features/setting-min-base-fee Learn how to set a minimum base fee on your OP-Stack Chain ## Overview | Parameter | Type | Default | Recommended | Max Allowed for Standard Chains | Units | | ----------------------- | ------ | ------------ | ----------- | ------------------------------- | ----- | | minBaseFee | Number | 0 (disabled) | 100,000 | 10,000,000,000 | wei | The Minimum Base Fee (`minBaseFee`) configuration was introduced in the [Jovian hardfork](https://docs.optimism.io/notices/upgrade-17). This feature allows chain operators to specify a minimum L2 base fee to which can help avoid excessively long priority fee auctions that can occur when the base fee falls too low. When [batcher-sequencer throttling is active](https://docs.optimism.io/chain-operators/guides/configuration/batcher#batcher-sequencer-throttling) for long enough and the minBaseFee isn't enabled (or is zero), the base fee can drop all the way down to 1 wei. It can take a long time to recover back to a stable base fee. The steps below explain how to update the `minBaseFee` parameter on-chain using the SystemConfig contract. Setting the `minBaseFee` too high may make transactions harder to include for users. ## How to Update the Minimum Base Fee The [SystemConfig](https://specs.optimism.io/protocol/system-config.html) contract stores configurable protocol parameters such as gas limits and fee settings.\ You can find its proxy address in the [state.json generated by op-deployer](https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/op-deployer-setup#deploy-l1-contracts). Note that the owner of the `SystemConfig` contract is the [System Config Owner address](/op-stack/protocol/privileged-roles), so this transaction must be sent from that address. To update the minimum base fee, call the following method on the `SystemConfig` contract: `setMinBaseFee(uint64 minBaseFee) external onlyOwner;` Example (using [cast](https://getfoundry.sh/cast/reference/cast/)): ```bash title="cast" theme={null} cast send "setMinBaseFee(uint64)" 100000 ``` After the transaction confirms, verify the current value by calling the following getter method on the `SystemConfig` contract: `function minBaseFee() external view returns (uint64);` Example (using [cast](https://getfoundry.sh/cast/reference/cast/)): ```bash title="cast" theme={null} cast call "minBaseFee()" ``` *** ## References * [Minimum Base Fee Configuration Spec](https://specs.optimism.io/protocol/jovian/system-config.html#minimum-base-fee-configuration) * [Jovian Upgrade Spec](https://specs.optimism.io/protocol/jovian/overview.html) * [SystemConfig Contract Spec](https://specs.optimism.io/protocol/system-config.html) * [Design Doc](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/minimum-base-fee.md) # Set the Operator Fee Source: https://docs.optimism.io/chain-operators/guides/features/setting-operator-fee Learn how to configure the operator fee on your OP Stack Chain ## Overview | Parameter | Default | Recommended | Type | | :-------------------- | :-----: | :------------- | :---------------------------- | | `operatorFeeScalar` | 0 | Chain-specific | uint32 scalar (scaled by 1e6) | | `operatorFeeConstant` | 0 | Chain-specific | uint64 scalar (wei) | The **Operator Fee** was introduced in the **[Isthmus upgrade](https://docs.optimism.io/notices/upgrade-14#operator-fee)** and modified in the **[Jovian upgrade](https://docs.optimism.io/notices/upgrade-17#breaking-changes)**.\ It allows OP Stack chain operators to charge an additional fee on transactions, on top of the **execution gas fee** (base fee + priority fee) and the **L1 data fee**. This mechanism gives operators two levers: * a **gas-proportional component** (`operatorFeeScalar`) that scales with gas used * a **flat component** (`operatorFeeConstant`) The operator fee is only applied on chains that have enabled the Isthmus upgrade. **Deposit transactions do not get charged operator fees.**\ For all deposit transactions, regardless of the operator fee configuration, the operator fee is always zero. *** ## Operator Fee Formula The operator fee is calculated using the following formula, depending on the active fork. **After Isthmus:** ```text theme={null} operatorFee = operatorFeeConstant + (operatorFeeScalar * gasUsed / 1e6) ``` **After Jovian:** ```text theme={null} operatorFee = operatorFeeConstant + (operatorFeeScalar × gasUsed × 100) ``` Setting operator fee values too high can significantly increase transaction costs and reduce user adoption. The operator fee directly impacts UX and competitiveness and should be adjusted conservatively. The default value for standard chains is 0, any other value is considered non-standard. *** ## How to Update the Operator Fee To update the operator fee parameters, call the following method on the `SystemConfig` contract from the `SystemConfigOwner`: `setOperatorFeeScalars(uint32 _operatorFeeScalar, uint64 _operatorFeeConstant) external onlyOwner;` Example using cast: ```bash title="cast" theme={null} cast send --rpc-url --private-key \ \ "setOperatorFeeScalars(uint32,uint64)" \ 500000 1000000000000 ``` After the transaction confirms, verify the current configuration by calling the following: `function operatorFeeScalar() view returns (uint32);`\ `function operatorFeeConstant() view returns (uint64);` Example using cast: ```bash title="cast" theme={null} cast call --rpc-url "operatorFeeScalar()" cast call --rpc-url "operatorFeeConstant()" ``` *** ## References * [Operator Fee Overview – OP Stack Fee Docs](https://docs.optimism.io/op-stack/transactions/fees#operator-fee-component) * [SystemConfig Operator Fee Parameter Configuration – OP Stack Specs](https://specs.optimism.io/protocol/isthmus/system-config.html#operator-fee-parameter-configuration) * [Isthmus Operator Fee Details – OP Stack Specs](https://specs.optimism.io/protocol/isthmus/exec-engine.html#operator-fee) # Using snap sync for chain operators Source: https://docs.optimism.io/chain-operators/guides/features/snap-sync Learn how to enable snap sync on your OP Stack chain. Snap sync significantly improves the experience of syncing an OP Stack node. On the consensus layer, `op-node` enables it with the `--syncmode=execution-layer` flag. Rather than re-executing every block from genesis, the execution client downloads chain and state data from other nodes on the network over P2P and begins executing from the completed state. This means that performing a snap sync is significantly faster than performing a full sync. * Snap sync enables node operators on your network to sync faster. * Snap sync removes the need for nodes on your post Ecotone network to run a [blob archiver](/node-operators/guides/management/blobs). ## Enable snap sync for chains To enable snap sync, chain operators need to spin up a node which is exposed to the network and has transaction gossip disabled. This node will serve snap sync requests on the execution layer from other nodes on the network. For snap sync, all nodes should expose port `30303` TCP and `30303` UDP to easily find other nodes to sync from. These are op-reth's defaults for `--port` (TCP) and `--discovery.port` (UDP). * If you set the port with [`--discovery.port`](/node-operators/op-reth/cli/op-reth/node), then you must open the port specified for UDP. * If you set [`--port`](/node-operators/op-reth/cli/op-reth/node), then you must open the port specified for TCP. * The only exception is for sequencers and transaction ingress nodes. * Expose port `30303` (op-reth's default listening and discovery port) to the internet on TCP and UDP. * Disable transaction gossip with the [`--rollup.disable-tx-pool-gossip`](/node-operators/op-reth/cli/op-reth/node) flag * See the [sync modes reference](/node-operators/reference/consensus-layer-sync) for how node operators enable snap sync (execution-layer sync) on your chain network. # Enabling Subblocks Source: https://docs.optimism.io/chain-operators/guides/features/subblocks-guide Learn about enabling Subblocks on an OP Stack chain. Subblocks replace Flashblocks. Flashblocks are no longer officially supported on OP Stack chains. Subblocks are a private feature available only to OP Enterprise customers. If you are interested in becoming an OP Enterprise customer, [contact the OP Enterprise team](https://optimism.io/learn-more). See [this explainer on Subblocks](/op-stack/features/subblocks) for more details. # Switch to Kona Proofs Source: https://docs.optimism.io/chain-operators/guides/features/switching-to-kona-proofs Learn how to switch your OP Stack chain to use Kona-based fault proofs as the respected game type. [Upgrade 18](/notices/archive/upgrade-18) (approved by Optimism Governance) introduced `CANNON_KONA` (8) as an available game type alongside `CANNON` (0). [Upgrade 19](/notices/archive/upgrade-19) promotes `CANNON_KONA` to the **respected game type** for chains managed by the Optimism Security Council — meaning it is applied automatically as part of the onchain upgrade. Non-managed chains that want to switch must follow this guide. ## Overview | Parameter | Type | Current (typical) | Target when switching | Notes | | ----------------------- | ------- | ----------------- | --------------------- | --------------------------------------------------- | | Respected game type | Enum | `CANNON` (0) | `CANNON_KONA` (8) | Determines which game type is used for withdrawals | | `OP_PROPOSER_GAME_TYPE` | Number | 0 | 8 | Proposer game type (must match respected game type) | | `cannonPrestate` | Bytes32 | Set | Set | Must be a valid `cannon64` prestate hash | | `cannonKonaPrestate` | Bytes32 | Set | Set | Must be a valid `cannon64-kona` prestate hash | Kona proofs use the `kona-client` fault proof program, which is a combination of `kona-node` and `op-reth`. It replaces `op-program` (a combination of `op-node` and `op-geth`), which has reached end-of-support and does not support the Karst hardfork. See [End of Support for op-geth and op-program](/notices/archive/op-geth-deprecation). Both programs: * Use Cannon as the FPVM, and * Are used by the same dispute game implementation (`FaultDisputeGame.sol`). After the cannon+kona upgrade is deployed, both game types are available: * `CANNON` (0): `op-program` (end-of-support) * `CANNON_KONA` (8): `kona-client` Until you switch, the respected game type remains `CANNON` (0), meaning only those games are used for withdrawals. Because `op-program` does not support Karst, complete this switch before activating the Karst hardfork on your chain. This guide explains how to switch your chain so that Kona proofs (`CANNON_KONA`, 8) become the respected game type. This guide assumes you have already completed the cannon+kona upgrade, including setting both `cannonPrestate` and `cannonKonaPrestate` in `OpChainConfig`, and that your fault proof infrastructure is healthy. The high-level flow is: * Verify that cannon+kona support is correctly deployed on-chain. * Confirm that your off-chain infra (especially `op-challenger`) is Kona-ready. * Switch the respected game type to `CANNON_KONA` (8). * Update `op-proposer` to post Kona games. * Monitor the system. *** ## How to Switch to Kona Proofs Before changing the respected game type, verify that your chain has been upgraded to support both `CANNON` and `CANNON_KONA` games. The required upgrade is performed via `OPCM.upgrade` with an `OpChainConfig` that sets both `cannonPrestate` and `cannonKonaPrestate`. 1. **Check `OpChainConfig` prestates** Ensure that the `OpChainConfig` used in your most recent upgrade included: * `cannonPrestate` pointing to a valid `cannon64` prestate. * `cannonKonaPrestate` pointing to a valid `cannon64-kona` prestate. Both hashes must come from the standard prestates in the superchain registry and must embed an up-to-date chain config for your chain. 2. **Verify `DisputeGameFactory` implementations** After the cannon+kona upgrade, the `DisputeGameFactory` should have: * A non-zero implementation for `CANNON` (0), and * A non-zero implementation for `CANNON_KONA` (8). Example (using [cast](https://getfoundry.sh/cast/reference/cast/)): ```bash title="cast" theme={null} # CANNON (0) implementation cast call "gameImpl(uint8)" 0 # CANNON_KONA (8) implementation cast call "gameImpl(uint8)" 8 ``` Both calls should return non-zero addresses. Your challengers must be able to play both cannon and kona games before you change the respected game type. 1. **Trace types** If you explicitly configure trace types, ensure that `cannon-kona` is included. A typical setting is: ```bash theme={null} OP_CHALLENGER_TRACE_TYPE="cannon,cannon-kona,permissioned" # or --trace-type=cannon,cannon-kona,permissioned ``` 2. **Prestate URLs** Make sure `op-challenger` can fetch both cannon and cannon-kona prestates: * If they are at the same URL, use: ```bash theme={null} --prestates-url= ``` * If they are at different locations, use: ```bash theme={null} --cannon-prestates-url= --cannon-kona-prestates-url= ``` 3. **Kona host binary** For operators not using the standard OP Labs `op-challenger` Docker images, you must also provide: ```bash theme={null} --cannon-kona-server=/path/to/kona-host # or OP_CHALLENGER_CANNON_KONA_SERVER=/path/to/kona-host ``` The `kona-host` binary is available from the Kona repository (for example under `bin/host`). Build it from the same release as the `cannon-kona` prestate you configured. Once both on-chain and off-chain pieces are ready, you can switch the respected game type so that Kona proofs become the canonical path for withdrawals. Changing the respected game type affects which games can be used to prove withdrawals. Only perform this step once you are confident in your Kona setup. The respected game type is configured in the `AnchorStateRegistry` contract. 1. **Encode the calldata** Use `cast calldata` to encode a call to `setRespectedGameType(uint32)` with game type `8` (which corresponds to `CANNON_KONA`): ```bash title="cast" theme={null} CALLDATA=$(cast calldata "setRespectedGameType(uint32)" 8) ``` 2. **Send the transaction** Send the transaction from the Guardian to the `AnchorStateRegistry`: ```bash title="cast" theme={null} cast send \ --rpc-url \ --private-key \ \ "$CALLDATA" ``` 3. **Verify the new respected game type** After the transaction confirms, verify that the respected game type is now `8`: ```bash title="cast" theme={null} cast call \ --rpc-url \ \ "respectedGameType()(uint32)" ``` The returned value should be `8`, indicating that `CANNON_KONA` is now the respected game type. With `CANNON_KONA` set as the respected game type, your proposers must create Kona games. 1. **Update the proposer game type** Change your `op-proposer` configuration from game type 0 to 8: ```bash theme={null} # Before OP_PROPOSER_GAME_TYPE=0 # or --game-type=0 # After switching to Kona OP_PROPOSER_GAME_TYPE=8 # or --game-type=8 ``` This change is not required as part of the initial cannon+kona upgrade; it is only required when you actually switch the respected game type to `CANNON_KONA`. 2. **Restart proposers** Restart your proposer processes so they pick up the new configuration. Verify in logs and metrics that they are now using game type 8. After switching to Kona proofs, closely monitor your chain to ensure everything is functioning as expected. 1. **Run test withdrawals** * Perform a few small test withdrawals and ensure that: * New fault dispute games are created with game type `CANNON_KONA` (8). * Your challengers are responding correctly using `kona-host`. 2. **Observe metrics and logs** * Monitor `op-proposer` and `op-challenger` logs for errors. * Watch dispute game metrics (for example, game counts and step timings) for anomalies. *** ## References * [OP Stack Fault Proofs Explainer](https://docs.optimism.io/op-stack/fault-proofs/explainer) * [Fault Proof Specs](https://specs.optimism.io/fault-proof/index.html) # Join the Superchain Registry Source: https://docs.optimism.io/chain-operators/guides/join-superchain-registry How to add your OP Stack chain to the Superchain Registry — prerequisites, config generation, and the pull-request process. The [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry) is the source-of-truth index of who is in the OP Stack Ecosystem and how each chain is configured. This guide walks you through adding your chain. The registry repo's [operations documentation](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md) is the canonical reference for every step below — each step links the matching section, and if this page and that document ever disagree, the registry repo wins. Joining gets you more than a listing: once your chain is in the registry, its config is embedded in downstream releases of `op-node` and `op-geth`, so nodes can join your network with the `--network` / `--op-network` flags and can inherit Superchain-wide hardfork activations automatically. See the [superchain-registry explainer](/op-stack/protocol/superchain-registry) for how that works. ## Before You Start * **Chat with the Optimism Foundation.** * **Your chain ID must be registered at [ethereum-lists/chains](https://github.com/ethereum-lists/chains).** The registry's validation suite checks against it; this is a mandatory prerequisite ([ops.md](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#adding-a-chain)). * **Standard chains must be deployed with [op-deployer](/chain-operators/tools/op-deployer/overview).** A chain is only considered standard in the registry if it was deployed with op-deployer, which also produces the `state.json` file the registry tooling consumes ([ops.md](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#0-standard-chains-deploy-your-chain-with-op-deployer)). Chains deployed another way follow the [custom-chain path](#custom-chains) below. * **Install the tooling dependencies:** `git` (`^2`), `go` (`^1.21`), and [`just`](https://github.com/casey/just) (`^1.28.0`) ([ops.md](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#1-install-dependencies)). ## Add Your Chain You will raise a pull request from your fork to the upstream repo. Start from a fresh, non-protected branch (not your fork's `main`), and add one chain per branch and PR. ([ops.md](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#2-fork-this-repository)) From the root of the registry repo, run: ```bash theme={null} just create-config ``` where `` is your chain's short name (for example `op`) and the state file is the `state.json` produced by op-deployer. This writes two files to the `.staging` directory: `.toml` and `.json.zst`. If you deployed with custom contracts, pass your op-deployer version as a third argument — supported values live in the registry's `versions.json`. ([ops.md](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#3-generate-a-config-from-your-state-file)) Most of `.toml` is populated from your deployer state, but you must fill in the rest yourself: `name`, `superchain` (`mainnet` or `sepolia`), `public_rpc`, `sequencer_rpc`, `explorer`, and `deployment_tx_hash`. Double-check the generated values while you are in the file. ([ops.md](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#4-update-generated-config)) Commit to your fork and open one PR per chain. Check the box to [allow edits from maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so reviewers can push to your branch. Automated checks will validate your chain and generate a report on its compliance with the standard blockchain charter. ([ops.md](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#5-commit)) A registry maintainer reviews your PR. When it is ready, the team generates code from your PR and pushes to your fork — do not run codegen yourself; it slows down review. ([ops.md](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#6-await-review)) ## Custom Chains If your chain was not deployed with op-deployer (for example, a heavily modified deployment), you must write the config file by hand instead of generating it: copy the example config into `.staging`, substitute every field for your chain (custom chains set `superchain_level = 0` and `governed_by_optimism = false`), and ZST-encode your genesis file with the registry's dictionary. The full field-by-field walkthrough lives in [Adding a custom chain](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#adding-a-custom-chain). ## After You Are In To receive Superchain-wide coordinated hardfork activations automatically, set `superchain_time` in your chain's config (use `0` if your chain has activated all Superchain forks up to its genesis time) and run your nodes with the network flags. Details in the [explainer](/op-stack/protocol/superchain-registry#hard-fork-activation-inheritance-behavior) and the registry's [hardfork activation inheritance spec](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/hardfork-activation-inheritance.md). ## Next Steps * [The superchain-registry explainer](/op-stack/protocol/superchain-registry) * [Deploy your chain with op-deployer](/chain-operators/tools/op-deployer/overview) * [Registry operations documentation](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md) (canonical) # Chain operator best practices Source: https://docs.optimism.io/chain-operators/guides/management/best-practices Learn some best practices for managing the OP Stack's off-chain components. The following information has some best practices around running the OP Stack's off-chain components. ## Correct release versions Chain and node operators should always run the latest production releases of the OP Stack's off-chain components. The latest notes and changelogs can be found on GitHub: * [OP monorepo releases](https://github.com/ethereum-optimism/optimism/releases) (includes `op-node` and other Go-based OP components) * [op-geth releases](https://github.com/ethereum-optimism/op-geth/releases) (standalone repository) * [op-contracts releases](https://github.com/ethereum-optimism/optimism/releases) (look for tags starting with `op-contracts/`) Some guidelines when picking versions: * **Production releases** are always tagged with `/v` for a specific OP component, for example: * `op-node/v1.7.5` for the `op-node` * `op-challenger/v1.0.0` for the `op-challenger` * **Monorepo releases** typically use a simple `v` format (e.g. `v1.7.7`) to indicate that all Go-based OP Stack components (in `op-*`) have been updated together. These do **not** include new L1 contract releases. * **Contracts releases** are tagged under `op-contracts/v` (e.g. `op-contracts/v1.6.0`) and contain updates to the Bedrock L1 contracts. * **`op-geth` versioning** includes upstream geth's version within its semver. For example, if upstream geth is at `v1.12.0`, an `op-geth` release might be `v1.101200.0`. The geth major version is used as our minor version (left-padded if needed), and the patch version is appended. Always consult release notes for additional details or upgrade instructions. ## Keep deployment artifacts After deploying your contracts on Ethereum, you should keep a record of all the deployment artifacts. This is will be all the [op-deployer](/chain-operators/tools/op-deployer/overview.mdx) artifacts, as well as the release tag and commit hash of `op-deployer` and `op-contracts`. You will need these artifacts to add your chain to the [Superchain Registry](/op-stack/protocol/superchain-registry). ## Incremental upgrade rollouts When upgrading your nodes, take a staggered approach. This means deploying the upgrade gradually across your infrastructure and ensuring things work as expected before making changes to every node. ## Isolate your sequencer You can isolate your sequencer node, by not connecting it directly to the internet. Instead, you could handle your ingress traffic behind a proxy. Have the proxy forward traffic to replicas and have them gossip the transactions internally. ## Improve reliability of peer-to-peer transactions These flags can improve the reliability of peer-to-peer transactions from internal replica nodes and the sequencer node. For sequencer nodes: ``` GETH_TXPOOL_JOURNAL: "" GETH_TXPOOL_JOURNALREMOTES: "false" GETH_TXPOOL_NOLOCALS: "true" ``` For replica nodes: ``` GETH_TXPOOL_JOURNALREMOTES: "true" GETH_TXPOOL_LIFETIME: "1h" GETH_TXPOOL_NOLOCALS: "true" ``` For additional information about these flags, check out our [Execution Layer Configuration Options](/node-operators/reference/op-reth-config) doc. ## Write your own runbooks Create custom runbooks to prepare for operating an OP Stack chain. You'll want to setup metrics endpoints and monitoring on your key components of the system and create runbooks to execute when something is not behaving as expected. ## Assumptions ### op-proposer assumes archive mode The `op-proposer` currently assumes that `op-geth` is being run in archive mode. This will likely be updated in a future network upgrade, but it is necessary for L2 withdrawals at the moment. **Running this in production** # Fee vault operations Source: https://docs.optimism.io/chain-operators/guides/management/fee-vaults How to configure, monitor, and withdraw from fee vaults on your OP Stack chain. This guide covers the operational aspects of managing fee vaults on your OP Stack chain. For a conceptual overview of how fee vaults work, see [Fee vaults](/op-stack/transactions/fee-vaults). ## Prerequisites * Access to the **ProxyAdminOwner** account (required for configuration changes) * An RPC endpoint for your L2 chain * `cast` CLI tool installed ([Foundry](https://book.getfoundry.sh/getting-started/installation)) ## Fee vault addresses | Vault | Address | Collects | Introduced | | ------------------- | -------------------------------------------- | ---------------------------- | ---------- | | `SequencerFeeVault` | `0x4200000000000000000000000000000000000011` | Priority fees (tips) | Legacy | | `BaseFeeVault` | `0x4200000000000000000000000000000000000019` | Base fees (not burned on L2) | Bedrock | | `L1FeeVault` | `0x420000000000000000000000000000000000001A` | L1 data fees | Bedrock | | `OperatorFeeVault` | `0x420000000000000000000000000000000000001B` | Operator fees | Isthmus | ## Checking vault state ### View current balance ```bash theme={null} export L2_RPC= export VAULT= cast balance $VAULT --rpc-url $L2_RPC ``` ### View configuration ```bash theme={null} # Recipient address cast call $VAULT "recipient()" --rpc-url $L2_RPC # Minimum withdrawal amount (in wei) cast call $VAULT "minWithdrawalAmount()" --rpc-url $L2_RPC # Withdrawal network (0 = L1, 1 = L2) cast call $VAULT "withdrawalNetwork()" --rpc-url $L2_RPC # Total ETH withdrawn historically cast call $VAULT "totalProcessed()" --rpc-url $L2_RPC ``` ## Updating configuration Configuration changes require the **ProxyAdminOwner** account. If your chain uses a multisig as the ProxyAdminOwner, these calls must be executed through the multisig. ### Set recipient ```bash theme={null} export L2_RPC= export VAULT= export PK= cast send --rpc-url $L2_RPC --private-key $PK \ $VAULT "setRecipient(address)" ``` ### Set minimum withdrawal amount ```bash theme={null} cast send --rpc-url $L2_RPC --private-key $PK \ $VAULT "setMinWithdrawalAmount(uint256)" ``` ### Set withdrawal network ```bash theme={null} # 0 = L1, 1 = L2 cast send --rpc-url $L2_RPC --private-key $PK \ $VAULT "setWithdrawalNetwork(uint8)" <0_OR_1> ``` ## Withdrawing fees Withdrawals are **permissionless** — anyone can trigger them once the vault balance meets the minimum threshold. ### Trigger a withdrawal ```bash theme={null} cast send --rpc-url $L2_RPC --private-key $PK \ $VAULT "withdraw()" ``` This withdraws the **entire vault balance** to the configured recipient. ### Withdrawal behavior by network * **L2 withdrawal (`withdrawalNetwork = 1`)**: Funds are transferred immediately to the recipient on L2. The transaction completes in a single step. * **L1 withdrawal (`withdrawalNetwork = 0`)**: An L2-to-L1 withdrawal is initiated via the `L2ToL1MessagePasser`. After calling `withdraw()`, you must still: 1. Wait for the withdrawal to be included in an L2 output root 2. Prove the withdrawal on L1 3. Wait for the finalization period 4. Finalize the withdrawal on L1 For details on completing L1 withdrawals, see [Withdrawal flow](/op-stack/bridging/withdrawal-flow). ## Initial configuration during deployment Fee vault recipients, minimum withdrawal amounts, and withdrawal networks are configured during chain deployment with `op-deployer`. For details on setting these parameters, see the [op-deployer setup guide](/chain-operators/tutorials/create-l2-rollup/op-deployer-setup). ## Monitoring It's good practice to monitor your fee vaults regularly: * **Vault balances**: Track balances to know when withdrawals can be triggered. * **`totalProcessed`**: Monitor cumulative withdrawals over time to understand revenue trends. ## Next steps * Read the [fee vaults explainer](/op-stack/transactions/fee-vaults) to understand how vaults work at the protocol level. * See [Transaction Fees 101](/chain-operators/guides/management/transaction-fees-101) to learn how to tune fee parameters. * Review [fee components and formulas](/op-stack/transactions/fees) for detailed fee calculations. # Changing gas target/limit Source: https://docs.optimism.io/chain-operators/guides/management/gas-target-limit Learn how to change the gas target and limit on your OP Stack chain. This guide covers how to optimize block processing performance at higher gas limits, test your infrastructure before activation, and safely change the gas target and/or limit on a live chain. This guide assumes your OP Stack chain has the [Holocene features](/notices/archive/holocene-changes) activated. ## Recommended config for best performance Some known ways to improve block processing performance: * **Use NVMe for storage** instead of local SSDs or other persistent disks * **Use full nodes where possible** over archive nodes ## Pre-activation testing To ensure your chain and supporting infrastructure can consistently process blocks up to your gas limit, you should run some performance tests. You'll want to run benchmarks and perform careful analysis of the results to ensure your execution clients can handle the increased gas usage. ## Changing the gas target/limit change How to change the gas target/limit on a live chain. ### Relevant configuration parameters The gas configuration on an OP Stack chain use the same EIP-1559 parameters as Ethereum. Where the **gas target** = **gas limit** / **elasticity**. These values can be found in the `SystemConfig` contract. ### Procedure Holocene introduces the ability to change the EIP-1559 parameters `elasticity` and `denominator` via the `SystemConfig`. This will allow you to set proper values for the `elasticity` and block `gasLimit`. **Example**: to double the *target* while keeping the block *limit* at 30Mgas/block: Retrieve the existing `eip1559Elasticity` and `eip1559Denominator` values: ```solidity theme={null} elasticity = SystemConfig.eip1559Elasticity() // 6 denominator = SystemConfig.eip1559Denominator() // 50 limit = SystemConfig.gasLimit() // 30_000_000 gas, 30Mgas ``` Current target = `30Mgas / 6 = 5Mgas per block` Use value from previous step as input to set new params and reduce the `elasticity` from `6` to `3`: ```solidity theme={null} SystemConfig.setEIP1559Params(denominator, 3) ``` New target = `30Mgas / 3 = 10Mgas per block` ## Post-activation monitoring What to monitor after executing the gas changes. ### SystemConfig contract values * `SystemConfig.gasLimit()` * `SystemConfig.eip1559Denominator()` * `SystemConfig.eip1559Elasticity()` ### Block explorer For example, on [OP Mainnet](https://optimistic.etherscan.io/blocks): * Any block with `gasUsed > gasTarget` should cause the base fee to increase * Any block with `gasUsed < gasTarget` should cause the base fee to decrease ### Node performance * Verify nodes are processing blocks faster than the block period * Monitor CPU/memory usage and p99 tail latency of block processing # Key management Source: https://docs.optimism.io/chain-operators/guides/management/key-management Understand the key management considerations for a chain's privileged roles: which keys must stay online as hot wallets, which belong in cold wallets, and where HSMs and multisigs fit. This page explains the key management considerations behind the privileged roles on your chain. There are certain [privileged roles](/op-stack/protocol/privileged-roles) that need careful consideration. The privileged roles are categorized as hot wallets or cold wallets. ## Hot wallets The addresses for the `Batcher` and the `Proposer` need to have their private keys online somewhere for a component of the system to work. If these addresses are compromised, the system can be exploited. It is up to the chain operator to make the decision on how they want to manage these keys. One suggestion is to use a Hardware Security Module (HSM) to provide a safer environment for key management. Cloud providers oftentimes provide Key Management Systems (KMS) that can work with your developer operations configurations. This can be used in conjunction with the `eth_signTransaction` RPC method. You can take a look at the signer client [source code](https://github.com/ethereum-optimism/optimism/blob/develop/op-service/signer/client.go) if you're interested in what's happening under the hood. ## Cold wallets The addresses for the cold wallets cannot be used without human intervention. These can be set up as multisig contracts, so they can be controlled by groups of community members and avoid a single point of failure. The signers behind a multisig should probably also use a hardware wallet. Refer to the [privileged roles](/op-stack/protocol/privileged-roles) documentation for more information about these different addresses and their security concerns. # Network Design Example Source: https://docs.optimism.io/chain-operators/guides/management/network-architecture This document describes an example network configuration for an OP Stack chain deployment. This document describes an example configuration for an OP Stack network deployment, focusing on the network architecture and node configuration required for production usage. OP Stack network design example (op-reth) ## Sequencers Sequencers receive transactions from the Tx Ingress Nodes via execution-layer p2p gossip and work with the batcher and proposer to create new blocks. ### Node Configuration * **Sequencer op-reth** can be either full or archive. op-reth runs as an archive node by default; pass `--full` to run a (pruned) full node. Full nodes offer better performance but can't recover from deep L1 reorgs, so run at least one archive sequencer as a backup. * **Sequencer op-node** should have p2p discovery disabled and only be statically peered with other internal nodes (or use [peer-management-service](https://github.com/ethereum-optimism/infra/tree/main/peer-mgmt-service) to define peering network). * The **op-conductor** RPC can act as a leader-aware RPC proxy for op-batcher (proxies the necessary op-reth / op-node RPC methods if the node is the leader). * Sequencers should have local transaction backup (journalling) disabled. ### op-node Configuration ```yaml theme={null} OP_NODE_P2P_NO_DISCOVERY: "true" OP_NODE_P2P_PEER_BANNING: "false" OP_NODE_P2P_STATIC: "" ``` ### op-reth Configuration op-reth is configured via CLI flags rather than `GETH_*` environment variables: ```sh theme={null} # Leave --rollup.disable-tx-pool-gossip unset so transactions are gossiped to the internal network --txpool.disable-transactions-backup # disable local transaction backup/journalling --txpool.lifetime 3600 # 1h, in seconds --txpool.nolocals --netrestrict "10.0.0.0/8" # ex: restrict p2p to internal ips ``` ## Tx Ingress Nodes These nodes receive `eth_sendRawTransaction` calls from the public and then gossip the transactions to the internal execution-layer network. This allows the Sequencer to focus on block creation while these nodes handle transaction ingress. ### Node Configuration * These can be either full or archive nodes. * They participate in the internal tx pool p2p network to forward transactions to sequencers. ### Configuration ```sh theme={null} # Leave --rollup.disable-tx-pool-gossip unset so transactions are gossiped to sequencers --txpool.disable-transactions-backup --txpool.lifetime 3600 # 1h, in seconds --txpool.nolocals --netrestrict "10.0.0.0/8" # ex: restrict p2p to internal ips ``` ## Archive RPC Nodes We recommend setting up some archive nodes for internal RPC usage, primarily used by the challenger, proposer, and security monitoring tools like [monitorism](/chain-operators/tools/chain-monitoring#monitorism). ### Node Configuration * Archive nodes are essential for accessing historical state data. * You can also use these nodes for taking disk snapshots for disaster recovery. ### Configuration op-reth runs as an archive node by default, so no extra flags are required — simply do **not** pass `--full` or `--minimal` (both enable pruning). op-reth stores state in MDBX plus static files, so the geth-specific `GETH_DB_ENGINE` and `GETH_STATE_SCHEME` options have no equivalent. ```sh theme={null} # op-reth is archive by default; no pruning flags needed. ``` ## Full Nodes These nodes run as full (pruned) nodes. op-reth does not implement geth-style snap sync; it syncs using its own staged-sync pipeline, so the geth `GETH_SYNCMODE`, `GETH_DB_ENGINE`, and `GETH_STATE_SCHEME` options do not apply. ### Configuration ```sh theme={null} --full # run a pruned full node (or --minimal for maximum pruning) ``` ## P2P Bootnodes (Execution Layer) These bootnodes facilitate peer discovery for public op-reth nodes. ### Node Configuration * The bootnode can be an op-reth instance or the [geth bootnode tool](https://etclabscore.github.io/core-geth/core/alltools/). * You may want to make your Full Nodes serve as your bootnodes as well. ## P2P Bootnodes (Consensus Layer) These are the op-node p2p network bootnodes. We recommend using the [geth bootnode tool](https://etclabscore.github.io/core-geth/core/alltools/) with discovery v5 enabled. ## Public RPC Public RPC design is not listed in the above diagram but can be implemented very similarly to Tx Ingress Nodes, with the following differences: ### Configuration Differences * Public RPC should **not** participate in the internal tx pool p2p network. * While it is possible to run Public RPC from the same nodes that serve Tx Ingress and participate in tx pool gossip, there have been execution-client bugs in the past that leaked tx pool details on read RPCs, so it is a possible risk to consider. * Public RPC [proxyd](https://github.com/ethereum-optimism/infra/tree/main/proxyd) should be run in `consensus_aware` routing mode and whitelist any RPCs you want to serve from op-reth. * Public RPC nodes should likely be archive nodes. ### About proxyd Proxyd is an RPC request router and proxy that provides the following capabilities: 1. Whitelists RPC methods. 2. Routes RPC methods to groups of backend services. 3. Automatically retries failed backend requests. 4. Tracks backend consensus (latest, safe, finalized blocks), peer count and sync state. 5. Re-writes requests and responses to enforce consensus. 6. Load balances requests across backend services. 7. Caches immutable responses from backends. 8. Provides metrics to measure request latency, error rates, and the like. ## Next steps * Learn more about using [proxyd](https://github.com/ethereum-optimism/infra/tree/main/proxyd) for your network. # Rollup operations Source: https://docs.optimism.io/chain-operators/guides/management/operations Learn basics of rollup operations, such as how to start and stop your rollup, get your rollup config, and how to add nodes. This guide reviews the basics of rollup operations, such as how to start your rollup, stop your rollup, get your rollup config, and add nodes. ## Stopping your rollup An orderly shutdown is done in the reverse order to the order in which components were started: ```sh theme={null} curl -d '{"id":0,"jsonrpc":"2.0","method":"admin_stopBatcher","params":[]}' \ -H "Content-Type: application/json" http://localhost:8548 | jq ``` This way the batcher knows to save any data it has cached to L1. Wait until you see `Batch Submitter stopped` in batcher's output before you stop the process. To stop the proposer, terminate the process directly. This can be done by: * Pressing **Ctrl+C** in the terminal running the process * Using system commands like `kill -TERM ` to stop the process gracefully Ensure that the proposer process has terminated completely before proceeding to stop other components. This component is stateless, so you can just stop the process. Use **CTRL-C** (SIGINT) so the execution client shuts down gracefully and flushes its database. Killing the process abruptly can leave the database in an inconsistent state and cause problems on the next start. ## Starting your rollup To restart the blockchain, use the same order of components you did when you initialized it. If `op-batcher` is still running and you just stopped it using RPC, you can start it with this command: ```sh theme={null} curl -d '{"id":0,"jsonrpc":"2.0","method":"admin_startBatcher","params":[]}' \ -H "Content-Type: application/json" http://localhost:8548 | jq ``` Start the proposer using the appropriate command. Here's an example: ```sh theme={null} ./bin/op-proposer \ --poll-interval=12s \ --rpc.port=8560 \ --rollup-rpc=http://localhost:8547 \ --l2oo-address=0xYourL2OutputOracleAddress \ --private-key=$PROPOSER_PRIVATE_KEY \ --l1-eth-rpc=$L1_RPC_URL ``` | Parameter | Description | | ------------- | -------------------------------------------------------------- | | poll-interval | How often to check for new output proposals (recommended: 12s) | | rpc.port | Local RPC port for the proposer service | | l2oo-address | The L2 Output Oracle contract address (0x-prefixed hex) | | private-key | Private key for signing proposals | | l1-eth-rpc | L1 network RPC endpoint URL | Synchronization takes time `op-batcher` might have warning messages similar to: ``` WARN [03-21|14:13:55.248] Error calculating L2 block range err="failed to get sync status: Post \"http://localhost:8547\": context deadline exceeded" WARN [03-21|14:13:57.328] Error calculating L2 block range err="failed to get sync status: Post \"http://localhost:8547\": context deadline exceeded" ``` This means that `op-node` is not yet synchronized up to the present time. Just wait until it is. ## Getting your rollup config Use this tool to get your rollup config from `op-node`. This will only work if your chain is **already** in the [superchain-registry](https://github.com/ethereum-optimism/superchain-registry/blob/main/chainList.json) and `op-node` has been updated to pull those changes in from the registry. This script will NOT work for chain operators trying to generate this data in order to submit it to the registry. You'll need to run this tool: ``` ./bin/op-node networks dump-rollup-config --network=op-sepolia { "genesis": { "l1": { "hash": "0x48f520cf4ddaf34c8336e6e490632ea3cf1e5e93b0b2bc6e917557e31845371b", "number": 4071408 }, "l2": { "hash": "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", "number": 0 }, "l2_time": 1691802540, "system_config": { "batcherAddr": "0x8f23bb38f531600e5d8fddaaec41f13fab46e98c", "overhead": "0x00000000000000000000000000000000000000000000000000000000000000bc", "scalar": "0x00000000000000000000000000000000000000000000000000000000000a6fe0", "gasLimit": 30000000 } }, "block_time": 2, "max_sequencer_drift": 600, "seq_window_size": 3600, "channel_timeout": 300, "l1_chain_id": 11155111, "l2_chain_id": 11155420, "regolith_time": 0, "canyon_time": 1699981200, "delta_time": 1703203200, "ecotone_time": 1708534800, "batch_inbox_address": "0xff00000000000000000000000000000011155420", "deposit_contract_address": "0x16fc5058f25648194471939df75cf27a2fdc48bc", "l1_system_config_address": "0x034edd2a225f7f429a63e0f1d2084b9e0a93b538", "da_challenge_address": "0x0000000000000000000000000000000000000000", "da_challenge_window": 0, "da_resolve_window": 0, "use_plasma": false } ``` Ensure that you are using the appropriate flag. The `--network=op-sepolia` flag allows the tool to pick up the appropriate data from the registry, and uses the OPChains mapping under the hood. ## Adding nodes To add nodes to the rollup, you need to initialize `op-node` and `op-reth`, similar to what you did for the first node. You should *not* add an `op-batcher` because there should be only one. ```bash theme={null} ~/op-reth/genesis.json ~/optimism/op-node/rollup.json ``` ```bash theme={null} cd ~/op-reth openssl rand -hex 32 > jwt.txt cp jwt.txt ~/optimism/op-node ``` ```bash theme={null} cd ~/op-reth op-reth init --chain=./genesis.json --datadir=./datadir ``` If you do it this way, you won't have to wait until the transactions are written to L1. If you already have peer to peer synchronization, add the new node to the `--p2p.static` list so it can synchronize. **Important:** Make sure to configure the `--rollup.sequencer` flag (alias `--rollup.sequencer-http`) to point to your sequencer node. This endpoint is crucial because `op-reth` will route `eth_sendRawTransaction` calls to this URL. The OP Stack does not currently have a public mempool, so configuring this is required if you want your node to support transaction submission. ## Next steps * See the [Consensus Client Configuration](/node-operators/guides/configuration/consensus-clients) and [Execution Client Configuration](/node-operators/guides/configuration/execution-clients) guides for additional explanation or customization. * If you experience difficulty at any stage of this process, please reach out to [developer support](https://github.com/ethereum-optimism/developers/discussions). # Transaction Fees 101 Source: https://docs.optimism.io/chain-operators/guides/management/transaction-fees-101 How to check and tune the fee parameters on your OP Stack chain, with example scenarios for common situations. This guide shows how to check and adjust the fee-related parameters on your chain's `SystemConfig` contract, and when each adjustment makes sense. It applies to the Jovian and following hardforks. * For how each fee component is calculated, see [transaction fees on OP Mainnet](https://docs.optimism.io/op-stack/transactions/fees#transaction-fees-on-op-mainnet). * For the full parameter catalogue — types, setters, and the OP Mainnet values — see the [fee parameters reference](/chain-operators/reference/fee-parameters). On an OP Stack chain a transaction's **Total Fee** is made of three main components: `Total Fee = L2 Fee + L1 Fee + Operator Fee` Fees are gathered in dedicated contract [fee vaults](/op-stack/transactions/fee-vaults) that collect the different fee components (for example `BaseFeeVault`, `SequencerFeeVault`, etc.). See the [fee vault operations guide](/chain-operators/guides/management/fee-vaults) for how to manage and withdraw from these vaults. ## Before you start Only the [SystemConfig owner](/op-stack/protocol/privileged-roles) can change these parameters. Export the values used by all the commands below: ```bash theme={null} export L1_RPC= export SYSTEM_CONFIG= export PK= ``` ## Tune the L2 fee The L2 fee is the EVM execution cost: `gasUsed * (baseFee + priorityFee)`. The `baseFee` is computed with the EIP-1559 mechanism and is **collected in the BaseFeeVault (not burned)** on OP Stack. You can tune L2 fee dynamics on the SystemConfig via: * `eip1559Denominator`: EIP-1559 max-change denominator, it appears in the denominator of the per-block base fee delta. Lower = faster response, so base fee adjusts faster but results in more volatility. * `eip1559Elasticity`: elasticity multiplier, sets the target relative to gasLimit. As `gas_target = gasLimit / elasticity`, a **smaller gas target** (larger elasticity) means the base fee will start increasing at a lower block gas usage (i.e., base fee increases sooner under load). * `gasLimit`: max gas per block. Lower `gasLimit` = less available gas per block (less supply), which makes base fees more sensitive to demand and can cause the base fee to move more easily. * `minBaseFee`: minimum floor on base fee, in wei (it can be 0). See [setting the minimum base fee](/chain-operators/guides/features/setting-min-base-fee). ### Check current values ```bash theme={null} cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "eip1559Denominator()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "eip1559Elasticity()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "minBaseFee()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "gasLimit()" ``` ### Set values ```bash theme={null} cast send --rpc-url $L1_RPC --private-key $PK \ $SYSTEM_CONFIG "setEIP1559Params(uint32,uint32)" cast send --rpc-url $L1_RPC --private-key $PK \ $SYSTEM_CONFIG "setMinBaseFee(uint64)" cast send --rpc-url $L1_RPC --private-key $PK \ $SYSTEM_CONFIG "setGasLimit(uint64)" ``` ## Tune the L1 fee The L1 fee charges for posting L2 data to L1: the transaction's estimated compressed (FastLZ) size is multiplied by a scalar-weighted L1 price. See the [fee parameters reference](/chain-operators/reference/fee-parameters#fee-formulas) for the formula. Reasons to tweak it: * Modify margin charged on top of expected costs * Adjust FastLZ estimates to reflect costs * Differentiate charges for per-byte vs per-blob costs to reflect actual L1 pricing The knobs: * `basefeeScalar`: scales the `l1BaseFee` contribution to the L1 data fee (per-byte). * `blobBaseFeeScalar`: scales the `l1BlobBaseFee` contribution (per-blob). ### Check current values ```bash theme={null} cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "basefeeScalar()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "blobbasefeeScalar()" ``` ### Set values ```bash theme={null} cast send --rpc-url $L1_RPC --private-key $PK \ $SYSTEM_CONFIG "setGasConfigEcotone(uint32,uint32)" ``` ## Tune the operator fee The operator fee is a discretionary, non-standard fee charged per transaction: `(gasUsed * operatorFeeScalar * 100) + operatorFeeConstant`. See [setting the operator fee](/chain-operators/guides/features/setting-operator-fee) for a dedicated guide. * `operatorFeeScalar`: per-gas operator margin. * `operatorFeeConstant`: flat per-transaction operator fee, in wei. Any non-zero operator fee makes the chain configuration [non-standard](/op-stack/protocol/superchain-registry#what-is-a-standard-chain). ### Check current values ```bash theme={null} cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "operatorFeeScalar()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "operatorFeeConstant()" ``` ### Set values ```bash theme={null} cast send --rpc-url $L1_RPC --private-key $PK \ $SYSTEM_CONFIG "setOperatorFeeScalars(uint32,uint64)" ``` ## Tune the DA footprint limit The `daFootprintGasScalar` is an in-protocol limit on estimated DA usage to prevent DA spam and priority fee auctions. See [how the DA footprint block limit works](/chain-operators/reference/da-footprint) for the concept and the [DA footprint setup guide](/chain-operators/guides/features/setting-da-footprint) for a dedicated walkthrough. * Default value is **400** * A value of **0** is treated as **400** * Setting it to **1** effectively disables DA footprint limiting ### Check current value ```bash theme={null} cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "daFootprintGasScalar()" ``` ### Set value ```bash theme={null} cast send --rpc-url $L1_RPC --private-key $PK \ $SYSTEM_CONFIG "setDAFootprintGasScalar(uint16)" ``` ## Example scenarios ### Normal traffic / below EIP-1559 target **What you'll see** * If blocks stay below the EIP-1559 target, `baseFee` trends toward the `minBaseFee` floor. * When L1 data usage is low, the L2 execution fee (`gasUsed * (baseFee + priorityFee)`) is typically the largest cost component. * The L1 data fee remains low/steady if calldata per transaction is small. **What to tweak** * Usually nothing. * If you need a revenue floor set/increase `minBaseFee`. **Tradeoff** * **Pros:** `minBaseFee` prevents prolonged low base fees and provides a predictable minimum (can be left at 0 to improve UX). * **Cons:** If set too high, it raises inclusion cost for low-value transactions and can negatively impact UX/accessibility. *** ### Busy blocks / congestion **What you'll see** * `baseFee` rises when blocks exceed the target: `gas_target = gasLimit / eip1559Elasticity` * Transactions with low priority tips may experience slower inclusion during congestion. **What to tweak** * `eip1559Elasticity` and `eip1559Denominator` : * To increase responsiveness: decrease `eip1559Denominator` and/or increase `eip1559Elasticity` (smaller target → baseFee increases sooner). * To decrease volatility: increase `eip1559Denominator` and/or reduce aggressiveness in `eip1559Elasticity`. **Tradeoff** * **Pros:** Faster base fee response better captures demand; elasticity provides direct control over the gas target. * **Cons:** Smaller denominator and/or aggressive elasticity increases per-block swings and increases fee volatility. *** ### Calldata-heavy transactions **What you'll see** * L1 data fee becomes a larger share of total cost for calldata heavy transactions (the L1 fee scales with compressed calldata size). * Increasing `basefeeScalar` increases the per-byte L1 charge, making calldata heavy transactions more expensive. **What to tweak** * `basefeeScalar` and `blobBaseFeeScalar`: * Increase them if you need to recover more L1/DA posting costs from data heavy transactions. * Decrease them if you want to reduce user cost for calldata/blob-heavy workloads. **Tradeoff** * **Pros:** Enables proportional recovery of L1/DA posting costs. * **Cons:** Penalizes calldata/blob-heavy dapps/users. Aggressive values can impact UX and reduce activity. *** ### Predictable operator revenue **What you'll see** * Introducing or increasing `operatorFeeScalar` raises the per-gas operator charge and increases predictable revenue per transaction. * `operatorFeeConstant` adds a flat per-transaction fee regardless of gas usage. **What to tweak** * `operatorFeeScalar` and `operatorFeeConstant`: * Use when you want direct, predictable operator revenue independent of congestion and L1 fee dynamics. **Tradeoff** * **Pros:** Direct and predictable revenue per transaction. * **Cons:** May discourage low-value transactions and changes transaction economics; should be used carefully. Any non-zero operator fee makes the chain configuration non-standard. *** ### DA-heavy workloads / DA-spam resistance **What you'll see** * DA footprint can limit how much transaction data fits into a block through scaled accounting of compressed DA usage. * Increasing `daFootprintGasScalar` raises the gas charged per DA-byte footprint, reducing DA capacity for the same byte footprint and deterring DA-heavy patterns. **What to tweak** * `daFootprintGasScalar`: * Default is **400**, and `0` is treated as the default. * Setting it to **1** disables the DA footprint limiting behavior. **Tradeoff** * **Pros:** Deters DA spam and makes DA costs explicit in block accounting. * **Cons:** Increasing it reduces DA capacity and may throttle the batcher or exclude legitimate DA-heavy workloads if set too aggressively. *** ## Summary 1. Make sure to check your current hardfork, this doc applies to Jovian and following hardforks. 2. Check the current fee parameters on your SystemConfig contract (see the [fee parameters reference](/chain-operators/reference/fee-parameters) for the expected values on OP Mainnet). 3. Make small changes and observe: vault balances, inclusion times, dropped txs, DA throttling, etc. 4. Extensively test all changes on a staging/testnet. 5. Communicate changes to dapp/wallet teams (gas estimation will change). *** ## References * [Fee parameters reference](/chain-operators/reference/fee-parameters) * [Transaction fees on OP Mainnet](https://docs.optimism.io/op-stack/transactions/fees#transaction-fees-on-op-mainnet) * [Operator fee](https://docs.optimism.io/op-stack/transactions/fees#operator-fee) * [L1 data fee](https://docs.optimism.io/op-stack/transactions/fees#l1-data-fee) * [SystemConfig interface](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol) * [DA footprint](https://docs.optimism.io/notices/archive/upgrade-17#block-header-changes) * [EIP-1559](https://docs.optimism.io/op-stack/protocol/differences#eip-1559-parameters) * [OP Mainnet values](https://etherscan.io/address/0x229047fed2591dbec1eF1118d64F7aF3dB9EB290#readProxyContract) # Troubleshooting chain operations Source: https://docs.optimism.io/chain-operators/guides/management/troubleshooting Learn solutions to common problems when troubleshooting chain operations. This page lists common troubleshooting scenarios and solutions for chain operators. ## EvmError in contract deployment L1 smart contract deployment fails with the following error: ```text theme={null} EvmError: Revert ``` ### Solution The OP Stack uses deterministic smart contract deployments to guarantee that all contract addresses can be computed ahead of time based on a "salt" value that is provided at deployment time. Each OP Stack chain must have a unique salt value to ensure that the contract addresses do not collide with other OP Stack chains. You can avoid this error by changing the salt used when deploying the L1 smart contracts. The salt value is set by the `IMPL_SALT` environment variable when deploying the contracts. The `IMPL_SALT` value must be a 32 byte hex string. You can generate a random salt value using the following command: ```bash theme={null} export IMPL_SALT=$(openssl rand -hex 32) ``` ## Failed to find the L2 Heads to start from `op-node` fails to execute the derivation process with the following error: ```text theme={null} WARN [02-16|21:22:02.868] Derivation process temporary error attempts=14 err="stage 0 failed resetting: temp: failed to find the L2 Heads to start from: failed to fetch L2 block by hash 0x0000000000000000000000000000000000000000000000000000000000000000: failed to determine block-hash of hash 0x0000000000000000000000000000000000000000000000000000000000000000, could not get payload: not found" ``` ### Solution This error can occur when the data directory for `op-reth` becomes corrupted (for example, as a result of a computer crash). You will need to reinitialize the data directory. If you are following the tutorial for [Creating Your Own L2 Rollup](/chain-operators/tutorials/create-l2-rollup), make sure to rerun the commands within the [Spin up sequencer](/chain-operators/tutorials/create-l2-rollup/op-reth-setup) section. If you are not following the tutorial, make sure to take the following steps: 1. Stop `op-node` and `op-reth`. 2. Delete the corresponding `op-reth` data directory. 3. Reinitialize `op-reth` with the `genesis.json` file: `op-reth init --chain=./genesis.json --datadir=./datadir`. 4. Restart `op-reth` and `op-node`. ## Batcher unable to publish transaction `op-batcher` fails to publish transactions with the following error: ```text theme={null} INFO [03-21|14:22:32.754] publishing transaction service=batcher txHash=2ace6d..7eb248 nonce=2516 gasTipCap=2,340,741 gasFeeCap=172,028,434,515 ERROR[03-21|14:22:32.844] unable to publish transaction service=batcher txHash=2ace6d..7eb248 nonce=2516 gasTipCap=2,340,741 gasFeeCap=172,028,434,515 err="insufficient funds for gas * price + value" ``` ### Solution You will observe this error if the `op-batcher` runs out of ETH to publish transactions to L1. This problem can be resolved by sending additional ETH to the `op-batcher` address. # Chain operators Source: https://docs.optimism.io/chain-operators/index Routes chain operators to the quickstart, guides, tutorials, tools, and reference for launching and running an OP Stack chain. You are launching or operating your own OP Stack chain. Deploy first, then use the guides, tools, and reference material to run it in production. Launch your first OP Stack chain with op-deployer. Set up the batcher, proposer, and challenger, enable features, and follow production best practices. Build a rollup component by component, upgrade L1 contracts, and customize your chain step by step. Operate op-deployer, op-conductor, chain monitoring, and the RPC frontends that keep a chain healthy. Check flag-level reference for the batcher, challenger, deployment configuration, and fee parameters. Route by role from the documentation home: app developers, node operators, and protocol learners each have their own section. # Choose how to run your chain Source: https://docs.optimism.io/chain-operators/launch-paths The spectrum between running an OP Stack chain yourself and having it operated for you, and what your team owns at each point on it. Every team launching an OP Stack chain lands somewhere on the same spectrum. At one end, your team runs every service and holds every key. At the other end, someone runs them for you. The choice is not about capability: it is about which parts of a standing operation your team wants to own. This page describes the spectrum and what falls to your team at each point on it. It does not pick a point for you. The pages linked below document the whole system regardless of who operates it. ## The spectrum | | Run it yourself | Run it with engineering support | Have it operated for you | | ------------------- | ------------------------------ | --------------------------------------------- | ------------------------------------------ | | Sequencer cluster | Your team | Your team, with OP Labs engineering behind it | OP Enterprise | | Fault-proof defense | Your team | Your team, with OP Labs engineering behind it | OP Enterprise | | Upgrade execution | Your team | Your team, with OP Labs engineering behind it | OP Enterprise | | Incident response | Your team | Your team, with OP Labs engineering behind it | OP Enterprise | | These docs | The reference for what you run | The reference for what you run | The reference for what runs on your behalf | ## Run it yourself Your team runs every service, holds every key, and owns every incident. These docs cover all of it, and every destination below is one click away. What that ownership includes, stated the way the docs themselves state it: ### The services you run * **The sequencer.** A single sequencer is a single point of failure for the whole chain: when it stops, no new unsafe blocks exist for anyone. The high-availability answer is a sequencer cluster managed by [op-conductor](/chain-operators/tools/op-conductor), with its nodes in separate failure domains. The design is not Byzantine fault tolerant: it assumes every node in the cluster is honest and operated by you, so it protects against crashes and partitions, not against a malicious cluster member. See [the launch guide's sequencer topology step](/use-cases/launch-a-chain-with-fault-proofs-and-ha-sequencing#step-3-design-the-sequencer-topology). * **The defense.** The defense is a service you run and a set of decisions your team staffs. The [`op-challenger`](/op-stack/fault-proofs/challenger) is a service that monitors every game, defends valid proposals, challenges invalid ones, resolves games, and claims bonds. Starting it is not the whole job. Every claim it posts carries a bond sent as transaction value; correct claims are refunded, incorrect ones pay the counter-claimer, and bonds from won games pay out only after a delay, so capital stays locked while games resolve. How much the challenger's account holds, how quickly you can top it up during an active dispute, and which absolute prestate it plays with are operational answers your team owns; the challenger refuses to interact with games whose prestate it does not have. See [Run a fault-proof challenger](/use-cases/run-a-fault-proof-challenger). * **The monitoring.** Watching the chain is a separate set of services from running it. `op-dispute-mon` tracks the status of every dispute game and is how you learn that your challenger is acting; `monitorism` carries the onchain security monitors, whose security-integrity group exists to check that the bridges between L2 and L1 behave as expected, including the faultproof withdrawal monitor that watches `ProvenWithdrawals` events on the `OptimismPortal` and flags invariant violations. Your own components need their metrics endpoints scraped alongside that: `op-node`, `op-batcher`, `op-proposer`, and `op-challenger` each expose one. Peer count belongs on that list too, because an `op-node` without peers cannot sync unsafe blocks and falls behind the sequencer. See [Chain monitoring options](/chain-operators/tools/chain-monitoring) and [the important node metrics](/node-operators/guides/monitoring/metrics#important-metrics). * **The RPC endpoints.** Every service in the stack depends on RPC, and not only on L1. Each sequencer's op-node derives the chain from an L1 RPC and an L1 beacon endpoint, and the batcher, proposer, and challenger read and transact against L1; `op-challenger` additionally needs an L2 archive node (`--l2-eth-rpc`) and a rollup node with SafeDB (`--rollup-rpc`), and `op-dispute-mon` takes a rollup RPC of its own. Redundant nodes behind a generic load balancer are the wrong shape for any of them. Two nodes can be at the same head, but nothing holds them there, and a service whose consecutive requests round-robin between them reads that divergence as blocks appearing and disappearing: reorgs that never happened. The challenger is the least tolerant consumer and needs one trusted endpoint that fails over deliberately rather than per request. See [the launch guide's section on a consistent view](/use-cases/launch-a-chain-with-fault-proofs-and-ha-sequencing#give-every-service-a-consistent-view-of-l1). ### The keys and the decisions * **The keys.** The batcher and proposer addresses need their private keys online somewhere for the system to work, and if those addresses are compromised, the system can be exploited. They are not the only privileged addresses your chain has. The Proxy Admins can upgrade most of the system contracts on L1 and L2, the System Config Owner can change the values in the `SystemConfig` contract, the Guardian can pause withdrawal logic and disable dispute game types from executing withdrawals, and the permissioned Challenger role is a distinct address from the `op-challenger` service. Which addresses hold which role, and how each key is held, whether through an HSM or a cloud key management system, are decisions the chain operator makes. See [Key management](/chain-operators/guides/management/key-management) and [Privileged roles in OP Stack chains](/op-stack/protocol/privileged-roles#privileged-roles-in-op-stack-chains) for what every role can do and what a compromise of it means. * **The path to permissionless proofs.** Chains deployed with `op-deployer` start with the permissioned dispute game, in which the proposer and challenger are specific addresses holding privileged roles. Moving to permissionless fault proofs is a switch your team schedules after launch. See [the launch guide's permissionless-proofs step](/use-cases/launch-a-chain-with-fault-proofs-and-ha-sequencing#step-7-schedule-the-switch-to-permissionless-proofs). ### The work that recurs * **The protocol upgrade cadence.** The OP Stack is being continuously improved and it's your responsibility to keep it up to date. Network upgrades, deprecations, security patches, and operational changes arrive as time-bound action items in [Network Notices](/notices), with the permanent record of each hardfork in the [hardfork registry](/op-stack/protocol/network-upgrades), which records activation times, the governing spec, and minimum component versions. Tracking each notice, moving your components to the versions it names, and executing the change on your chain recurs for as long as the chain runs. * **The standing work.** Running current production releases, keeping the deployment artifacts, staggering upgrade rollouts across your infrastructure, isolating the sequencer, and writing your own runbooks are continuous tasks rather than launch-day ones. Monitoring only helps if someone is on the other end of it. Metrics endpoints on your key components, and runbooks to execute when something is not behaving as expected, are the documented practice; the alerting path, the people reachable through it, and the incident response itself are yours to build and staff. See [Chain operator best practices](/chain-operators/guides/management/best-practices). The full deployment tutorial: contracts, genesis, sequencer, batcher, proposer, and challenger on a testnet. The launch guide: fault proofs from day one and a sequencer topology with no single point of failure, through failover drills. Bond budgeting, prestate selection, the infrastructure the challenger depends on, and how to confirm it is defending your chain. Release selection, deployment artifacts, staggered rollouts, sequencer isolation, and runbooks. ## Run it with engineering support Your team still runs the chain. The difference is who sits behind the decisions above and behind the incidents when they happen: OP Labs engineering does, alongside your operators. Everything linked in the previous section stays the reference for what your team is running, because it is the same system. One capability on this path is not something your team has to stand up itself: OP Labs can optionally run a backup sequencer for your chain, alongside the sequencer cluster your team operates. It is opt-in rather than part of the path by default, and whether to take it is your team's decision. ## Have it operated for you OP Enterprise runs the chain and your team consumes it. The pages above still describe what is running on your behalf, which is why they are worth reading on this path too: the properties you are buying are the ones those pages document. ## What OP Enterprise is OP Enterprise is Optimism's managed offering. It covers fully managed and supported self-managed options, backed by an uptime SLA, priority incident response, direct engineering support, and managed public RPC. The [OP Enterprise](https://optimism.io/op-enterprise?utm_source=docs\&utm_medium=docs\&utm_campaign=op-enterprise) page states what each option includes and is the source of truth for its terms. This page does not restate them. ## Where to go from here Whichever point on the spectrum you choose, the [chain operator quickstart](/chain-operators/quickstart) and the pages it leads to describe the same chain. Start there if you have not deployed one yet. # Chain operator quickstart Source: https://docs.optimism.io/chain-operators/quickstart Launch a scalable and customizable Layer 2 Rollup blockchain with Ethereum-grade security - powered by Optimism. Launch your own OP Stack chain: an open-source, modular, Ethereum Layer 2 rollup. This page orients you on the key components and the sequence of steps, then hands you off to the [full deployment tutorial](/chain-operators/tutorials/create-l2-rollup). There are two ways to have an OP Stack chain: run it yourself, which is what this page and the tutorial behind it cover, or have it run for you. [Choose how to run your chain](/chain-operators/launch-paths) sets out the spectrum between them and what your team owns at each point on it. ## Components Before you deploy, it is important to understand the key components and how they come together to create your blockchain. * **L1 Smart contracts**: A set of smart contracts to be deployed on Ethereum to bridge between the L1 and L2 domains and manage aspects of the rollup. * **Sequencer**: A single privileged node that accepts and derives user transactions on the network to construct the blockchain. * **Batcher**: A sequencer service that publishes L2 transactions onto Ethereum. Using Ethereum as a data availability layer, the OP Stack inherits Ethereum's security properties by allowing any node to derive the state of the L2 blockchain from L1. * **Proposer**: A service responsible for publishing the L2 state root to Ethereum which enables user withdrawals of assets. * **Challenger**: The challenger enforces network security by disputing invalid state roots that have been posted to Ethereum. ## Deployment The following section will walk you through the sequence of steps a chain operator will follow to begin sequencing a chain. Using a CLI tool called [op-deployer](/chain-operators/tools/op-deployer/overview) you will configure your chain and then deploy the smart contracts on Ethereum. After deploying the L1 smart contracts, you will use [op-deployer](/chain-operators/tools/op-deployer/overview) to generate two files necessary to run nodes on the L2 network: * **Genesis file** (`genesis.json`): Initializes the execution client (`op-reth`) * **Rollup configuration file** (`rollup.json`): Configures the consensus client (`op-node`) These files contain all the essential information your services need to interact with Ethereum and the system contracts you deployed. To begin sequencing transactions and building blocks, you will then run an **execution client** and **consensus client** that come together as your **sequencer node**. Next you will run `op-batcher` which will publish user transactions on Ethereum. Then you will run `op-proposer` to publish the L2 state root on Ethereum to enable withdrawals back to Ethereum. Finally you will run `op-challenger` to monitor and dispute any invalid L2 state roots that have been posted. Deploy a complete OP Stack testnet, component by component, with a working automated example alongside. ## Next Steps Take a look at some of the [chain operator best practices](/chain-operators/guides/management/best-practices) to get an idea of some of the things you'll need to keep in mind. **Running this in production** # Batcher configuration reference Source: https://docs.optimism.io/chain-operators/reference/batcher-configuration Reference for all op-batcher configuration options, covering CLI flags, environment variables, and default values. This page catalogues every configuration option for the op-batcher, the service that posts L2 sequencer data to L1 to make it available for verifiers. For guidance on choosing values — the batcher policy, cost tuning, multi-blob transactions, and sequencer throttling — see the [batcher configuration guide](/chain-operators/guides/configuration/batcher). ## Flags Generated from [`op-batcher/v1.16.11`](https://github.com/ethereum-optimism/optimism/releases/tag/op-batcher%2Fv1.16.11) flag definitions. 87 flags: 3 required, 84 optional. ### Required flags | Flag | Description | Environment variable | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | | `--l1-eth-rpc` | HTTP provider URL for L1 | `OP_BATCHER_L1_ETH_RPC` | | `--l2-eth-rpc` | HTTP provider URL for L2 execution engine. A comma-separated list enables the active L2 endpoint provider. Such a list needs to match the number of rollup-rpcs provided. | `OP_BATCHER_L2_ETH_RPC` | | `--rollup-rpc` | HTTP provider URL for Rollup node. A comma-separated list enables the active L2 endpoint provider. Such a list needs to match the number of l2-eth-rpcs provided. | `OP_BATCHER_ROLLUP_RPC` | ### Optional flags | Flag | Description | Default | Environment variable | | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------- | | `--active-sequencer-check-duration` | The duration between checks to determine the active sequencer endpoint. | `5s` | `OP_BATCHER_ACTIVE_SEQUENCER_CHECK_DURATION` | | `--altda.da-server` | HTTP address of a DA Server | — | `OP_BATCHER_ALTDA_DA_SERVER` | | `--altda.da-service` | Use DA service type where commitments are generated by Alt-DA server | `false` | `OP_BATCHER_ALTDA_DA_SERVICE` | | `--altda.enabled` | Enable Alt-DA mode Alt-DA Mode is a Beta feature of the MIT licensed OP Stack. While it has received initial review from core contributors, it is still undergoing testing, and may have bugs or other issues. | `false` | `OP_BATCHER_ALTDA_ENABLED` | | `--altda.get-timeout` | Timeout for get requests. 0 means no timeout. | `0s` | `OP_BATCHER_ALTDA_GET_TIMEOUT` | | `--altda.max-concurrent-da-requests` | Maximum number of concurrent requests to the DA server | `1` | `OP_BATCHER_ALTDA_MAX_CONCURRENT_DA_REQUESTS` | | `--altda.put-timeout` | Timeout for put requests. 0 means no timeout. | `0s` | `OP_BATCHER_ALTDA_PUT_TIMEOUT` | | `--altda.verify-on-read` | Verify input data matches the commitments from the DA storage service | `true` | `OP_BATCHER_ALTDA_VERIFY_ON_READ` | | `--approx-compr-ratio` | The approximate compression ratio (\<= 1.0). Only relevant for ratio compressor. | `0.6` | `OP_BATCHER_APPROX_COMPR_RATIO` | | `--batch-type` | The batch type. 0 for SingularBatch and 1 for SpanBatch. | `singular` | `OP_BATCHER_BATCH_TYPE` | | `--check-recent-txs-depth` | Indicates how many blocks back the batcher should look during startup for a recent batch tx on L1. This can speed up waiting for node sync. It should be set to the verifier confirmation depth of the sequencer (e.g. 4). | `0` | `OP_BATCHER_CHECK_RECENT_TXS_DEPTH` | | `--compression-algo` | The compression algorithm to use. Valid options: zlib, brotli, brotli-9, brotli-10, brotli-11 | `zlib` | `OP_BATCHER_COMPRESSION_ALGO` | | `--compressor` | The type of compressor. Valid options: none, ratio, shadow | `"shadow"` | `OP_BATCHER_COMPRESSOR` | | `--data-availability-type` | The data availability type to use for submitting batches to the L1. Valid options: calldata, blobs, auto | `calldata` | `OP_BATCHER_DATA_AVAILABILITY_TYPE` | | `--fee-limit-multiplier` | The multiplier applied to fee suggestions to put a hard limit on fee increases | `5` | `OP_BATCHER_TXMGR_FEE_LIMIT_MULTIPLIER` | | `--hd-path` | The HD path used to derive the sequencer wallet from the mnemonic. The mnemonic flag must also be set. | — | `OP_BATCHER_HD_PATH` | | `--log.color` | Color the log output if in terminal mode | `false` | `OP_BATCHER_LOG_COLOR` | | `--log.format` | Format the log output. Supported formats: text, terminal, logfmt, logfmtms, json, jsonms | `text` | `OP_BATCHER_LOG_FORMAT` | | `--log.level` | The lowest log level that will be output | `INFO` | `OP_BATCHER_LOG_LEVEL` | | `--log.pid` | Show pid in the log | `false` | `OP_BATCHER_LOG_PID` | | `--max-blocks-per-span-batch` | Maximum number of blocks to add to a span batch. Default is 0 - no maximum. | `0` | `OP_BATCHER_MAX_BLOCKS_PER_SPAN_BATCH` | | `--max-channel-duration` | The maximum duration of L1-blocks to keep a channel open. 0 to disable. | `0` | `OP_BATCHER_MAX_CHANNEL_DURATION` | | `--max-l1-tx-size-bytes` | The maximum size of a batch tx submitted to L1. Ignored for blobs, where max blob size will be used. | `120000` | `OP_BATCHER_MAX_L1_TX_SIZE_BYTES` | | `--max-pending-tx` | The maximum number of pending transactions. 0 for no limit. | `1` | `OP_BATCHER_MAX_PENDING_TX` | | `--metrics.addr` | Metrics listening address | `"0.0.0.0"` | `OP_BATCHER_METRICS_ADDR` | | `--metrics.enabled` | Enable the metrics server | `false` | `OP_BATCHER_METRICS_ENABLED` | | `--metrics.port` | Metrics listening port | `7300` | `OP_BATCHER_METRICS_PORT` | | `--mnemonic` | The mnemonic used to derive the wallets for either the service | — | `OP_BATCHER_MNEMONIC` | | `--network-timeout` | Timeout for all network operations | `10s` | `OP_BATCHER_NETWORK_TIMEOUT` | | `--num-confirmations` | Number of confirmations which we will wait after sending a transaction | `10` | `OP_BATCHER_NUM_CONFIRMATIONS` | | `--poll-interval` | How frequently to poll L2 for new blocks | `6s` | `OP_BATCHER_POLL_INTERVAL` | | `--pprof.addr` | pprof listening address | `"0.0.0.0"` | `OP_BATCHER_PPROF_ADDR` | | `--pprof.enabled` | Enable the pprof server | `false` | `OP_BATCHER_PPROF_ENABLED` | | `--pprof.path` | pprof file path. If it is a directory, the path is \{dir}/\{profileType}.prof | — | `OP_BATCHER_PPROF_PATH` | | `--pprof.port` | pprof listening port | `6060` | `OP_BATCHER_PPROF_PORT` | | `--pprof.type` | pprof profile type. One of cpu, heap, goroutine, threadcreate, block, mutex, allocs | — | `OP_BATCHER_PPROF_TYPE` | | `--private-key` | The private key to use with the service. Must not be used with mnemonic. | — | `OP_BATCHER_PRIVATE_KEY` | | `--resubmission-timeout` | Duration we will wait before resubmitting a transaction to L1 | `48s` | `OP_BATCHER_RESUBMISSION_TIMEOUT` | | `--rpc.addr` | rpc listening address | `"0.0.0.0"` | `OP_BATCHER_RPC_ADDR` | | `--rpc.enable-admin` | Enable the admin API | `false` | `OP_BATCHER_RPC_ENABLE_ADMIN` | | `--rpc.port` | rpc listening port | `8545` | `OP_BATCHER_RPC_PORT` | | `--safe-abort-nonce-too-low-count` | Number of ErrNonceTooLow observations required to give up on a tx at a particular nonce without receiving confirmation | `3` | `OP_BATCHER_SAFE_ABORT_NONCE_TOO_LOW_COUNT` | | `--sequencer-hd-path` | DEPRECATED: The HD path used to derive the sequencer wallet from the mnemonic. The mnemonic flag must also be set. | — | `OP_BATCHER_SEQUENCER_HD_PATH` | | `--signer.address` | Address the signer is signing requests for | — | `OP_BATCHER_SIGNER_ADDRESS` | | `--signer.endpoint` | Signer endpoint the client will connect to | — | `OP_BATCHER_SIGNER_ENDPOINT` | | `--signer.header` | Headers to pass to the remote signer. Format `key=value`. Value can contain any character allowed in a HTTP header. When using env vars, split with commas. When using flags one key value pair per flag. | — | `OP_BATCHER_SIGNER_HEADER` | | `--signer.tls.ca` | tls ca cert path | `"tls/ca.crt"` | `OP_BATCHER_SIGNER_TLS_CA` | | `--signer.tls.cert` | tls cert path | `"tls/tls.crt"` | `OP_BATCHER_SIGNER_TLS_CERT` | | `--signer.tls.enabled` | Enable or disable TLS client authentication for the signer | `true` | `OP_BATCHER_SIGNER_TLS_ENABLED` | | `--signer.tls.key` | tls key | `"tls/tls.key"` | `OP_BATCHER_SIGNER_TLS_KEY` | | `--stopped` | Initialize the batcher in a stopped state. The batcher can be started using the admin\_startBatcher RPC | `false` | `OP_BATCHER_STOPPED` | | `--sub-safety-margin` | The batcher tx submission safety margin (in #L1-blocks) to subtract from a channel's timeout and sequencing window, to guarantee safe inclusion of a channel on L1. | `10` | `OP_BATCHER_SUB_SAFETY_MARGIN` | | `--target-num-frames` | The target number of frames to create per channel. Controls number of blobs per blob tx, if using Blob DA. | `1` | `OP_BATCHER_TARGET_NUM_FRAMES` | | `--throttle.additional-endpoints` | Comma-separated list of endpoints to distribute throttling configuration to (in addition to the L2 endpoints specified with --l2-eth-rpc). | — | `OP_BATCHER_THROTTLE_ADDITIONAL_ENDPOINTS` | | `--throttle.block-size-lower-limit` | The limit on the DA size of blocks when we are at maximum throttle intensity (linear and quadratic controllers only). 0 means no limits will ever be applied, so consider 1 the smallest effective limit. | `2000` | `OP_BATCHER_THROTTLE_BLOCK_SIZE_LOWER_LIMIT` | | `--throttle.block-size-upper-limit` | The limit on the DA size of blocks when we are at 0 throttle intensity (applied when throttling is inactive) | `130000` | `OP_BATCHER_THROTTLE_BLOCK_SIZE_UPPER_LIMIT` | | `--throttle.controller-type` | Type of throttle controller to use: 'step', 'linear', 'quadratic' (default) or 'pid' (EXPERIMENTAL - use with caution) | `"quadratic"` | `OP_BATCHER_THROTTLE_CONTROLLER_TYPE` | | `--throttle.pid-integral-max` | EXPERIMENTAL: PID controller maximum integral windup. Only relevant if --throttle-controller-type is set to 'pid' | `1000` | `OP_BATCHER_THROTTLE_PID_INTEGRAL_MAX` | | `--throttle.pid-kd` | EXPERIMENTAL: PID controller derivative gain. Only relevant if --throttle-controller-type is set to 'pid' | `0.05` | `OP_BATCHER_THROTTLE_PID_KD` | | `--throttle.pid-ki` | EXPERIMENTAL: PID controller integral gain. Only relevant if --throttle-controller-type is set to 'pid' | `0.01` | `OP_BATCHER_THROTTLE_PID_KI` | | `--throttle.pid-kp` | EXPERIMENTAL: PID controller proportional gain. Only relevant if --throttle-controller-type is set to 'pid' | `0.33` | `OP_BATCHER_THROTTLE_PID_KP` | | `--throttle.pid-output-max` | EXPERIMENTAL: PID controller maximum output. Only relevant if --throttle-controller-type is set to 'pid' | `1` | `OP_BATCHER_THROTTLE_PID_OUTPUT_MAX` | | `--throttle.pid-sample-time` | EXPERIMENTAL: PID controller sample time interval, default is 2s | `2s` | `OP_BATCHER_THROTTLE_PID_SAMPLE_TIME` | | `--throttle.tx-size-lower-limit` | The limit on the DA size of transactions when we are at maximum throttle intensity. 0 means no limits will ever be applied, so consider 1 the smallest effective limit. | `150` | `OP_BATCHER_THROTTLE_TX_SIZE_LOWER_LIMIT` | | `--throttle.tx-size-upper-limit` | The limit on the DA size of transactions when we are at 0+ throttle intensity (limit of the intensity as it approaches 0 from positive values). Not applied when throttling is inactive. | `20000` | `OP_BATCHER_THROTTLE_TX_SIZE_UPPER_LIMIT` | | `--throttle.unsafe-da-bytes-lower-threshold` | The threshold on unsafe\_da\_bytes beyond which the batcher will start to throttle the block builder. Zero disables throttling. | `3200000` | `OP_BATCHER_THROTTLE_UNSAFE_DA_BYTES_LOWER_THRESHOLD` | | `--throttle.unsafe-da-bytes-upper-threshold` | Threshold on unsafe\_da\_bytes at which throttling has the maximum intensity (linear and quadratic controllers only) | `12800000` | `OP_BATCHER_THROTTLE_UNSAFE_DA_BYTES_UPPER_THRESHOLD` | | `--txmgr.already-published-custom-errs` | List of custom RPC error messages that indicate that a transaction has already been published. | — | `OP_BATCHER_TXMGR_ALREADY_PUBLISHED_CUSTOM_ERRS` | | `--txmgr.blob-tip-cap-dynamic` | Use dynamic blob tip cap from the blob tip oracle instead of static tip cap for blob transactions. Regular transactions still use min-tip-cap/max-tip-cap. | `false` | `OP_BATCHER_TXMGR_BLOB_TIP_CAP_DYNAMIC` | | `--txmgr.blob-tip-cap-percentile` | Percentile of recent blob tx tips to use for suggestion (1-100). Only used when blob-tip-cap-dynamic is enabled. | `60` | `OP_BATCHER_TXMGR_BLOB_TIP_CAP_PERCENTILE` | | `--txmgr.blob-tip-cap-range` | Number of recent blocks to analyze for blob tip cap distribution. Only used when blob-tip-cap-dynamic is enabled. | `20` | `OP_BATCHER_TXMGR_BLOB_TIP_CAP_RANGE` | | `--txmgr.cell-proof-time` | Enables cell proofs in blob transactions for Fusaka (EIP-7742) compatibility from the provided unix timestamp. Should be set to the L1 Fusaka time. May be left blank for Ethereum Mainnet, Sepolia, Holesky, or Hoodi L1s. | `18446744073709551615` | `OP_BATCHER_TXMGR_CELL_PROOF_TIME` | | `--txmgr.fee-limit-threshold` | The minimum threshold (in GWei) at which fee bumping starts to be capped. Allows arbitrary fee bumps below this threshold. | `100` | `OP_BATCHER_TXMGR_FEE_LIMIT_THRESHOLD` | | `--txmgr.max-basefee` | Enforces a maximum base fee (in GWei) to assume when determining tx fees, `TxMgr` returns an error when exceeded. Disabled by default. | `0` | `OP_BATCHER_TXMGR_MAX_BASEFEE` | | `--txmgr.max-retries` | Maximum number of times to resubmit a transaction to L1 on a transient error. Set to 0 to disable retries. | `10` | `OP_BATCHER_TXMGR_MAX_RETRIES` | | `--txmgr.max-tip-cap` | Enforces a maximum tip cap (in GWei) to use when determining tx fees, `TxMgr` returns an error when exceeded. Disabled by default. | `0` | `OP_BATCHER_TXMGR_MAX_TIP_CAP` | | `--txmgr.min-basefee` | Enforces a minimum base fee (in GWei) to assume when determining tx fees. 1 GWei by default. | `1` | `OP_BATCHER_TXMGR_MIN_BASEFEE` | | `--txmgr.min-tip-cap` | Enforces a minimum tip cap (in GWei) to use when determining tx fees. 1 GWei by default. | `1` | `OP_BATCHER_TXMGR_MIN_TIP_CAP` | | `--txmgr.not-in-mempool-timeout` | Timeout for aborting a tx send if the tx does not make it to the mempool. | `2m0s` | `OP_BATCHER_TXMGR_TX_NOT_IN_MEMPOOL_TIMEOUT` | | `--txmgr.rebroadcast-interval` | Interval at which a published transaction will be rebroadcasted if it has not yet been mined. Should be less than ResubmissionTimeout to have an effect. | `12s` | `OP_BATCHER_TXMGR_REBROADCAST_INTERVAL` | | `--txmgr.receipt-query-interval` | Frequency to poll for receipts | `12s` | `OP_BATCHER_TXMGR_RECEIPT_QUERY_INTERVAL` | | `--txmgr.retry-interval` | Duration we will wait before resubmitting a transaction to L1 on a transient error. Values \<= 0 will result in retrying immediately. Should be less than ResubmissionTimeout to have an effect. | `1s` | `OP_BATCHER_TXMGR_RETRY_INTERVAL` | | `--txmgr.send-timeout` | Timeout for sending transactions. If 0 it is disabled. | `0s` | `OP_BATCHER_TXMGR_TX_SEND_TIMEOUT` | | `--wait-node-sync` | Indicates if, during startup, the batcher should wait for a recent batcher tx on L1 to finalize (via more block confirmations). This should help avoid duplicate batcher txs. | `false` | `OP_BATCHER_WAIT_NODE_SYNC` | ## Throttling The `throttle.*` flags control how the batcher limits data availability (DA) usage when a backlog builds up. When the amount of sequenced data that has not yet been posted to L1 (the `unsafe_da_bytes` metric) exceeds `--throttle.unsafe-da-bytes-lower-threshold`, the batcher instructs block builders — over the `--l2-eth-rpc` endpoints, plus any endpoints listed in `--throttle.additional-endpoints` — to limit transaction and block DA sizes, scaling between the configured upper and lower size limits as the backlog grows. `--throttle.controller-type` selects how throttling intensity ramps with the backlog: `step`, `linear`, `quadratic` (the default), or the experimental `pid` controller, which is tuned with the six `throttle.pid-*` flags. For the design of the throttling subsystem, including the PID controller, see [`op-batcher/throttling.md`](https://github.com/ethereum-optimism/optimism/blob/develop/op-batcher/throttling.md) in the monorepo. ## Notes on selected flags ### batch-type Span batches (`--batch-type=1`) aggregate consecutive L2 blocks into a single batch for better compression. See the [span batch feature page](/op-stack/features/span-batches) to learn more. ### data-availability-type Setting this flag to `auto` allows the batcher to automatically switch between `calldata` and `blobs` based on the current L1 gas price. ### altda.\* The `altda.*` flags configure Alt-DA mode, a Beta feature of the OP Stack. While it has received initial review from core contributors, it is still undergoing testing, and may have bugs or other issues. See the [Alt-DA mode guide](/chain-operators/guides/features/alt-da-mode-guide) for setup instructions. # Challenger configuration reference Source: https://docs.optimism.io/chain-operators/reference/challenger-configuration Reference for all op-challenger configuration options, covering CLI flags, environment variables, and default values. This page catalogues every configuration option for the op-challenger, the dispute game agent that monitors fault proof games on L1, challenges invalid claims, and defends valid state transitions. For step-by-step setup instructions — prestates, trace types, wallets, and monitoring — see the [challenger configuration guide](/chain-operators/guides/configuration/op-challenger-config-guide); for how the fault proof system works, see the [challenger explainer](/op-stack/fault-proofs/challenger). ## Flags Generated from [`op-challenger/v1.9.3`](https://github.com/ethereum-optimism/optimism/releases/tag/op-challenger%2Fv1.9.3) flag definitions. 88 flags: 4 required, 84 optional. ### Required flags | Flag | Description | Environment variable | | -------------- | ----------------------------------------------------------------------- | -------------------------- | | `--datadir` | Directory to store data generated as part of responding to games | `OP_CHALLENGER_DATADIR` | | `--l1-beacon` | Address of L1 Beacon API endpoint to use | `OP_CHALLENGER_L1_BEACON` | | `--l1-eth-rpc` | HTTP provider URL for L1. | `OP_CHALLENGER_L1_ETH_RPC` | | `--l2-eth-rpc` | URLs of L2 JSON-RPC endpoints to use (eth and debug namespace required) | `OP_CHALLENGER_L2_ETH_RPC` | ### Optional flags | Flag | Description | Default | Environment variable | | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | --------------------------------------------------- | | `--additional-bond-claimants` | List of addresses to claim bonds for, in addition to the configured transaction sender | — | `OP_CHALLENGER_ADDITIONAL_BOND_CLAIMANTS` | | `--cannon-bin` | Path to cannon executable to use when generating trace data (cannon game type only) | — | `OP_CHALLENGER_CANNON_BIN` | | `--cannon-depset-config` | Interop dependency set config file (cannon game type only) | — | `OP_CHALLENGER_CANNON_DEPSET_CONFIG` | | `--cannon-info-freq` | Frequency of cannon info log messages to generate in VM steps (cannon game type only) | `10000000` | `OP_CHALLENGER_CANNON_INFO_FREQ` | | `--cannon-kona-depset-config` | Interop dependency set config file (cannon-kona game type only) | — | `OP_CHALLENGER_CANNON_KONA_DEPSET_CONFIG` | | `--cannon-kona-l1-genesis` | Path to the L1 genesis file. Only required if the L1 is not mainnet, sepolia, holesky, or hoodi. | — | `OP_CHALLENGER_CANNON_KONA_L1_GENESIS` | | `--cannon-kona-l2-genesis` | Paths to the op-geth genesis file (cannon-kona game type only) | — | `OP_CHALLENGER_CANNON_KONA_L2_GENESIS` | | `--cannon-kona-prestate` | Path to absolute prestate to use when generating trace data (cannon-kona game type only) | — | `OP_CHALLENGER_CANNON_KONA_PRESTATE` | | `--cannon-kona-prestates-url` | Base URL to absolute prestates to use when generating trace data. Prestates in this directory should be name as \.bin.gz \.json.gz or \.json (cannon-kona game type only) | — | `OP_CHALLENGER_CANNON_KONA_PRESTATES_URL` | | `--cannon-kona-rollup-config` | Rollup chain parameters (cannon-kona game type only) | — | `OP_CHALLENGER_CANNON_KONA_ROLLUP_CONFIG` | | `--cannon-kona-server` | Path to kona executable to use as pre-image oracle server when generating trace data (cannon-kona game type only) | — | `OP_CHALLENGER_CANNON_KONA_SERVER` | | `--cannon-l1-genesis` | Path to the L1 genesis file. Only required if the L1 is not mainnet, sepolia, holesky, or hoodi. | — | `OP_CHALLENGER_CANNON_L1_GENESIS` | | `--cannon-l2-genesis` | Paths to the op-geth genesis file (cannon game type only) | — | `OP_CHALLENGER_CANNON_L2_GENESIS` | | `--cannon-prestate` | Path to absolute prestate to use when generating trace data (cannon game type only) | — | `OP_CHALLENGER_CANNON_PRESTATE` | | `--cannon-prestates-url` | Base URL to absolute prestates to use when generating trace data. Prestates in this directory should be name as \.bin.gz \.json.gz or \.json (cannon game type only) | — | `OP_CHALLENGER_CANNON_PRESTATES_URL` | | `--cannon-rollup-config` | Rollup chain parameters (cannon game type only) | — | `OP_CHALLENGER_CANNON_ROLLUP_CONFIG` | | `--cannon-server` | Path to executable to use as pre-image oracle server when generating trace data (cannon game type only) | — | `OP_CHALLENGER_CANNON_SERVER` | | `--cannon-snapshot-freq` | Frequency of cannon snapshots to generate in VM steps (cannon game type only) | `1000000000` | `OP_CHALLENGER_CANNON_SNAPSHOT_FREQ` | | `--depset-config` | Interop dependency set config file | — | `OP_CHALLENGER_DEPSET_CONFIG` | | `--fee-limit-multiplier` | The multiplier applied to fee suggestions to put a hard limit on fee increases | `5` | `OP_CHALLENGER_TXMGR_FEE_LIMIT_MULTIPLIER` | | `--game-allowlist` | List of Fault Game contract addresses the challenger is allowed to play. If empty, the challenger will play all games. | — | `OP_CHALLENGER_GAME_ALLOWLIST` | | `--game-factory-address` | Address of the fault game factory contract. | — | `OP_CHALLENGER_GAME_FACTORY_ADDRESS` | | `--game-types` | The game types to support. Valid options: alphabet, cannon, cannon-kona, permissioned, fast, super-cannon-kona, super-permissioned, zk | `"cannon", "cannon-kona"` | `OP_CHALLENGER_GAME_TYPES` | | `--game-window` | The time window which the challenger will look for games to progress and claim bonds. This should include a buffer for the challenger to claim bonds for games outside the maximum game duration. | `672h0m0s` | `OP_CHALLENGER_GAME_WINDOW` | | `--hd-path` | The HD path used to derive the sequencer wallet from the mnemonic. The mnemonic flag must also be set. | — | `OP_CHALLENGER_HD_PATH` | | `--http-poll-interval` | Polling interval for latest-block subscription when using an HTTP RPC provider. | `12s` | `OP_CHALLENGER_HTTP_POLL_INTERVAL` | | `--l1-genesis` | Path to the L1 genesis file. Only required if the L1 is not mainnet, sepolia, holesky, or hoodi. | — | `OP_CHALLENGER_L1_GENESIS` | | `--l1-rpc-kind` | The kind of RPC provider, used to inform optimal transactions receipts fetching, and thus reduce costs. Valid options: alchemy, quicknode, infura, parity, nethermind, debug\_geth, erigon, basic, any, standard | `standard` | `OP_CHALLENGER_L1_RPC_KIND` | | `--l2-experimental-eth-rpc` | L2 Address of L2 JSON-RPC endpoint to use (eth and debug namespace required with execution witness support) (cannon game type only) | — | `OP_CHALLENGER_L2_EXPERIMENTAL_ETH_RPC` | | `--l2-genesis` | Paths to the op-geth genesis file | — | `OP_CHALLENGER_L2_GENESIS` | | `--log.color` | Color the log output if in terminal mode | `false` | `OP_CHALLENGER_LOG_COLOR` | | `--log.format` | Format the log output. Supported formats: text, terminal, logfmt, logfmtms, json, jsonms | `text` | `OP_CHALLENGER_LOG_FORMAT` | | `--log.level` | The lowest log level that will be output | `INFO` | `OP_CHALLENGER_LOG_LEVEL` | | `--log.pid` | Show pid in the log | `false` | `OP_CHALLENGER_LOG_PID` | | `--max-concurrency` | Maximum number of threads to use when progressing games | `4` | `OP_CHALLENGER_MAX_CONCURRENCY` | | `--max-pending-tx` | The maximum number of pending transactions. 0 for no limit. | `10` | `OP_CHALLENGER_MAX_PENDING_TX` | | `--metrics.addr` | Metrics listening address | `"0.0.0.0"` | `OP_CHALLENGER_METRICS_ADDR` | | `--metrics.enabled` | Enable the metrics server | `false` | `OP_CHALLENGER_METRICS_ENABLED` | | `--metrics.port` | Metrics listening port | `7300` | `OP_CHALLENGER_METRICS_PORT` | | `--min-update-interval` | Minimum time between scheduling update cycles based on the L1 block time. | `0s` | `OP_CHALLENGER_MIN_UPDATE_INTERVAL` | | `--mnemonic` | The mnemonic used to derive the wallets for either the service | — | `OP_CHALLENGER_MNEMONIC` | | `--network` | Predefined network selection. Available networks: every chain bundled from the [superchain-registry](https://github.com/ethereum-optimism/superchain-registry) at the release; run `op-challenger --help` for the exact list | — | `OP_CHALLENGER_NETWORK` | | `--network-timeout` | Timeout for all network operations | `10s` | `OP_CHALLENGER_NETWORK_TIMEOUT` | | `--num-confirmations` | Number of confirmations which we will wait after sending a transaction | `3` | `OP_CHALLENGER_NUM_CONFIRMATIONS` | | `--pprof.addr` | pprof listening address | `"0.0.0.0"` | `OP_CHALLENGER_PPROF_ADDR` | | `--pprof.enabled` | Enable the pprof server | `false` | `OP_CHALLENGER_PPROF_ENABLED` | | `--pprof.path` | pprof file path. If it is a directory, the path is \{dir}/\{profileType}.prof | — | `OP_CHALLENGER_PPROF_PATH` | | `--pprof.port` | pprof listening port | `6060` | `OP_CHALLENGER_PPROF_PORT` | | `--pprof.type` | pprof profile type. One of cpu, heap, goroutine, threadcreate, block, mutex, allocs | — | `OP_CHALLENGER_PPROF_TYPE` | | `--prestates-url` | Base URL to absolute prestates to use when generating trace data. Prestates in this directory should be name as \.bin.gz \.json.gz or \.json | — | `OP_CHALLENGER_PRESTATES_URL` | | `--private-key` | The private key to use with the service. Must not be used with mnemonic. | — | `OP_CHALLENGER_PRIVATE_KEY` | | `--response-delay` | Delay before responding to game actions to slow down game progression. | `0s` | `OP_CHALLENGER_RESPONSE_DELAY` | | `--response-delay-after` | Number of responses after which to start applying the delay (0 = from first response). | `0` | `OP_CHALLENGER_RESPONSE_DELAY_AFTER` | | `--resubmission-timeout` | Duration we will wait before resubmitting a transaction to L1 | `24s` | `OP_CHALLENGER_RESUBMISSION_TIMEOUT` | | `--rollup-config` | Rollup chain parameters | — | `OP_CHALLENGER_ROLLUP_CONFIG` | | `--rollup-rpc` | HTTP provider URL for the rollup node | — | `OP_CHALLENGER_ROLLUP_RPC` | | `--safe-abort-nonce-too-low-count` | Number of ErrNonceTooLow observations required to give up on a tx at a particular nonce without receiving confirmation | `3` | `OP_CHALLENGER_SAFE_ABORT_NONCE_TOO_LOW_COUNT` | | `--selective-claim-resolution` | Only resolve claims for the configured claimants | `false` | `OP_CHALLENGER_SELECTIVE_CLAIM_RESOLUTION` | | `--signer.address` | Address the signer is signing requests for | — | `OP_CHALLENGER_SIGNER_ADDRESS` | | `--signer.endpoint` | Signer endpoint the client will connect to | — | `OP_CHALLENGER_SIGNER_ENDPOINT` | | `--signer.header` | Headers to pass to the remote signer. Format `key=value`. Value can contain any character allowed in a HTTP header. When using env vars, split with commas. When using flags one key value pair per flag. | — | `OP_CHALLENGER_SIGNER_HEADER` | | `--signer.tls.ca` | tls ca cert path | `"tls/ca.crt"` | `OP_CHALLENGER_SIGNER_TLS_CA` | | `--signer.tls.cert` | tls cert path | `"tls/tls.crt"` | `OP_CHALLENGER_SIGNER_TLS_CERT` | | `--signer.tls.enabled` | Enable or disable TLS client authentication for the signer | `true` | `OP_CHALLENGER_SIGNER_TLS_ENABLED` | | `--signer.tls.key` | tls key | `"tls/tls.key"` | `OP_CHALLENGER_SIGNER_TLS_KEY` | | `--super-cannon-kona-depset-config` | Interop dependency set config file (super-cannon-kona game type only) | — | `OP_CHALLENGER_SUPER_CANNON_KONA_DEPSET_CONFIG` | | `--super-cannon-kona-l1-genesis` | Path to the L1 genesis file. Only required if the L1 is not mainnet, sepolia, holesky, or hoodi. | — | `OP_CHALLENGER_SUPER_CANNON_KONA_L1_GENESIS` | | `--super-cannon-kona-l2-genesis` | Paths to the op-geth genesis file (super-cannon-kona game type only) | — | `OP_CHALLENGER_SUPER_CANNON_KONA_L2_GENESIS` | | `--super-cannon-kona-prestates-url` | Base URL to absolute prestates to use when generating trace data. Prestates in this directory should be name as \.bin.gz \.json.gz or \.json (super-cannon-kona game type only) | — | `OP_CHALLENGER_SUPER_CANNON_KONA_PRESTATES_URL` | | `--super-cannon-kona-rollup-config` | Rollup chain parameters (super-cannon-kona game type only) | — | `OP_CHALLENGER_SUPER_CANNON_KONA_ROLLUP_CONFIG` | | `--supernode-rpc` | Provider URL for supernode roots | — | `OP_CHALLENGER_SUPERNODE_RPC` | | `--txmgr.already-published-custom-errs` | List of custom RPC error messages that indicate that a transaction has already been published. | — | `OP_CHALLENGER_TXMGR_ALREADY_PUBLISHED_CUSTOM_ERRS` | | `--txmgr.cell-proof-time` | Enables cell proofs in blob transactions for Fusaka (EIP-7742) compatibility from the provided unix timestamp. Should be set to the L1 Fusaka time. May be left blank for Ethereum Mainnet, Sepolia, Holesky, or Hoodi L1s. | `18446744073709551615` | `OP_CHALLENGER_TXMGR_CELL_PROOF_TIME` | | `--txmgr.fee-limit-threshold` | The minimum threshold (in GWei) at which fee bumping starts to be capped. Allows arbitrary fee bumps below this threshold. | `100` | `OP_CHALLENGER_TXMGR_FEE_LIMIT_THRESHOLD` | | `--txmgr.max-basefee` | Enforces a maximum base fee (in GWei) to assume when determining tx fees, `TxMgr` returns an error when exceeded. Disabled by default. | `0` | `OP_CHALLENGER_TXMGR_MAX_BASEFEE` | | `--txmgr.max-retries` | Maximum number of times to resubmit a transaction to L1 on a transient error. Set to 0 to disable retries. | `10` | `OP_CHALLENGER_TXMGR_MAX_RETRIES` | | `--txmgr.max-tip-cap` | Enforces a maximum tip cap (in GWei) to use when determining tx fees, `TxMgr` returns an error when exceeded. Disabled by default. | `0` | `OP_CHALLENGER_TXMGR_MAX_TIP_CAP` | | `--txmgr.min-basefee` | Enforces a minimum base fee (in GWei) to assume when determining tx fees. 1 GWei by default. | `1` | `OP_CHALLENGER_TXMGR_MIN_BASEFEE` | | `--txmgr.min-tip-cap` | Enforces a minimum tip cap (in GWei) to use when determining tx fees. 1 GWei by default. | `1` | `OP_CHALLENGER_TXMGR_MIN_TIP_CAP` | | `--txmgr.not-in-mempool-timeout` | Timeout for aborting a tx send if the tx does not make it to the mempool. | `1m0s` | `OP_CHALLENGER_TXMGR_TX_NOT_IN_MEMPOOL_TIMEOUT` | | `--txmgr.rebroadcast-interval` | Interval at which a published transaction will be rebroadcasted if it has not yet been mined. Should be less than ResubmissionTimeout to have an effect. | `0s` | `OP_CHALLENGER_TXMGR_REBROADCAST_INTERVAL` | | `--txmgr.receipt-query-interval` | Frequency to poll for receipts | `12s` | `OP_CHALLENGER_TXMGR_RECEIPT_QUERY_INTERVAL` | | `--txmgr.retry-interval` | Duration we will wait before resubmitting a transaction to L1 on a transient error. Values \<= 0 will result in retrying immediately. Should be less than ResubmissionTimeout to have an effect. | `1s` | `OP_CHALLENGER_TXMGR_RETRY_INTERVAL` | | `--txmgr.send-timeout` | Timeout for sending transactions. If 0 it is disabled. | `2m0s` | `OP_CHALLENGER_TXMGR_TX_SEND_TIMEOUT` | ## Notes on selected flags ### Conditionally required flags The required table above lists the flags op-challenger always checks at startup. Additional flags become required depending on the configuration: the chain must be identified by `--network` or by `--game-factory-address`, and each enabled game type requires its trace-execution flags (for example the `cannon-kona` game type requires the kona server and an absolute prestate via `--cannon-kona-prestate` or `--cannon-kona-prestates-url`). ### network When `--network` is set to a chain bundled from the superchain-registry, the `--game-factory-address` is resolved automatically from the registry and does not need to be set. ### game-types Selects which dispute game types the challenger plays. Which type defends your chain depends on the protocol version it runs; see the [challenger configuration guide](/chain-operators/guides/configuration/op-challenger-config-guide) for choosing game types, trace types, and the matching prestates. ### cannon-\* and cannon-kona-\* The `cannon-*` flags apply only when a cannon-based game type is enabled, and the `cannon-kona-*` variants only to the `cannon-kona` game type. Each of these settings has a default variant plus a game-type-specific variant that overrides it (the `( game type only)` suffix in the table above). Note that op-program, the fault proof program the non-kona cannon game types execute, has [reached end of support](/notices/archive/op-geth-deprecation), so only the kona variants are still being maintained. ## Utility subcommands Beyond running the challenger service, the `op-challenger` binary provides utility subcommands for inspecting and interacting with dispute games: `list-games`, `list-claims`, `list-credits`, `create-game`, `move`, `resolve`, `resolve-claim`, and `run-trace`. Each takes its own flags; run `op-challenger --help` for details. # How the DA footprint block limit works Source: https://docs.optimism.io/chain-operators/reference/da-footprint Understand the Data Availability (DA) footprint block limit introduced in the Jovian hardfork, how the DA footprint is calculated, and why the default gas scalar is 400. The **Data Availability (DA) Footprint Block Limit** was introduced in the **[Jovian hardfork](https://docs.optimism.io/notices/upgrade-17)** to limit the total amount of transaction data that can fit into a block based on a scaled estimate of the compressed size (or "data availability footprint") of that data. This page explains the problem the limit solves, how the DA footprint is calculated, and how the `daFootprintGasScalar` parameter shapes the limit. To change the scalar on your chain, follow the [DA footprint setup guide](/chain-operators/guides/features/setting-da-footprint). ## Why a DA footprint limit exists When an OP Stack chain receives more calldata-heavy transactions than can fit into the L1's available blob space, the [batcher can throttle the chain's throughput](https://docs.optimism.io/chain-operators/guides/configuration/batcher#batcher-sequencer-throttling). However, continuous batcher throttling may cause the base fee to drop to the [minimum base fee](https://docs.optimism.io/chain-operators/guides/features/setting-min-base-fee), causing unnecessary losses for the chain operator and negative user experiences such as priority fee auctions. And without throttling, the batcher runs the risk of becoming overwhelmed with chain data to batch to the blob space. Limiting the amount of (estimated compressed) calldata taken up by transactions in a block using their total DA footprint can reduce the need for batcher throttling and its related issues. ## How the DA footprint is calculated For all [non-deposit transactions](https://docs.optimism.io/reference/glossary#deposited-transaction) processed by an OP Stack chain, a DA footprint value is recorded alongside the transaction's gas usage. The DA footprint can be configured via the `daFootprintGasScalar` variable in the `SystemConfig` contract on the L1 chain. The DA footprint is automatically calculated for every transaction first by calculating a `daUsageEstimate` for that transaction: ```python theme={null} daUsageEstimate = max( minTransactionSize, (intercept + fastlzCoef * tx.fastlzSize) // 1e6 ) ``` where the `minTransactionSize`, `intercept`, `fastlzCoef`, and `tx.fastlzSize` are as specified in the [Fjord specs](https://specs.optimism.io/protocol/fjord/exec-engine.html#fees). Then the `daUsageEstimate` is multiplied by the `daFootprintGasScalar` to get the `daFootprint` for that individual transaction. ```python theme={null} daFootprint += daUsageEstimate * daFootprintGasScalar ``` The `daFootprint` for all the transactions in a block are then added together to calculate that block's total `daFootprint`. With the block's total `daFootprint` calculated: * The block's total `daFootprint` must stay below its `gasLimit`. * The `blobGasUsed` property of each block header is set to that block's `daFootprint`. * The base fee update calculation then uses `gasMetered := max(gasUsed, blobGasUsed)` as a replacement for the `gasUsed` variable. From Jovian, transaction receipts also record the transaction's DA Footprint in the receipt's `blobGasUsed` field, as well as the block's `daFootprintGasScalar` in a new field with the same name. ## What the DA footprint gas scalar controls The *DA footprint gas scalar* scales the *estimated DA usage in bytes* to the gas dimension, and this scaled estimate of the DA usage is what we call the *DA footprint*. This allows us to limit the estimated DA usage using the block's `gasLimit`: the effective limit of estimated DA usage per block is `gasLimit / daFootprintGasScalar` bytes. So *increasing* this scalar makes DA usage more gas-heavy, so *decreases* the limit, and vice versa. This is closely related to how the calldata (floor) cost of `40` gas per non-zero byte limits the total amount of calldata in a block. A DA footprint gas scalar of `400` effectively limits *incompressible* calldata by a factor of `10` compared to its limit without a DA footprint block limit. As such, the feature can be seen as an extension of the existing calldata limit. But instead of repricing the calldata (floor) gas cost, the limit is accounted in parallel to EVM execution gas, and is based on the more relevant FastLZ-based DA usage estimate instead of simply counting zero and non-zero bytes. ## Why the default value is 400 The default scalar of `400` was chosen so that it protects chains in worst-case DA spam scenarios, but has negligible to no impact during normal operation. Careful [analyses](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/da-footprint-block-limit.md) have been done to estimate the impact on current OP Stack chains and pick the right default. Only high-throughput chains would occasionally even see a small impact from the resulting DA footprint limit (as slightly faster rising base fees). The DA footprint limit is mostly invisible. On mid to low-throughput chains, the feature is expected to have no impact under normal usage conditions. It acts more like an insurance to protect against worst-case *incompressible* DA spam. A `daFootprintGasScalar` value of `0` in the `SystemConfig` is treated as the default of `400`. To effectively disable the limit, set the scalar to a very low value such as `1`. ## Next steps * To set or change the scalar on your chain, follow [Set the DA Footprint Gas Scalar](/chain-operators/guides/features/setting-da-footprint). * For the full set of fee-related `SystemConfig` parameters, see the [fee parameters reference](/chain-operators/reference/fee-parameters). ## References * [DA Footprint Configuration Spec](https://specs.optimism.io/protocol/jovian/system-config.html#da-footprint-configuration) * [Jovian Upgrade Spec](https://specs.optimism.io/protocol/jovian/overview.html) * [SystemConfig Contract Spec](https://specs.optimism.io/protocol/system-config.html) * [Design Doc](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/da-footprint-block-limit.md) # Fee parameters Source: https://docs.optimism.io/chain-operators/reference/fee-parameters Reference for the fee-related SystemConfig parameters on an OP Stack chain — what each parameter controls, its setter and getter, and the OP Mainnet values. This page catalogues the fee-related parameters a chain operator can set on the `SystemConfig` contract, from the Jovian hardfork onward. For how fees are calculated and charged, see [transaction fees on OP Mainnet](https://docs.optimism.io/op-stack/transactions/fees#transaction-fees-on-op-mainnet). For when and how to adjust these parameters, see the [fee tuning guide](/chain-operators/guides/management/transaction-fees-101). Only the [SystemConfig owner](/op-stack/protocol/privileged-roles) can call the setter methods listed below. ## Fee formulas On an OP Stack chain a transaction's **Total Fee** is made of three main components: `Total Fee = L2 Fee + L1 Fee + Operator Fee` | Component | Formula | | ------------ | ----------------------------------------------------------- | | L2 fee | `gasUsed * (baseFee + priorityFee)` | | L1 fee | `estimatedSizeScaled * l1FeeScaled / 1e12` (see below) | | Operator fee | `(gasUsed * operatorFeeScalar * 100) + operatorFeeConstant` | The L1 fee charges for posting L2 data to L1, based on the transaction's estimated compressed (FastLZ) size: ```ts theme={null} l1FeeScaled = baseFeeScalar * 16 * l1BaseFee + blobBaseFeeScalar * l1BlobBaseFee estimatedSizeScaled = max( minTransactionSize * 1e6, intercept + fastlzCoef * fastlzSize ) l1Fee = estimatedSizeScaled * l1FeeScaled / 1e12 ``` **Pre-Jovian (Isthmus) operator fee formula:** `operatorFee = (gasUsed * operatorFeeScalar / 1e6) + operatorFeeConstant` ## Parameters All parameters live on the `SystemConfig` contract on L1 (see the [`ISystemConfig` interface](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol)). Each getter below is a `view` method with the same name as the parameter. | Parameter | Type | What it controls | Setter | OP Mainnet value | | ---------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------- | | `eip1559Denominator` | `uint32` | EIP-1559 max-change denominator: appears in the denominator of the per-block base fee delta. Lower = faster base fee response, more volatility. | `setEIP1559Params(uint32,uint32)` | `250` | | `eip1559Elasticity` | `uint32` | Elasticity multiplier: sets the gas target relative to the gas limit (`gas_target = gasLimit / elasticity`). Larger elasticity = smaller target, so base fee increases sooner under load. | `setEIP1559Params(uint32,uint32)` | `2` | | `gasLimit` | `uint64` | Maximum gas per block. Lower limit = less supply per block, making base fees more sensitive to demand. | `setGasLimit(uint64)` | `40,000,000` | | `minBaseFee` | `uint64` | Minimum floor on the base fee, in wei (can be 0). See [setting the minimum base fee](/chain-operators/guides/features/setting-min-base-fee). | `setMinBaseFee(uint64)` | `0` | | `basefeeScalar` | `uint32` | Scales the `l1BaseFee` (per-byte) contribution to the L1 data fee. | `setGasConfigEcotone(uint32,uint32)` | `5227` | | `blobbasefeeScalar` | `uint32` | Scales the `l1BlobBaseFee` (per-blob) contribution to the L1 data fee. | `setGasConfigEcotone(uint32,uint32)` | `1014213` | | `operatorFeeScalar` | `uint32` | Per-gas operator margin. See [setting the operator fee](/chain-operators/guides/features/setting-operator-fee). | `setOperatorFeeScalars(uint32,uint64)` | `0` | | `operatorFeeConstant` | `uint64` | Flat per-transaction operator fee, in wei. | `setOperatorFeeScalars(uint32,uint64)` | `0` | | `daFootprintGasScalar` | `uint16` | Scales estimated DA usage to the gas dimension to limit DA-heavy blocks. See [how the DA footprint block limit works](/chain-operators/reference/da-footprint). | `setDAFootprintGasScalar(uint16)` | `0` (treated as `400`) | * Any non-zero operator fee makes the chain configuration [non-standard](/op-stack/protocol/superchain-registry#what-is-a-standard-chain). * A `daFootprintGasScalar` of `0` is treated as the default of `400`; set it to `1` to effectively disable the DA footprint limit. The OP Mainnet values can be verified against the [OP Mainnet SystemConfig contract on Etherscan](https://etherscan.io/address/0x229047fed2591dbec1eF1118d64F7aF3dB9EB290#readProxyContract). ## Fee vault recipients Fees are gathered in dedicated contract [fee vaults](/op-stack/transactions/fee-vaults). See the [fee vault operations guide](/chain-operators/guides/management/fee-vaults) for how to manage and withdraw from these vaults. | Fee component | Recipient vault | | ------------- | ------------------- | | `baseFee` | `BaseFeeVault` | | `priorityFee` | `SequencerFeeVault` | | `l1Fee` | `L1FeeVault` | | `operatorFee` | `OperatorFeeVault` | ## Reading current values Each parameter has a getter with the same name on the `SystemConfig` contract: ```bash theme={null} export L1_RPC= export SYSTEM_CONFIG= cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "eip1559Denominator()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "eip1559Elasticity()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "gasLimit()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "minBaseFee()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "basefeeScalar()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "blobbasefeeScalar()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "operatorFeeScalar()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "operatorFeeConstant()" cast call --rpc-url $L1_RPC $SYSTEM_CONFIG "daFootprintGasScalar()" ``` ## References * [Transaction fees on OP Mainnet](https://docs.optimism.io/op-stack/transactions/fees#transaction-fees-on-op-mainnet) * [Operator fee](https://docs.optimism.io/op-stack/transactions/fees#operator-fee) * [L1 data fee](https://docs.optimism.io/op-stack/transactions/fees#l1-data-fee) * [`ISystemConfig` interface](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol) * [DA footprint](https://docs.optimism.io/notices/archive/upgrade-17#block-header-changes) * [EIP-1559 parameters](https://docs.optimism.io/op-stack/protocol/differences#eip-1559-parameters) # OP Contracts Manager Source: https://docs.optimism.io/chain-operators/reference/opcm Understand what OP Contracts Manager is, why it exists, and how it deploys and upgrades the L1 contracts for OP Stack chains in a single transaction. The OP Contracts Manager is a contract that deploys the L1 contracts for an OP Stack chain in a single transaction. It provides a minimal set of user-configurable parameters to ensure that the resulting chain meets the standard configuration requirements. Additionally, as of [Upgrade 13](https://gov.optimism.io/t/upgrade-proposal-13-opcm-and-incident-response-improvements/9739), instances of OPCM can upgrade existing OP Stack chains. The version deployed is always a governance-approved contract release. The set of governance approved contract releases can be found on the Optimism Monorepo releases page, and is the set of releases named `op-contracts/vX.Y.Z`. It deploys the [Fault Proof System](/op-stack/fault-proofs/explainer), using the [PermissionedDisputeGame](/op-stack/protocol/smart-contracts#proposals-and-fault-proofs). ## Purpose OPCM simplifies the L1 contract deployments for new OP Stack chains. For each smart contract release there will be a new OPCM instance. It addresses three aspects of deploying the OP Stack's L1 contracts: 1. **Deploy Shared Contracts.** Shared contracts are used between many OP chains, so this occurs only occasionally in production. 2. **Deploy Shared Implementation Contracts.** This occurs once per contracts release in production. 3. **Deploy OP Chain Contracts.** This occurs for every OP chain deployment in production. Additionally, after the Upgrade 13 network upgrade, OPCM instances will be used to upgrade existing OP Stack chains. ## Learn more * Checkout the [OPCM specs](https://specs.optimism.io/experimental/op-contracts-manager.html?utm_source=op-docs\&utm_medium=docs) * Checkout the [OPCM design document](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/op-contracts-manager-arch.md) # Rollup deployment configuration Source: https://docs.optimism.io/chain-operators/reference/rollup-deployment-configuration Reference for the OP Stack rollup deployment configuration values. This page is the reference for the values in the `DeployConfig` — the flat JSON configuration that sets the L1 contract parameters and the L2 genesis state when an OP Stack chain is deployed. The schema tables below are generated directly from the `DeployConfig` Go struct tree in the monorepo (`op-chain-ops/genesis`) at a finalized op-deployer release, so the field list, JSON keys, types, and descriptions cannot silently fall behind the source. Recommended values and standard-configuration requirements are policy rather than code, and are maintained by hand in the [guidance section](#guidance-and-standard-configuration-requirements) below. **The recommended way to deploy an OP Stack chain is [OP Deployer](/chain-operators/tools/op-deployer/overview).** OP Deployer takes a declarative [intent file](/chain-operators/tools/op-deployer/usage/init) (`intent.toml`) rather than a hand-written `DeployConfig` JSON, and derives the `DeployConfig` documented here from that intent as part of its deployment pipeline. Most chain operators set the intent file and never edit a `DeployConfig` directly. This page documents the underlying `DeployConfig` surface: the exhaustive set of values a deployment ultimately resolves to. Use it to understand what an intent setting maps to, to interpret the `DeployConfig` that OP Deployer can emit for an applied deployment (via `op-deployer inspect deploy-config`), or as background for the lower-level [custom deployments](/chain-operators/tools/op-deployer/usage/custom-deployments) OP Deployer also supports. Deploy-config values are largely immutable after a chain is deployed, so this page targets the values you set at genesis. The output-oracle proposal fields (the [`l2OutputOracle*` values](#legacy-output-oracle)) describe the legacy `L2OutputOracle` proposal system and apply only to chains still on that system. Chains using [permissionless fault proofs](/op-stack/fault-proofs/explainer) — the standard configuration for new OP Stack chains — set the [fault-proof deployment values](#fault-proofs) instead: `useFaultProofs` together with the `faultGame*`, `preimageOracle*`, `proofMaturityDelaySeconds`, `disputeGameFinalityDelaySeconds`, and `respectedGameType` fields. Standard configuration is the set of requirements for an OP Stack chain to be considered a Standard Chain within the OP Stack. These requirements are currently a draft, pending governance approval. For more details, please see this [governance thread](https://gov.optimism.io/t/season-6-draft-standard-rollup-charter/8135) and the actual requirements in the [OP Stack Configurability Specification](https://specs.optimism.io/protocol/configurability.html?utm_source=op-docs\&utm_medium=docs). ## Configuration values Generated from the [`DeployConfig` struct](https://github.com/ethereum-optimism/optimism/blob/op-deployer%2Fv0.7.1/op-chain-ops/genesis/config.go) in `op-chain-ops/genesis` at [`op-deployer/v0.7.1`](https://github.com/ethereum-optimism/optimism/releases/tag/op-deployer%2Fv0.7.1): 122 values in 20 groups. The JSON key for each value is its `json:"..."` struct tag there; descriptions are the Go doc comments. When this page and the source disagree, the source wins. ### Development accounts | JSON key | Type | Description | | ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------- | | `fundDevAccounts` | boolean | FundDevAccounts configures whether to fund the dev accounts. This should only be used during devnet deployments. | ### L2 genesis block | JSON key | Type | Description | | ----------------------------- | -------------------------------- | ----------- | | `l2GenesisBlockNonce` | number (hex-encoded) | — | | `l2GenesisBlockGasLimit` | number (hex-encoded) | — | | `l2GenesisBlockDifficulty` | number (hex-encoded big integer) | — | | `l2GenesisBlockMixHash` | 32-byte hash | — | | `l2GenesisBlockNumber` | number (hex-encoded) | — | | `l2GenesisBlockGasUsed` | number (hex-encoded) | — | | `l2GenesisBlockParentHash` | 32-byte hash | — | | `l2GenesisBlockBaseFeePerGas` | number (hex-encoded big integer) | — | ### Ownership OwnershipDeployConfig defines the ownership of an L2 chain deployment. This excludes superchain-wide contracts. | JSON key | Type | Description | | ------------------ | ------- | --------------------------------------------------------------------------------------------------------------------- | | `proxyAdminOwner` | address | ProxyAdminOwner represents the owner of the ProxyAdmin predeploy on L2. | | `finalSystemOwner` | address | FinalSystemOwner is the owner of the system on L1. Any L1 contract that is ownable has this account set as its owner. | ### Fee vaults | JSON key | Type | Description | | ------------------------------------------ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `baseFeeVaultRecipient` | address | BaseFeeVaultRecipient represents the recipient of fees accumulated in the BaseFeeVault. Can be an account on L1 or L2, depending on the BaseFeeVaultWithdrawalNetwork value. | | `l1FeeVaultRecipient` | address | L1FeeVaultRecipient represents the recipient of fees accumulated in the L1FeeVault. Can be an account on L1 or L2, depending on the L1FeeVaultWithdrawalNetwork value. | | `sequencerFeeVaultRecipient` | address | SequencerFeeVaultRecipient represents the recipient of fees accumulated in the SequencerFeeVault. Can be an account on L1 or L2, depending on the SequencerFeeVaultWithdrawalNetwork value. | | `operatorFeeVaultRecipient` | address | OperatorFeeVaultRecipient represents the recipient of fees accumulated in the OperatorFeeVault. | | `baseFeeVaultMinimumWithdrawalAmount` | number (hex-encoded big integer) | BaseFeeVaultMinimumWithdrawalAmount represents the minimum withdrawal amount for the BaseFeeVault. | | `l1FeeVaultMinimumWithdrawalAmount` | number (hex-encoded big integer) | L1FeeVaultMinimumWithdrawalAmount represents the minimum withdrawal amount for the L1FeeVault. | | `sequencerFeeVaultMinimumWithdrawalAmount` | number (hex-encoded big integer) | SequencerFeeVaultMinimumWithdrawalAmount represents the minimum withdrawal amount for the SequencerFeeVault. | | `operatorFeeVaultMinimumWithdrawalAmount` | number (hex-encoded big integer) | OperatorFeeVaultMinimumWithdrawalAmount represents the minimum withdrawal amount for the OperatorFeeVault. | | `baseFeeVaultWithdrawalNetwork` | string: "remote" (withdraw to L1) or "local" (withdraw to L2); legacy 0/1 accepted | BaseFeeVaultWithdrawalNetwork represents the withdrawal network for the BaseFeeVault. | | `l1FeeVaultWithdrawalNetwork` | string: "remote" (withdraw to L1) or "local" (withdraw to L2); legacy 0/1 accepted | L1FeeVaultWithdrawalNetwork represents the withdrawal network for the L1FeeVault. | | `sequencerFeeVaultWithdrawalNetwork` | string: "remote" (withdraw to L1) or "local" (withdraw to L2); legacy 0/1 accepted | SequencerFeeVaultWithdrawalNetwork represents the withdrawal network for the SequencerFeeVault. | | `operatorFeeVaultWithdrawalNetwork` | string: "remote" (withdraw to L1) or "local" (withdraw to L2); legacy 0/1 accepted | OperatorFeeVaultWithdrawalNetwork represents the withdrawal network for the OperatorFeeVault. | ### Governance token GovernanceDeployConfig is exclusive to OP-Mainnet and the testing of OP-Mainnet-like chains. | JSON key | Type | Description | | ----------------------- | ------- | ---------------------------------------------------------------------------------------------------------- | | `enableGovernance` | boolean | EnableGovernance configures whether or not include governance token predeploy. | | `governanceTokenSymbol` | string | GovernanceTokenSymbol represents the ERC20 symbol of the GovernanceToken. | | `governanceTokenName` | string | GovernanceTokenName represents the ERC20 name of the GovernanceToken | | `governanceTokenOwner` | address | GovernanceTokenOwner represents the owner of the GovernanceToken. Has the ability to mint and burn tokens. | ### Gas price oracle GasPriceOracleDeployConfig configures the GasPriceOracle L2 predeploy. | JSON key | Type | Description | | ----------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `gasPriceOracleOverhead` | number | GasPriceOracleOverhead represents the initial value of the gas overhead in the GasPriceOracle predeploy. Deprecated: Since Ecotone, this field is superseded by GasPriceOracleBaseFeeScalar and GasPriceOracleBlobBaseFeeScalar. | | `gasPriceOracleScalar` | number | GasPriceOracleScalar represents the initial value of the gas scalar in the GasPriceOracle predeploy. Deprecated: Since Ecotone, this field is superseded by GasPriceOracleBaseFeeScalar and GasPriceOracleBlobBaseFeeScalar. | | `gasPriceOracleBaseFeeScalar` | number | GasPriceOracleBaseFeeScalar represents the value of the base fee scalar used for fee calculations. | | `gasPriceOracleBlobBaseFeeScalar` | number | GasPriceOracleBlobBaseFeeScalar represents the value of the blob base fee scalar used for fee calculations. | | `gasPriceOracleOperatorFeeScalar` | number | GasPriceOracleOperatorFeeScalar represents the value of the operator fee scalar used for fee calculations. | | `gasPriceOracleOperatorFeeConstant` | number | GasPriceOracleOperatorFeeConstant represents the value of the operator fee constant used for fee calculations. | ### Custom gas token GasTokenDeployConfig configures the optional custom gas token functionality. | JSON key | Type | Description | | ---------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `useCustomGasToken` | boolean | UseCustomGasToken is a flag to indicate that a custom gas token should be used | | `gasPayingTokenName` | string | GasPayingTokenName represents the custom gas token name. | | `gasPayingTokenSymbol` | string | GasPayingTokenSymbol represents the custom gas token symbol. | | `nativeAssetLiquidityAmount` | number (hex-encoded big integer) | NativeAssetLiquidityAmount represents the amount of liquidity to pre-fund the NativeAssetLiquidity contract with. | | `liquidityControllerOwner` | address | LiquidityControllerOwner represents the owner of the LiquidityController. | ### Operator addresses OperatorDeployConfig configures the hot-key addresses for operations such as sequencing and batch-submission. | JSON key | Type | Description | | --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `p2pSequencerAddress` | address | P2PSequencerAddress is the address of the key the sequencer uses to sign blocks on the P2P layer. | | `batchSenderAddress` | address | BatchSenderAddress represents the initial sequencer account that authorizes batches. Transactions sent from this account to the batch inbox address are considered valid. | ### EIP-1559 fee market EIP1559DeployConfig configures the EIP-1559 parameters of the chain. | JSON key | Type | Description | | -------------------------- | ------ | --------------------------------------------------------------------------------------------- | | `eip1559Elasticity` | number | EIP1559Elasticity is the elasticity of the EIP1559 fee market. | | `eip1559Denominator` | number | EIP1559Denominator is the denominator of EIP1559 base fee market. | | `eip1559DenominatorCanyon` | number | EIP1559DenominatorCanyon is the denominator of EIP1559 base fee market when Canyon is active. | ### Network upgrade (hardfork) activations UpgradeScheduleDeployConfig configures when network upgrades activate. | JSON key | Type | Description | | --------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `l2GenesisRegolithTimeOffset` | number (hex-encoded), nullable | L2GenesisRegolithTimeOffset is the number of seconds after genesis block that Regolith hard fork activates. Set it to 0 to activate at genesis. Nil to disable Regolith. | | `l2GenesisCanyonTimeOffset` | number (hex-encoded), nullable | L2GenesisCanyonTimeOffset is the number of seconds after genesis block that Canyon hard fork activates. Set it to 0 to activate at genesis. Nil to disable Canyon. | | `l2GenesisDeltaTimeOffset` | number (hex-encoded), nullable | L2GenesisDeltaTimeOffset is the number of seconds after genesis block that Delta hard fork activates. Set it to 0 to activate at genesis. Nil to disable Delta. | | `l2GenesisEcotoneTimeOffset` | number (hex-encoded), nullable | L2GenesisEcotoneTimeOffset is the number of seconds after genesis block that Ecotone hard fork activates. Set it to 0 to activate at genesis. Nil to disable Ecotone. | | `l2GenesisFjordTimeOffset` | number (hex-encoded), nullable | L2GenesisFjordTimeOffset is the number of seconds after genesis block that Fjord hard fork activates. Set it to 0 to activate at genesis. Nil to disable Fjord. | | `l2GenesisGraniteTimeOffset` | number (hex-encoded), nullable | L2GenesisGraniteTimeOffset is the number of seconds after genesis block that Granite hard fork activates. Set it to 0 to activate at genesis. Nil to disable Granite. | | `l2GenesisHoloceneTimeOffset` | number (hex-encoded), nullable | L2GenesisHoloceneTimeOffset is the number of seconds after genesis block that the Holocene hard fork activates. Set it to 0 to activate at genesis. Nil to disable Holocene. | | `l2GenesisIsthmusTimeOffset` | number (hex-encoded), nullable | L2GenesisIsthmusTimeOffset is the number of seconds after genesis block that the Isthmus hard fork activates. Set it to 0 to activate at genesis. Nil to disable Isthmus. | | `l2GenesisJovianTimeOffset` | number (hex-encoded), nullable | L2GenesisJovianTimeOffset is the number of seconds after genesis block that the Jovian hard fork activates. Set it to 0 to activate at genesis. Nil to disable Jovian. | | `l2GenesisKarstTimeOffset` | number (hex-encoded), nullable | L2GenesisKarstTimeOffset is the number of seconds after genesis block that the Karst hard fork activates. Set it to 0 to activate at genesis. Nil to disable Karst. | | `l2GenesisInteropTimeOffset` | number (hex-encoded), nullable | L2GenesisInteropTimeOffset is the number of seconds after genesis block that the Interop hard fork activates. Set it to 0 to activate at genesis. Nil to disable Interop. | | `l2GenesisPectraBlobScheduleTimeOffset` | number (hex-encoded), nullable | L2GenesisPectraBlobScheduleTimeOffset is the number of seconds after genesis block that the PectraBlobSchedule fix activates. Set it to 0 to activate at genesis. Nil to disable the PectraBlobSchedule fix. | | `l1CancunTimeOffset` | number (hex-encoded), nullable | When Cancun activates. Relative to L1 genesis. | | `l1PragueTimeOffset` | number (hex-encoded), nullable | When Prague activates. Relative to L1 genesis. | | `l1OsakaTimeOffset` | number (hex-encoded), nullable | When Osaka activates. Relative to L1 genesis. | | `l1BPO1TimeOffset` | number (hex-encoded), nullable | When BPO1 activates. Relative to L1 genesis. | | `l1BPO2TimeOffset` | number (hex-encoded), nullable | When BPO2 activates. Relative to L1 genesis. | | `l1BPO3TimeOffset` | number (hex-encoded), nullable | When BPO3 activates. Relative to L1 genesis. | | `l1BPO4TimeOffset` | number (hex-encoded), nullable | When BPO4 activates. Relative to L1 genesis. | | `l1BlobScheduleConfig` | object (go-ethereum blob schedule) | Blob schedule config. | ### Core protocol parameters L2CoreDeployConfig configures the core protocol parameters of the chain. | JSON key | Type | Description | | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `l1ChainID` | number | L1ChainID is the chain ID of the L1 chain. | | `l2ChainID` | number | L2ChainID is the chain ID of the L2 chain. | | `l2BlockTime` | number | L2BlockTime is the number of seconds between each L2 block. | | `finalizationPeriodSeconds` | number | FinalizationPeriodSeconds represents the number of seconds before an output is considered finalized. This impacts the amount of time that withdrawals take to finalize and is generally set to 1 week. | | `maxSequencerDrift` | number | MaxSequencerDrift is the number of seconds after the L1 timestamp of the end of the sequencing window that batches must be included, otherwise L2 blocks including deposits are force included. | | `sequencerWindowSize` | number | SequencerWindowSize is the number of L1 blocks per sequencing window. | | `channelTimeout` | number | ChannelTimeoutBedrock is the number of L1 blocks that a frame stays valid when included in L1. | | `batchInboxAddress` | address | BatchInboxAddress is the L1 account that batches are sent to. | | `systemConfigStartBlock` | number | SystemConfigStartBlock represents the block at which the op-node should start syncing from. It is an override to set this value on legacy networks where it is not set by default. It can be removed once all networks have this value set in their storage. | ### Fee market limits | JSON key | Type | Description | | ---------------------- | ------ | --------------------------------------------------------------------------------- | | `minBaseFee` | number | MinBaseFee is the minimum base applied to each block. | | `daFootprintGasScalar` | number | DAFootprintGasScalar is the scalar used to compute the DAFootprint of each block. | ### Alt-DA mode AltDADeployConfig configures optional AltDA functionality. | JSON key | Type | Description | | ---------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `useAltDA` | boolean | UseAltDA is a flag that indicates if the system is using op-alt-da | | `daCommitmentType` | string | DACommitmentType specifies the allowed commitment | | `daChallengeWindow` | number | DAChallengeWindow represents the block interval during which the availability of a data commitment can be challenged. | | `daResolveWindow` | number | DAResolveWindow represents the block interval during which a data availability challenge can be resolved. | | `daBondSize` | number | DABondSize represents the required bond size to initiate a data availability challenge. | | `daResolverRefundPercentage` | number | DAResolverRefundPercentage represents the percentage of the resolving cost to be refunded to the resolver such as 100 means 100% refund. | ### Development L1 genesis DevL1DeployConfig is used to configure a L1 chain for development/testing purposes. A production L2 deployment does not utilize this configuration, except of a L1BlockTime sanity-check (set this to 12 for L1 Ethereum). | JSON key | Type | Description | | ----------------------------- | -------------------------------- | ----------- | | `l1BlockTime` | number | — | | `l1GenesisBlockTimestamp` | number (hex-encoded) | — | | `l1GenesisBlockNonce` | number (hex-encoded) | — | | `l1GenesisBlockGasLimit` | number (hex-encoded) | — | | `l1GenesisBlockDifficulty` | number (hex-encoded big integer) | — | | `l1GenesisBlockMixHash` | 32-byte hash | — | | `l1GenesisBlockCoinbase` | address | — | | `l1GenesisBlockNumber` | number (hex-encoded) | — | | `l1GenesisBlockGasUsed` | number (hex-encoded) | — | | `l1GenesisBlockParentHash` | 32-byte hash | — | | `l1GenesisBlockBaseFeePerGas` | number (hex-encoded big integer) | — | | `l1GenesisBlockExcessBlobGas` | number (hex-encoded), nullable | — | | `l1GenesisBlockblobGasUsed` | number (hex-encoded), nullable | — | ### L1 starting block | JSON key | Type | Description | | -------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `l1StartingBlockTag` | L1 block number, tag, or hash | L1StartingBlockTag anchors the L2 at an L1 block. The timestamp of the block referenced by l1StartingBlockTag is used in the L2 genesis block, rollup-config, and L1 output-oracle contract. The Output oracle deploy script may use it if the L2 starting timestamp is nil, assuming the L2 genesis is set up with this. The L2 genesis timestamp does not affect the initial L2 account state: the storage of the L1Block contract at genesis is zeroed, since the adoption of the L2-genesis allocs-generation through solidity script. | ### Superchain configuration SuperchainL1DeployConfig configures parameters of the superchain-wide deployed contracts to L1. This deployment is global, and can be reused between L2s that target the same superchain. | JSON key | Type | Description | | -------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------- | | `superchainConfigGuardian` | address | SuperchainConfigGuardian represents the GUARDIAN account in the SuperchainConfig. Has the ability to pause withdrawals. | ### Legacy output oracle OutputOracleDeployConfig configures the legacy OutputOracle deployment to L1. This is obsoleted with Fault Proofs. See FaultProofDeployConfig. | JSON key | Type | Description | | ----------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `l2OutputOracleSubmissionInterval` | number | L2OutputOracleSubmissionInterval is the number of L2 blocks between outputs that are submitted to the L2OutputOracle contract located on L1. | | `l2OutputOracleStartingTimestamp` | number | L2OutputOracleStartingTimestamp is the starting timestamp for the L2OutputOracle. MUST be the same as the timestamp of the L2OO start block. | | `l2OutputOracleStartingBlockNumber` | number | L2OutputOracleStartingBlockNumber is the starting block number for the L2OutputOracle. Must be greater than or equal to the first Bedrock block. The first L2 output will correspond to this value plus the submission interval. | | `l2OutputOracleProposer` | address | L2OutputOracleProposer is the address of the account that proposes L2 outputs. | | `l2OutputOracleChallenger` | address | L2OutputOracleChallenger is the address of the account that challenges L2 outputs. | ### Fault proofs FaultProofDeployConfig configures the fault-proof deployment to L1. | JSON key | Type | Description | | --------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `useFaultProofs` | boolean | UseFaultProofs is a flag that indicates if the system is using fault proofs instead of the older output oracle mechanism. | | `faultGameAbsolutePrestate` | 32-byte hash | FaultGameAbsolutePrestate is the absolute prestate of Cannon. This is computed by generating a proof from the 0th -> 1st instruction and grabbing the prestate from the output JSON. All honest challengers should agree on the setup state of the program. | | `faultGameMaxDepth` | number | FaultGameMaxDepth is the maximum depth of the position tree within the fault dispute game. `2^{FaultGameMaxDepth}` is how many instructions the execution trace bisection game supports. Ideally, this should be conservatively set so that there is always enough room for a full Cannon trace. | | `faultGameClockExtension` | number | FaultGameClockExtension is the amount of time that the dispute game will set the potential grandchild claim's, clock to, if the remaining time is less than this value at the time of a claim's creation. | | `faultGameMaxClockDuration` | number | FaultGameMaxClockDuration is the maximum amount of time that may accumulate on a team's chess clock before they may no longer respond. | | `faultGameGenesisBlock` | number | FaultGameGenesisBlock is the block number for genesis. | | `faultGameGenesisOutputRoot` | 32-byte hash | FaultGameGenesisOutputRoot is the output root for the genesis block. | | `faultGameSplitDepth` | number | FaultGameSplitDepth is the depth at which the fault dispute game splits from output roots to execution trace claims. | | `faultGameWithdrawalDelay` | number | FaultGameWithdrawalDelay is the number of seconds that users must wait before withdrawing ETH from a fault game. | | `preimageOracleMinProposalSize` | number | PreimageOracleMinProposalSize is the minimum number of bytes that a large preimage oracle proposal can be. | | `preimageOracleChallengePeriod` | number | PreimageOracleChallengePeriod is the number of seconds that challengers have to challenge a large preimage proposal. | | `proofMaturityDelaySeconds` | number | ProofMaturityDelaySeconds is the number of seconds that a proof must be mature before it can be used to finalize a withdrawal. | | `disputeGameFinalityDelaySeconds` | number | DisputeGameFinalityDelaySeconds is an additional number of seconds a dispute game must wait before it can be used to finalize a withdrawal. | | `respectedGameType` | number | RespectedGameType is the dispute game type that the OptimismPortal contract will respect for finalizing withdrawals. | ### L1 dependency addresses L1DependenciesConfig is the set of addresses that affect the L2 genesis construction, and is dependent on prior deployment of contracts to L1. This is generally not configured in deploy-config JSON, but rather merged in through a L1 deployments JSON file. | JSON key | Type | Description | | ----------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `l1StandardBridgeProxy` | address | L1StandardBridgeProxy represents the address of the L1StandardBridgeProxy on L1 and is used as part of building the L2 genesis state. | | `l1CrossDomainMessengerProxy` | address | L1CrossDomainMessengerProxy represents the address of the L1CrossDomainMessengerProxy on L1 and is used as part of building the L2 genesis state. | | `l1ERC721BridgeProxy` | address | L1ERC721BridgeProxy represents the address of the L1ERC721Bridge on L1 and is used as part of building the L2 genesis state. | | `systemConfigProxy` | address | SystemConfigProxy represents the address of the SystemConfigProxy on L1 and is used as part of the derivation pipeline. | | `optimismPortalProxy` | address | OptimismPortalProxy represents the address of the OptimismPortalProxy on L1 and is used as part of the derivation pipeline. | | `daChallengeProxy` | address | DAChallengeProxy represents the L1 address of the DataAvailabilityChallenge contract. | ### Legacy fields LegacyDeployConfig retains legacy DeployConfig attributes. The genesis generation may log warnings, do a best-effort support attempt, or ignore these attributes completely. | JSON key | Type | Description | | ----------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `deploymentWaitConfirmations` | number | DeploymentWaitConfirmations is the number of confirmations to wait during deployment. This is DEPRECATED and should be removed in a future PR. | | `channelTimeoutGranite` | number | — | ## Guidance and standard-configuration requirements The tables above are the exhaustive schema. This section carries the hand-maintained guidance for the values chain operators most often need to reason about: recommended values, validation constraints, and the standard-configuration requirements from the draft [Standard Rollup Charter](https://gov.optimism.io/t/season-6-draft-standard-rollup-charter/8135). ### Hardfork activation guidance * The standard configuration requires network upgrades (hardforks) to be activated. New chains set each `l2GenesisTimeOffset` to `"0x0"` so every governance-approved upgrade is active at genesis; a nil (omitted) offset disables the fork. * Later forks cannot activate before earlier ones, and two forks cannot activate at the same post-genesis time. * The interoperability hardfork activation offset is a non-standard feature: interoperability is still [experimental](https://specs.optimism.io/interop/overview.html?utm_source=op-docs\&utm_medium=docs). ### Roles and ownership requirements * `finalSystemOwner`: must not be `address(0)`. It is recommended to have a single admin address to retain a common security model. Standard configuration: must be the Chain Governor or Servicer; however, the L1 ProxyAdmin owner must be held by the Optimism Security Council. At the moment, the L1 ProxyAdmin owner is transferred from the Chain Governor or Servicer to [0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A](https://etherscan.io/address/0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A). * `proxyAdminOwner`: owns the `ProxyAdmin` predeploy on L2, which owns all of the Proxy contracts for every predeployed contract in the range `0x42...0000` to `0x42...2048`, making predeploys upgradeable. Must not be `address(0)`; a single admin address is recommended. * `superchainConfigGuardian`: standard configuration requires [0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2](https://etherscan.io/address/0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2), a 1/1 Safe owned by the Security Council Safe, with the [Deputy Pause Module](https://specs.optimism.io/protocol/deputy-pause-module.html?utm_source=op-docs\&utm_medium=docs) enabled to allow the Optimism Foundation to act as Pause Deputy. * `p2pSequencerAddress` and `batchSenderAddress`: hot-key addresses you control — the sequencer's block-signing key and the batcher account whose transactions to the batch inbox are considered valid. Neither may be `address(0)`. `batchSenderAddress` can be updated later via the `SystemConfig` contract on L1. No standard requirement. * The [L1 dependency addresses](#l1-dependency-addresses) (`l1StandardBridgeProxy`, `l1CrossDomainMessengerProxy`, `l1ERC721BridgeProxy`, `systemConfigProxy`, `optimismPortalProxy`): filled in from the L1 deployment rather than hand-configured; none of them may be `address(0)`. Standard configuration requires the implementation contracts to be the most up-to-date, governance-approved version of the OP Stack codebase — and, if the chain has been upgraded in the past, that the previous versions were a standard release of the codebase. ### Sequencing and batching guidance * `l2BlockTime`: must be nonzero, a whole number, and less than the L1 block time (12 seconds on Ethereum mainnet and Sepolia). Standard configuration: 1 or 2 seconds. * `maxSequencerDrift`: must be nonzero. 1800 (30 minutes) is the constant that takes effect with the [Fjord activation](/op-stack/protocol/network-upgrades#activations). * `sequencerWindowSize`: must be nonzero. Standard configuration: 3\_600 base layer blocks (12 hours for an L2 on Ethereum, assuming 12 second L1 blocktime). This is an important value for constraining the sequencer's ability to re-order transactions; higher values would pose a risk to user protections. * `channelTimeout`: the default of 50 was introduced in the [Granite network upgrade](/op-stack/protocol/network-upgrades#activations). * `batchInboxAddress`: standard configuration convention is `versionByte || keccak256(bytes32(chainId))[:19]`, where `||` denotes concatenation, `versionByte` is `0x00`, and `chainId` is a `uint256`. This covers the full range of chain IDs, up to the full `uint256` size: ```solidity theme={null} bytes32 hash = keccak256(abi.encodePacked(bytes32(uint256(chainId)))); // take the first 19 bytes of the hash, then prepend a version byte of 0x00 // batchInboxAddress = 0x00{hash[:19]} ``` * `systemConfigStartBlock`: standard configuration: the block where the `SystemConfig` was initialized. * `l1StartingBlockTag`: it is generally recommended to use a finalized L1 block to avoid issues with reorgs. ### Chain ID requirements * `l1ChainID`: must be nonzero. 1 for Ethereum mainnet, 11155111 for the Sepolia test network; see [chainlist](https://chainlist.org/?testnets=true) for other networks. Standard configuration: 1 (Ethereum). * `l2ChainID`: must be nonzero and, for security reasons, unique. Standard configuration: a Foundation-approved, globally unique value. Chains should add their chain IDs to [ethereum-lists/chains](https://github.com/ethereum-lists/chains). ### Gas and fee guidance * `l2GenesisBlockGasLimit`: must be nonzero and greater than `MaxResourceLimit + SystemTxMaxGas` (the gas a deposit plus the system transaction can use). Standard configuration: no higher than 200\_000\_000 gas; chain operators are driven to maintain a stable and reliable chain, so careful deliberation is necessary when considering a change. * `l2GenesisBlockBaseFeePerGas`: cannot be nil. * `gasPriceOracleBaseFeeScalar` and `gasPriceOracleBlobBaseFeeScalar`: should not be 0. Standard configuration: set such that the fee margin is between 0 and 50%. See [transaction fees](/op-stack/transactions/fees) for how the scalars enter the fee calculation. * `eip1559Elasticity` and `eip1559Denominator`: must be nonzero. `eip1559DenominatorCanyon` must be nonzero if Canyon is activated; 250 is the recommended value. * `minBaseFee`: an absolute minimum base fee in wei, to help shorten the length of priority fee auctions; 0 disables it (the default). 100000 wei is the recommended value; setting the minimum too high may make transactions harder to get included for users. Standard configuration: must not be set higher than 10000000000 wei. See the [minimum base fee specs](https://specs.optimism.io/protocol/jovian/exec-engine.html#minimum-base-fee) for more detail. * `daFootprintGasScalar`: multiplied by the DA usage estimate to limit the total estimated compressed transaction data that can fit into a block; 400 is the recommended value. As of Jovian, the base fee update calculation uses `gasMetered := max(gasUsed, blobGasUsed)` in place of `gasUsed`, so blocks with high DA usage may cause the base fee to increase in subsequent blocks. See the [DA footprint block limit specs](https://specs.optimism.io/protocol/jovian/exec-engine.html#da-footprint-block-limit) for more detail. ### Fee vault guidance * The `*FeeVaultRecipient` addresses must not be `address(0)`; a single admin address is recommended to retain a common security model. * The `*FeeVaultWithdrawalNetwork` values choose where each vault withdraws: `"remote"` sends fees to the recipient address on L1, `"local"` on L2. Withdrawals to L1 are more expensive. Note that when the config is re-emitted (for example by `op-deployer inspect deploy-config`), these values marshal in the legacy numeric form: `0` for `"remote"`, `1` for `"local"`. * The `*FeeVaultMinimumWithdrawalAmount` values exist because withdrawals to L1 are expensive: the minimum prevents the overhead cost of continuous tiny withdrawals that would cost more to execute than they return. ### Withdrawal finality guidance * `finalizationPeriodSeconds`: must be nonzero. 12 seconds is recommended on test networks, seven days on production ones. Standard configuration: 7 days — a high-security, excessively safe upper bound that leaves enough time to consider social-layer solutions to a hack if necessary, and allows other network participants to challenge the integrity of the corresponding output root. ### Legacy output-oracle guidance These apply only to chains still on the legacy `L2OutputOracle` proposal system; new chains use [fault proofs](#fault-proofs) instead. * `l2OutputOracleSubmissionInterval`: must be nonzero; 120 blocks (4 minutes) is suggested. * `l2OutputOracleStartingBlockNumber`: should be 0 for new chains; may be non-zero for networks upgraded from a legacy system (like OP Mainnet). * `l2OutputOracleStartingTimestamp`: MUST be the timestamp corresponding to the block defined by `l1StartingBlockTag`. * `l2OutputOracleProposer`: must not be `address(0)`. No standard requirement. This role is only active when the `OptimismPortal` respected game type is `PERMISSIONED_CANNON`. The L1 ProxyAdmin sets the implementation of the `PERMISSIONED_CANNON` game type, and thus determines the proposer configuration of the permissioned dispute game. * `l2OutputOracleChallenger`: must not be `address(0)`; a single admin address is recommended to retain a common security model. ### Fault-proof value guidance You should understand the implications of running a fault-proof chain before setting `useFaultProofs`; see the [fault proofs explainer](/op-stack/fault-proofs/explainer). `proofMaturityDelaySeconds` and `disputeGameFinalityDelaySeconds` should not be 0. `faultGameMaxDepth` should be conservatively set so that there is always enough room for a full Cannon trace. ### Alt-DA guidance Alt-DA mode is a non-standard feature. It enables integration of Data Availability layers into the OP Stack regardless of their commitment type; see [Alt-DA mode](/op-stack/features/experimental/alt-da-mode). * `daCommitmentType`: must be either `KeccakCommitment` or `GenericCommitment` (recommended); `KeccakCommitment` will be deprecated. * `daChallengeWindow` and `daResolveWindow`: must be nonzero when using Alt-DA mode with Keccak commitments. * `daChallengeProxy`: must not be `address(0)` when using Alt-DA mode with Keccak commitments, and must be `address(0)` with generic commitments. ### Governance and development settings * `enableGovernance`: false is recommended; the governance token predeploy is exclusive to OP Mainnet and the testing of OP-Mainnet-like chains. * `fundDevAccounts` and the [development L1 genesis](#development-l1-genesis) values are for devnet deployments only; a production L2 deployment does not use them, except for the `l1BlockTime` sanity check (12 for Ethereum). # Chain monitoring options Source: https://docs.optimism.io/chain-operators/tools/chain-monitoring Learn about onchain and offchain monitoring options for your OP Stack chain. This explainer covers the basics of onchain and offchain monitoring options for your OP Stack chain. Onchain monitoring services allow chain operators to monitor the overall system and onchain events. Offchain monitoring lets chain operators to monitor the operation and behavior of nodes and other offchain components. ## Onchain monitoring services Onchain monitoring services provide insights into the overall system, helping chain operators track and monitor on-chain events. Some examples of onchain monitoring services include `monitorism` and `dispute-mon`. ### `monitorism` Monitorism is a tooling suite that supports monitoring and active remediation actions for the OP Stack chain. Monitorism uses monitors as passive security providing automated monitoring for the OP Stack. They are used to monitor the OP stack and alert on specific events that could be a sign of a security incident. Currently, the list of monitors includes: Security integrity monitors: These are monitors necessary for making sure Bridges between L2 and L1 are safe and work as expected. These monitors are divided in two subgroups: * Pre-Faultproof Chain Monitors: * Fault Monitor: checks for changes in output roots posted to the L2OutputOracle contract. When a change is detected, it reconstructs the output root from a trusted L2 source and looks for a match. * Withdrawals Monitor: checks for new withdrawals that have been proven to the OptimismPortal contract. Each withdrawal is checked against the `L2ToL1MessagePasser` contract. * Faultproof chain monitors: * Faultproof Withdrawal: The Faultproof Withdrawal component monitors `ProvenWithdrawals` events on the `OptimismPortal` contract and performs checks to detect any violations of invariant conditions on the chain. If a violation is detected, the issue is logged, and a Prometheus metric is set for the event. This component is designed to work exclusively with chains that are already utilizing the Fault Proofs system. This is a new version of the deprecated `chain-mon`, `faultproof-wd-mon`. For detailed information on how the component works and the algorithms used, please refer to the component README. Security monitors: Those tools monitor other aspects of several contracts used in optimism: * Global Events Monitor: made for taking YAML rules as configuration and monitoring the events that are emitted on the chain. * Liveness Expiration Monitor: monitors the liveness expiration on Safes. * Balances Monitor: emits a metric reporting the balances for the configured accounts. * Multisig Monitor: The multisig monitor reports the paused status of the OptimismPortal contract. If set, reports the latest nonce of the configured Safe address and the latest presigned nonce stored in One Password.. The latest presigned nonce is identified by looking for items in the configured vault that follow a `ready-.json` name. The highest nonce of this item name format is reported. * Drippie Monitor: tracks the execution and executability of drips within a Drippie contract. * Secrets Monitor: takes a Drippie contract as a parameter and monitors for any drips within that contract that use the `CheckSecrets` dripcheck contract. `CheckSecrets` is a dripcheck that allows a drip to begin once a specific secret has been revealed (after a delay period) and cancels the drip if a second secret is revealed. Monitoring these secrets is important, as their revelation may indicate that the secret storage platform has been compromised and someone is attempting to exfiltrate the ETH controlled by the drip. For more information on these monitors and how to use them, [check out the repo](https://github.com/ethereum-optimism/monitorism?tab=readme-ov-file#monitorism). ### `dispute-mon` Chain operators should consider running `op-dispute-mon`. It's an essential security monitoring service that tracks game statuses, providing visibility over the last 28 days. `dispute-mon` is set up and built the same way as `op-challenger`. This means that you can run it the same way (run `make op-dispute-mon` in the directory). A basic configuration option would look like this: ``` OP_DISPUTE_MON_LOG_FORMAT=logfmt OP_DISPUTE_MON_METRICS_ENABLED=true OP_DISPUTE_MON_METRICS_ADDR=0.0.0.0 OP_DISPUTE_MON_METRICS_PORT=7300 OP_DISPUTE_MON_L1_ETH_RPC=.. OP_DISPUTE_MON_ROLLUP_RPC=.. OP_DISPUTE_MON_GAME_FACTORY_ADDRESS=.. OP_DISPUTE_MON_HONEST_ACTORS=.. ``` `OP_DISPUTE_MON_HONEST_ACTORS` is a CSV (no spaces) list of addresses that are used for the honest `op-challenger` instances. Additional flags: * `OP_DISPUTE_MON_GAME_WINDOW`: This is the window of time to report on games. It should leave a buffer beyond the max game duration for bond claiming. If Fault Proof game parameters are not changes (e.g. MAX\_CLOCK\_DURATION), it is recommended to leave this as the default. * `OP_DISPUTE_MON_MONITOR_INTERVAL`: The interval at which to check for new games. Defaults to 30 seconds currently. * `OP_DISPUTE_MON_MAX_CONCURRENCY`: The max thread count. Defaults to 5 currently. You can find more info on `op-dispute-mon` on [the repo](https://github.com/ethereum-optimism/optimism/tree/develop/op-dispute-mon). ## Offchain component monitoring Offchain monitoring allows chain operators to monitor the operation and behavior of nodes and other offchain components. Some of the more common components that you'll likely want to monitor include `op-node`, `op-geth`, `op-proposer`, `op-batcher`, and `op-challenger`. The general steps for enabling offchain monitoring are pretty consistent for all the OP components: 1. Expose the monitoring port by enabling the `--metrics.enabled` flag 2. Customize the metrics port and address via the `--metrics.port` and `--metrics.addr` flags, respectively 3. Use [Prometheus](https://prometheus.io/) to scrape data from the metrics port 4. Save the data in `influxdb` 5. Share the data with [Grafana](https://grafana.com/) to build your custom dashboard ### `op-node` `op-node` metrics and monitoring is detailed in the [Node Metrics and Monitoring](/node-operators/guides/monitoring/metrics) guide. To enable metrics, pass the `--metrics.enabled` flag to `op-node` and follow the steps above for customization options. See [this curated list](/operators/node-operators/management/metrics#important-metrics) for important metrics to track specifically for `op-node`. ### `op-geth` To enable metrics, pass the `--metrics.enabled` flag to the op-geth. You can customize the metrics port and address via the `--metrics.port` and `--metrics.addr` flags, respectively. ### `op-proposer` To enable metrics, pass the `--metrics.enabled` flag to the op-proposer. You can customize the metrics port and address via the `--metrics.port` and `--metrics.addr` flags, respectively. You can find more information about these flags in our [Proposer configuration doc](/operators/chain-operators/configuration/proposer#metricsenabled). ### `op-batcher` To enable metrics, pass the `--metrics.enabled` flag to the op-batcher. You can customize the metrics port and address via the `--metrics.port` and `--metrics.addr` flags, respectively. You can find more information about these flags in our [Batcher configuration doc](/operators/chain-operators/configuration/proposer#metricsenabled). ### `op-challenger` The `op-challenger` operates as the *honest actor* in the fault dispute system and defends the chain by securing the `OptimismPortal` and ensuring the game always resolves to the correct state of the chain. For verifying the legitimacy of claims, `op-challenger` relies on a synced, trusted rollup node as well as a trace provider (e.g., [Cannon](/op-stack/fault-proofs/cannon)). See the [OP-Challenger Explainer](/op-stack/fault-proofs/challenger) for more information on this service. To enable metrics, pass the `--metrics.enabled` flag to `op-challenger` and follow the steps above for customization options. ``` --metrics.addr value (default: "0.0.0.0") ($OP_CHALLENGER_METRICS_ADDR) Metrics listening address --metrics.enabled (default: false) ($OP_CHALLENGER_METRICS_ENABLED) Enable the metrics server --metrics.port value (default: 7300) ($OP_CHALLENGER_METRICS_PORT) Metrics listening port ``` ## Next steps * If you encounter difficulties at any stage of this process, please reach out to [developer support](https://github.com/ethereum-optimism/developers/discussions). # Blockscout block explorer Source: https://docs.optimism.io/chain-operators/tools/explorer Blockscout an open source block explorer for the OP Stack. [Blockscout](https://www.blockscout.com/) is an open source block explorer that supports OP Stack chains. Keep reading for a quick overview on how to deploy Blockscout for your OP Stack chain. Check out the [Blockscout documentation](https://docs.blockscout.com) for up-to-date information on how to deploy and maintain a Blockscout instance. ## Dependencies * [Docker](https://docs.docker.com/get-docker/) ## Create an archive node Blockscout needs access to an [archive node](https://www.alchemy.com/overviews/archive-nodes#archive-nodes) for your OP Stack chain to properly index transactions, blocks, and internal interactions. If using `op-geth`, you can run a node in archive mode with the `--gcmode=archive` flag. Archive nodes take up significantly more disk space than full nodes. You may need to have 2-4 terabytes of disk space available (ideally SSD) if you intend to run an archive node for a production OP Stack chain. 1-200 gigabytes of disk space may be sufficient for a development chain. ## Installation Blockscout can be started from its source code on GitHub. ```sh theme={null} git clone https://github.com/blockscout/blockscout.git -b production-optimism cd blockscout/docker-compose ``` ## Configuration Review the configuration files within the `envs` directory and make any necessary changes. In particular, make sure to review `envs/common-blockscout.env` and `envs/common-frontend.env`. ## Starting Blockscout Start Blockscout with the following command: ```sh theme={null} DOCKER_REPO=blockscout-optimism docker compose -f geth.yml up ``` ## Usage ### Explorer After Blockscout is started, browse to [http://localhost](http://localhost) to view the user interface. Note that this URL may differ if you have changed the Blockscout configuration. ### API Blockscout provides both a REST API and a GraphQL API. Refer to the [API documentation](https://docs.blockscout.com/for-users/api) for more information. # OP Conductor Source: https://docs.optimism.io/chain-operators/tools/op-conductor Understand how op-conductor keeps an OP Stack sequencer highly available, the guarantees it provides, and how its Raft-based design works. This page explains what the `op-conductor` service is and how it works at a high level. To add it to an existing network, follow the [setup guide](/chain-operators/tools/op-conductor/setup). For the full flag and RPC catalogue, see the [configuration and RPC reference](/chain-operators/tools/op-conductor/reference). ## Enhancing sequencer reliability and availability The [op-conductor](https://github.com/ethereum-optimism/optimism/tree/develop/op-conductor) is an auxiliary service designed to enhance the reliability and availability of a sequencer within high-availability setups. By minimizing the risks associated with a single point of failure, the op-conductor ensures that the sequencer remains operational and responsive. ### Assumptions It is important to note that the `op-conductor` does not incorporate Byzantine fault tolerance (BFT). This means the system operates under the assumption that all participating nodes are honest and act correctly. ### Summary of guarantees The design of the `op-conductor` provides the following guarantees: * **No Unsafe Reorgs** * **No Unsafe Head Stall During Network Partition** * **100% Uptime with No More Than 1 Node Failure** ## Design op-conductor. **On a high level, `op-conductor` serves the following functions:** ### Raft consensus layer participation * **Leader determination:** Participates in the Raft consensus algorithm to determine the leader among sequencers. * **State management:** Stores the latest unsafe block ensuring consistency across the system. ### RPC request handling * **Admin RPC:** Provides administrative RPCs for manual recovery scenarios, including, but not limited to: stopping the leadership vote and removing itself from the cluster. * **Health RPC:** Offers health RPCs for the `op-node` to determine whether it should allow the publishing of transactions and unsafe blocks. ### Sequencer health monitoring * Continuously monitors the health of the sequencer (op-node) to ensure optimal performance and reliability. ### Control loop management * Implements a control loop to manage the status of the sequencer (op-node), including starting and stopping operations based on different scenarios and health checks. ## Conductor state transition The following is a state machine diagram of how the op-conductor manages the sequencers Raft consensus. op-conductor-state-transition. **Helpful tips:** To better understand the graph, focus on one node at a time, understand what can be transitioned to this current state and how it can transition to other states. This way you could understand how we handle the state transitions. ## Next steps * Follow the [setup guide](/chain-operators/tools/op-conductor/setup) to add op-conductor to an existing multi-sequencer network without downtime. * Look up flags and admin RPCs in the [configuration and RPC reference](/chain-operators/tools/op-conductor/reference). * Checkout [op-conductor-mon](https://github.com/ethereum-optimism/infra): which monitors multiple op-conductor instances and provides a unified interface for reporting metrics. * Get familiar with [op-conductor-ops](https://github.com/ethereum-optimism/infra/tree/main/op-conductor-ops) to interact with op-conductor. # Configuration and RPCs Source: https://docs.optimism.io/chain-operators/tools/op-conductor/reference Reference for op-conductor configuration flags, environment variables, and conductor namespace RPC methods. This page catalogues op-conductor's configuration options and its admin RPC methods. For how the service works, see [OP Conductor](/chain-operators/tools/op-conductor); to add it to a running network, follow the [setup guide](/chain-operators/tools/op-conductor/setup). ## Configuration options Generated from [`op-conductor/v0.9.4`](https://github.com/ethereum-optimism/optimism/releases/tag/op-conductor%2Fv0.9.4) flag definitions. 61 flags: 9 required, 52 optional. ### Required flags | Flag | Description | Environment variable | | ------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------ | | `--consensus.addr` | Address (excluding port) to listen for consensus connections. | `OP_CONDUCTOR_CONSENSUS_ADDR` | | `--consensus.port` | Port to listen for consensus connections. May be 0 to let the system select a port. | `OP_CONDUCTOR_CONSENSUS_PORT` | | `--execution.rpc` | HTTP provider URL for execution layer | `OP_CONDUCTOR_EXECUTION_RPC` | | `--healthcheck.interval` | Interval between health checks | `OP_CONDUCTOR_HEALTHCHECK_INTERVAL` | | `--healthcheck.min-peer-count` | Minimum number of peers required to be considered healthy | `OP_CONDUCTOR_HEALTHCHECK_MIN_PEER_COUNT` | | `--healthcheck.unsafe-interval` | Interval allowed between unsafe head and now measured in seconds | `OP_CONDUCTOR_HEALTHCHECK_UNSAFE_INTERVAL` | | `--node.rpc` | HTTP provider URL for op-node | `OP_CONDUCTOR_NODE_RPC` | | `--raft.server.id` | Unique ID for this server used by raft consensus | `OP_CONDUCTOR_RAFT_SERVER_ID` | | `--raft.storage.dir` | Directory to store raft data | `OP_CONDUCTOR_RAFT_STORAGE_DIR` | ### Optional flags | Flag | Description | Default | Environment variable | | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------- | | `--consensus.advertised` | Full address (host and port) for other peers to contact the consensus server. Optional: if left empty, the local address is advertised. | — | `OP_CONDUCTOR_CONSENSUS_ADVERTISED` | | `--healthcheck.execution-p2p-check-api` | Type of EL P2P check to perform. If not set, the default `net` type will be used corresponding to the `net_peerCount` RPC call. | `"net"` | `OP_CONDUCTOR_HEALTHCHECK_EXECUTION_P2P_CHECK_API` | | `--healthcheck.execution-p2p-enabled` | Whether to enable EL P2P checks | `false` | `OP_CONDUCTOR_HEALTHCHECK_EXECUTION_P2P_ENABLED` | | `--healthcheck.execution-p2p-min-peer-count` | Minimum number of EL P2P peers required to be considered healthy | `0` | `OP_CONDUCTOR_HEALTHCHECK_EXECUTION_P2P_MIN_PEER_COUNT` | | `--healthcheck.execution-p2p-rpc-url` | URL override for the execution layer RPC client for the sake of p2p healthcheck. If not set, the execution RPC URL will be used. | — | `OP_CONDUCTOR_HEALTHCHECK_EXECUTION_P2P_RPC_URL` | | `--healthcheck.rollup-boost-partial-healthiness-tolerance-interval-seconds` | The time frame within which rollup-boost partial healthiness tolerance is evaluated | `0` | `OP_CONDUCTOR_HEALTHCHECK_ROLLUP_BOOST_PARTIAL_HEALTHINESS_TOLERANCE_INTERVAL_SECONDS` | | `--healthcheck.rollup-boost-partial-healthiness-tolerance-limit` | Sets the count of rollup-boost partial healthiness failures to occur before marking op-conducto as unhealthy. Default is 0 with which a single occurrence of rollup-boost partial healthiness is enough to set op-conductor as unhealthy | `0` | `OP_CONDUCTOR_HEALTHCHECK_ROLLUP_BOOST_PARTIAL_HEALTHINESS_TOLERANCE_LIMIT` | | `--healthcheck.safe-enabled` | Whether to enable safe head progression checks | `false` | `OP_CONDUCTOR_HEALTHCHECK_SAFE_ENABLED` | | `--healthcheck.safe-interval` | Interval between safe head progression measured in seconds | `1200` | `OP_CONDUCTOR_HEALTHCHECK_SAFE_INTERVAL` | | `--log.color` | Color the log output if in terminal mode | `false` | `OP_CONDUCTOR_LOG_COLOR` | | `--log.format` | Format the log output. Supported formats: text, terminal, logfmt, logfmtms, json, jsonms | `text` | `OP_CONDUCTOR_LOG_FORMAT` | | `--log.level` | The lowest log level that will be output | `INFO` | `OP_CONDUCTOR_LOG_LEVEL` | | `--log.pid` | Show pid in the log | `false` | `OP_CONDUCTOR_LOG_PID` | | `--metrics.addr` | Metrics listening address | `"0.0.0.0"` | `OP_CONDUCTOR_METRICS_ADDR` | | `--metrics.enabled` | Enable the metrics server | `false` | `OP_CONDUCTOR_METRICS_ENABLED` | | `--metrics.port` | Metrics listening port | `7300` | `OP_CONDUCTOR_METRICS_PORT` | | `--network` | Predefined network selection. Available networks: every chain bundled from the [superchain-registry](https://github.com/ethereum-optimism/superchain-registry) at the release; run `op-conductor --help` for the exact list | — | `OP_CONDUCTOR_NETWORK` | | `--override.canyon` | Manually specify the canyon fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_CANYON` | | `--override.delta` | Manually specify the delta fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_DELTA` | | `--override.ecotone` | Manually specify the ecotone fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_ECOTONE` | | `--override.fjord` | Manually specify the fjord fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_FJORD` | | `--override.granite` | Manually specify the granite fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_GRANITE` | | `--override.holocene` | Manually specify the holocene fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_HOLOCENE` | | `--override.interop` | Manually specify the interop fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_INTEROP` | | `--override.isthmus` | Manually specify the isthmus fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_ISTHMUS` | | `--override.jovian` | Manually specify the jovian fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_JOVIAN` | | `--override.karst` | Manually specify the karst fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_KARST` | | `--override.pectrablobschedule` | Manually specify the pectrablobschedule fork timestamp, overriding the bundled setting | `0` | `OP_CONDUCTOR_OVERRIDE_PECTRABLOBSCHEDULE` | | `--paused` | Whether the conductor is paused | `false` | `OP_CONDUCTOR_PAUSED` | | `--pprof.addr` | pprof listening address | `"0.0.0.0"` | `OP_CONDUCTOR_PPROF_ADDR` | | `--pprof.enabled` | Enable the pprof server | `false` | `OP_CONDUCTOR_PPROF_ENABLED` | | `--pprof.path` | pprof file path. If it is a directory, the path is \{dir}/\{profileType}.prof | — | `OP_CONDUCTOR_PPROF_PATH` | | `--pprof.port` | pprof listening port | `6060` | `OP_CONDUCTOR_PPROF_PORT` | | `--pprof.type` | pprof profile type. One of cpu, heap, goroutine, threadcreate, block, mutex, allocs | — | `OP_CONDUCTOR_PPROF_TYPE` | | `--raft.bootstrap` | If this node should bootstrap a new raft cluster | `false` | `OP_CONDUCTOR_RAFT_BOOTSTRAP` | | `--raft.heartbeat-timeout` | Heartbeat interval timeout | `1s` | `OP_CONDUCTOR_RAFT_HEARTBEAT_TIMEOUT` | | `--raft.lease-timeout` | Leader lease timeout | `500ms` | `OP_CONDUCTOR_RAFT_LEASE_TIMEOUT` | | `--raft.round-robin-leader-transfer` | Enable deterministic round-robin leader transfer instead of Raft's default log-based selection. Must be enabled on all conductors in the cluster. | `false` | `OP_CONDUCTOR_RAFT_ROUND_ROBIN_LEADER_TRANSFER` | | `--raft.snapshot-interval` | The interval to check if a snapshot should be taken. | `2m0s` | `OP_CONDUCTOR_RAFT_SNAPSHOT_INTERVAL` | | `--raft.snapshot-threshold` | Number of logs to trigger a snapshot | `8192` | `OP_CONDUCTOR_RAFT_SNAPSHOT_THRESHOLD` | | `--raft.trailing-logs` | Number of logs to keep after a snapshot | `10240` | `OP_CONDUCTOR_RAFT_TRAILING_LOGS` | | `--rollup-boost.enabled` | Enable the rollup-boost healthcheck that uses HTTP status codes (200/206/503). Healthchecks are performed against execution.rpc + '/healthz' (path appended automatically). Mutually exclusive with rollup-boost.next-enabled. | `false` | `OP_CONDUCTOR_ROLLUP_BOOST_ENABLED` | | `--rollup-boost.healthcheck-timeout` | Timeout for rollup-boost healthchecks (applies to both standard and next) | `5s` | `OP_CONDUCTOR_ROLLUP_BOOST_HEALTHCHECK_TIMEOUT` | | `--rollup-boost.next-enabled` | Enable rollup-boost healthcheck using JSON response parsing. Requires rollup-boost.next-healthcheck-url. Mutually exclusive with rollup-boost.enabled. | `false` | `OP_CONDUCTOR_ROLLUP_BOOST_NEXT_ENABLED` | | `--rollup-boost.next-healthcheck-url` | Full URL including path for the rollup-boost health endpoint (e.g., '[http://localhost:8080/healthz](http://localhost:8080/healthz)'). Required when rollup-boost.next-enabled is true. | — | `OP_CONDUCTOR_ROLLUP_BOOST_NEXT_HEALTHCHECK_URL` | | `--rollup.config` | Rollup chain parameters | — | `OP_CONDUCTOR_ROLLUP_CONFIG` | | `--rollupboost.ws-url` | WebSocket URL for the rollup boost to listen for payload streams. | — | `OP_CONDUCTOR_ROLLUPBOOST_WS_URL` | | `--rpc.addr` | rpc listening address | `"0.0.0.0"` | `OP_CONDUCTOR_RPC_ADDR` | | `--rpc.enable-admin` | Enable the admin API | `false` | `OP_CONDUCTOR_RPC_ENABLE_ADMIN` | | `--rpc.enable-proxy` | Enable the RPC proxy to underlying sequencer services | `true` | `OP_CONDUCTOR_RPC_ENABLE_PROXY` | | `--rpc.port` | rpc listening port | `8545` | `OP_CONDUCTOR_RPC_PORT` | | `--websocket.server-port` | Port for the conductor to run a WebSocket server that pushes payload streams out. | `8546` | `OP_CONDUCTOR_WEBSOCKET_SERVER_PORT` | ## Notes on selected flags ### raft.bootstrap For bootstrapping a new cluster. This should only be used on the sequencer that is currently active and can only be started once with this flag, otherwise the flag has to be removed or the raft log must be deleted before re-bootstrapping the cluster. ### paused There is no configuration state, so if you unpause via RPC and then restart, it will start paused again. ## RPCs Conductor exposes [admin RPCs](https://github.com/ethereum-optimism/optimism/blob/develop/op-conductor/rpc/api.go#L17) on the `conductor` namespace. ### conductor\_overrideLeader `OverrideLeader` is used to override the leader status, this is only used to return true for `Leader()` & `LeaderWithID()` calls. It does not impact the actual raft consensus leadership status. It is supposed to be used when the cluster is unhealthy and the node is the only one up, to allow batcher to be able to connect to the node so that it could download blocks from the manually started sequencer. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_overrideLeader","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_overrideLeader --rpc-url http://127.0.0.1:8547 ``` ### conductor\_pause `Pause` pauses op-conductor. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_pause","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_pause --rpc-url http://127.0.0.1:8547 ``` ### conductor\_resume `Resume` resumes op-conductor. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_resume","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_resume --rpc-url http://127.0.0.1:8547 ``` ### conductor\_paused Paused returns true if the op-conductor is paused. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_paused","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_paused --rpc-url http://127.0.0.1:8547 ``` ### conductor\_stopped Stopped returns true if the op-conductor is stopped. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_stopped","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_stopped --rpc-url http://127.0.0.1:8547 ``` ### conductor\_sequencerHealthy SequencerHealthy returns true if the sequencer is healthy. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_sequencerHealthy","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_sequencerHealthy --rpc-url http://127.0.0.1:8547 ``` ### conductor\_leader API related to consensus. Leader returns true if the server is the leader. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_leader","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_leader --rpc-url http://127.0.0.1:8547 ``` ### conductor\_leaderWithID API related to consensus. LeaderWithID returns the current leader's server info. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_leaderWithID","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_leaderWithID --rpc-url http://127.0.0.1:8547 ``` ### conductor\_addServerAsVoter API related to consensus. AddServerAsVoter adds a server as a voter to the cluster. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_addServerAsVoter","params":[, , ],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_addServerAsVoter --rpc-url http://127.0.0.1:8547 ``` ### conductor\_addServerAsNonvoter API related to consensus. AddServerAsNonvoter adds a server as a non-voter to the cluster. non-voter The non-voter will not participate in the leader election. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_addServerAsNonvoter","params":[, , ],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_addServerAsNonvoter --rpc-url http://127.0.0.1:8547 ``` ### conductor\_removeServer API related to consensus. RemoveServer removes a server from the cluster. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_removeServer","params":[, ],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_removeServer --rpc-url http://127.0.0.1:8547 ``` ### conductor\_transferLeader API related to consensus. TransferLeader transfers leadership to another server (resigns). ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_transferLeader","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_transferLeader --rpc-url http://127.0.0.1:8547 ``` ### conductor\_transferLeaderToServer API related to consensus. TransferLeaderToServer transfers leadership to a specific server. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_transferLeaderToServer","params":[, , ],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_transferLeaderToServer --rpc-url http://127.0.0.1:8547 ``` ### conductor\_clusterMembership ClusterMembership returns the current cluster membership configuration. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_clusterMembership","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_clusterMembership --rpc-url http://127.0.0.1:8547 ``` ### conductor\_active API called by `op-node`. Active returns true if the op-conductor is active (not paused or stopped). ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_active","params":[],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} cast rpc conductor_active --rpc-url http://127.0.0.1:8547 ``` ### conductor\_commitUnsafePayload API called by `op-node`. CommitUnsafePayload commits an unsafe payload (latest head) to the consensus layer. This method is typically called by the op-node to commit execution payload envelopes. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"conductor_commitUnsafePayload","params":[{ "executionPayload": { "parentHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "feeRecipient": "0x4200000000000000000000000000000000000019", "stateRoot": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", "receiptsRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "blockNumber": "0x64", "gasLimit": "0x1c9c380", "gasUsed": "0x5208", "timestamp": "0x12345678", "extraData": "0x", "baseFeePerGas": "0x7", "blockHash": "0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba", "transactions": [] } }],"id":1}' \ http://127.0.0.1:8547 ``` ```sh theme={null} # Example with basic payload structure cast rpc conductor_commitUnsafePayload \ '{"executionPayload":{"parentHash":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef","feeRecipient":"0x4200000000000000000000000000000000000019","stateRoot":"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890","receiptsRoot":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef","blockNumber":"0x64","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x12345678","extraData":"0x","baseFeePerGas":"0x7","blockHash":"0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba","transactions":[]}}' \ --rpc-url http://127.0.0.1:8547 ``` # Setup Source: https://docs.optimism.io/chain-operators/tools/op-conductor/setup Add op-conductor to an existing multi-sequencer OP Stack network without downtime. For how op-conductor works and the guarantees it provides, see [OP Conductor](/chain-operators/tools/op-conductor). The flags and RPC methods used below are catalogued in the [configuration and RPC reference](/chain-operators/tools/op-conductor/reference). At OP Labs, op-conductor is deployed as a kubernetes statefulset because it requires a persistent volume to store the raft log. This guide describes setting up conductor on an existing network without incurring downtime. You can utilize the [op-conductor-ops](https://github.com/ethereum-optimism/infra/tree/main/op-conductor-ops) tool to confirm the conductor status between the steps. ## Assumptions This setup guide has the following assumptions: * 3 deployed sequencers (sequencer-0, sequencer-1, sequencer-2) that are all in sync and in the same vpc network * sequencer-0 is currently the active sequencer * You can execute a blue/green style sequencer deployment workflow that involves no downtime (described below) * conductor and sequencers are running in k8s or some other container orchestrator (vm-based deployment may be slightly different and not covered here) ## Spin up op-conductor Deploy a conductor instance per sequencer with sequencer-1 as the raft cluster bootstrap node: * suggested conductor configs: ```yaml theme={null} OP_CONDUCTOR_CONSENSUS_ADDR: '0.0.0.0' OP_CONDUCTOR_CONSENSUS_ADVERTISED: '' OP_CONDUCTOR_CONSENSUS_PORT: '50050' OP_CONDUCTOR_EXECUTION_RPC: ':8545' OP_CONDUCTOR_HEALTHCHECK_INTERVAL: '1' OP_CONDUCTOR_HEALTHCHECK_MIN_PEER_COUNT: '2' # set based on your internal p2p network peer count OP_CONDUCTOR_HEALTHCHECK_UNSAFE_INTERVAL: '5' # recommend a 2-3x multiple of your network block time to account for temporary performance issues OP_CONDUCTOR_LOG_FORMAT: logfmt OP_CONDUCTOR_LOG_LEVEL: info OP_CONDUCTOR_METRICS_ADDR: 0.0.0.0 OP_CONDUCTOR_METRICS_ENABLED: 'true' OP_CONDUCTOR_METRICS_PORT: '7300' OP_CONDUCTOR_NETWORK: '' OP_CONDUCTOR_NODE_RPC: ':8545' OP_CONDUCTOR_RAFT_SERVER_ID: 'unique raft server id' OP_CONDUCTOR_RAFT_STORAGE_DIR: /conductor/raft OP_CONDUCTOR_RPC_ADDR: 0.0.0.0 OP_CONDUCTOR_RPC_ENABLE_ADMIN: 'true' OP_CONDUCTOR_RPC_ENABLE_PROXY: 'true' OP_CONDUCTOR_RPC_PORT: '8547' ``` * sequencer-1 op-conductor extra config: ```yaml theme={null} OP_CONDUCTOR_PAUSED: "true" OP_CONDUCTOR_RAFT_BOOTSTRAP: "true" ``` Pause `sequencer-0` &` sequencer-2` conductors with [conductor\_pause](/chain-operators/tools/op-conductor/reference#conductor_pause) RPC request. Deploy an `op-node` config update to all sequencers that enables conductor. Use a blue/green style deployment workflow that switches the active sequencer to `sequencer-1`: * all sequencer op-node configs: ```yaml theme={null} OP_NODE_CONDUCTOR_ENABLED: "true" # this is what commits unsafe blocks to the raft logs OP_NODE_RPC_ADMIN_STATE: "" # this flag can't be used with conductor ``` Confirm `sequencer-1` is active and successfully producing unsafe blocks. Because `sequencer-1` was the raft cluster bootstrap node, it is now committing unsafe payloads to the raft log. Add voting nodes to cluster using [conductor\_AddServerAsVoter](/chain-operators/tools/op-conductor/reference#conductor_addserverasvoter) RPC request to the leader conductor (`sequencer-1`) Confirm cluster membership and sequencer state: * `sequencer-0` and `sequencer-2`: 1. raft cluster follower 2. sequencer is stopped 3. conductor is paused 4. conductor enabled in op-node config * `sequencer-1` 1. raft cluster leader 2. sequencer is active 3. conductor is paused 4. conductor enabled in op-node config Resume all conductors with [conductor\_resume](/chain-operators/tools/op-conductor/reference#conductor_resume) RPC request to each conductor instance. Confirm all conductors successfully resumed with [conductor\_paused](/chain-operators/tools/op-conductor/reference#conductor_paused) Trigger leadership transfer to `sequencer-0` using [conductor\_transferLeaderToServer](/chain-operators/tools/op-conductor/reference#conductor_transferleadertoserver) Confirm cluster membership and sequencer state: **`sequencer-1` and `sequencer-2`:** 1. raft cluster follower 2. sequencer is stopped 3. conductor is active 4. conductor enabled in op-node config **`sequencer-0`:** 1. raft cluster leader 2. sequencer is active 3. conductor is active 4. conductor enabled in op-node config Deploy a config change to `sequencer-1` conductor to remove the `OP_CONDUCTOR_PAUSED: true` flag and `OP_CONDUCTOR_RAFT_BOOTSTRAP` flag. ### Blue/green deployment In order to ensure there is no downtime when setting up conductor, you need to have a deployment script that can update sequencers without network downtime. An example of this workflow might look like: 1. Query current state of the network and determine which sequencer is currently active (referred to as "original" sequencer below). From the other available sequencers, choose a candidate sequencer. 2. Deploy the change to the candidate sequencer and then wait for it to sync up to the original sequencer's unsafe head. You may want to check peer counts and other important health metrics. 3. Stop the original sequencer using `admin_stopSequencer` which returns the last inserted unsafe block hash. Wait for candidate sequencer to sync with this returned hash in case there is a delta. 4. Start the candidate sequencer at the original's last inserted unsafe block hash. 1. Here you can also execute additional check for unsafe head progression and decide to roll back the change (stop the candidate sequencer, start the original, rollback deployment of candidate, etc.) 5. Deploy the change to the original sequencer, wait for it to sync to the chain head. Execute health checks. ### Post-conductor launch deployments After conductor is live, a similar canary style workflow is used to ensure minimal downtime in case there is an issue with deployment: 1. Choose a candidate sequencer from the raft-cluster followers 2. Deploy to the candidate sequencer. Run health checks on the candidate. 3. Transfer leadership to the candidate sequencer using `conductor_transferLeaderToServer`. Run health checks on the candidate. 4. Test if candidate is still the leader using `conductor_leader` after some grace period (ex: 30 seconds) 1. If not, then there is likely an issue with the deployment. Roll back. 5. Upgrade the remaining sequencers, run healthchecks. # Install op-deployer Source: https://docs.optimism.io/chain-operators/tools/op-deployer/installation Learn how to install op-deployer from pre-built binaries or from source. OP Deployer can be installed both from pre-built binaries and from source. This guide will walk you through both methods. ## Install From Binaries Installing OP Deployer from pre-built binaries is the easiest and most preferred way to get started. To install from binaries, download the latest release from the [releases page](https://github.com/ethereum-optimism/optimism/releases?q=op-deployer\&expanded=true) and extract the binary to a directory in your `$PATH`. ## Install From Source To install from source, you will need Go, `just`, and `git`. Then, run the following: ```shell theme={null} git clone git@github.com:ethereum-optimism/optimism.git # you can skip this if you already have the repo cd optimism/op-deployer just build cp ./bin/op-deployer /usr/local/bin/op-deployer # or any other directory in your $PATH ``` # Known Limitations Source: https://docs.optimism.io/chain-operators/tools/op-deployer/known-limitations Known limitations and workarounds for OP Deployer. OP Deployer is subject to some known limitations which we're working on addressing in future releases. ## Tagged Releases on New Chains **Fixed in all versions after v0.0.11.** It is not currently possible to deploy chains using tagged contract locators (i.e., those starting with `tag://`) anywhere except Sepolia and Ethereum mainnet. If you try to, you'll see an error like this: ``` ####################### WARNING! WARNING WARNING! ####################### You are deploying a tagged release to a chain with no pre-deployed OPCM. Due to a quirk of our contract version system, this can lead to deploying contracts containing unaudited or untested code. As a result, this functionality is currently disabled. We will fix this in an upcoming release. This process will now exit. ####################### WARNING! WARNING WARNING! ####################### ``` Like the error says, this is due to a quirk of how we version our smart contracts. We currently follow a process like this: 1. We tag a release, like op-contracts/v1.8.0. 2. We update the [release notes](https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.8.0) to reference which contracts are updated in that release. 3. We manually deploy the updated contract implementations. 4. We manually deploy a new OPCM to reference the newly-deployed implementations, as well as existing implementations for any contracts that have not been updated. There's a flaw in this strategy, however. The release only includes the contracts that explicitly changed during that release. **This means that any contract not referenced as "updated" in the release notes is "in-development," and has not been audited or approved by governance.** Deploying all contracts from the release tag will therefore deploy a combination of prod-ready and in-development code. To get the version of the contract that will *actually* run in prod, OP Deployer would have to reference all previous releases to get the correct combination of contracts. For example, to deploy on Holesky you will need to deploy contracts from versions `op-contracts/v1.8.0`, `op-contracts/v1.6.0`, and `op-contracts/v1.3.0`. On Sepolia and mainnet, we've been incrementally deploying implementation contracts so we just use the existing implementations to work around this issue. We plan on addressing this in our next release. In the meantime, as a workaround you can use a non-tagged locator for development chains, or use Sepolia or Ethereum mainnet as your L1. # OP Deployer Source: https://docs.optimism.io/chain-operators/tools/op-deployer/overview A CLI tool for deploying and upgrading smart contracts for OP Stack chains. OP Deployer is a CLI tool that simplifies deploying and upgrading smart contracts for OP Stack chains. It also exposes a suite of libraries that allow developers to easily manage smart contracts from their applications. ## Goals ### Declarative With OP Deployer, developers define their chain's desired configuration in a declarative configuration file. The tool then makes the minimum number of smart contract calls required to make the deployment match the configuration. This ensures that the implementation details of the deployment are abstracted away, and allows complex configurations to be expressed cleanly without concern for the underlying deployment process. ### Portable OP Deployer is designed to be small, portable, and easily installed. As such it is distributed as a standalone binary with no additional dependencies. This allows it to be used in a variety of contexts, including as a CLI tool, in CI pipelines, and as part of local development environments like [Kurtosis](https://github.com/ethpandaops/optimism-package). ### Standard, But Extensible OP Deployer aims to make doing the right thing easy, and doing dangerous things hard. As such its configuration and API are optimized for deploying and upgrading Standard OP Chains. However, it also exposes a lower-level set of primitives and configuration directives which users can use to deploy more complex configurations if the need arises. ## Development Status OP Deployer is undergoing active development and has been used for several mainnet deployments. It is considered production-ready. However, please keep in mind that **OP Deployer has not been audited** and that any chains deployed using OP Deployer should be checked thoroughly for correctness prior to launch. ## Next Steps * [Install op-deployer](/chain-operators/tools/op-deployer/installation) - Install from pre-built binaries or from source * [Bootstrap](/chain-operators/tools/op-deployer/usage/bootstrap) - Deploy global singletons and implementation contracts * [Architecture](/chain-operators/tools/op-deployer/reference/architecture/overview) - Understand OP Deployer's architecture # Scripting Engine Source: https://docs.optimism.io/chain-operators/tools/op-deployer/reference/architecture/engine Understand OP Deployer's in-memory EVM scripting engine: what it enables, why on-chain interactions run through Solidity scripts, and how Go code communicates with scripts inside the simulated EVM. One of OP Deployer's most powerful features is its in-memory EVM scripting engine. The scripting engine provides similar capabilities to Forge: * It runs all on-chain calls in a simulated environment first, which allows the effects of on-chain calls to be validated before they cost gas. * It exposes Foundry cheatcodes, which allow for deep instrumentation and customization of the EVM environment. These cheatcodes in turn allow OP Deployer to call into Solidity scripts. The scripting engine is really the heart of OP Deployer. Without it, OP Deployer would be nothing more than a thin wrapper over Forge. The scripting engine enables: * Easy integration with existing Solidity-based tooling. * Detailed stack traces when deployments fail. * Fast feedback loops that prevent sending on-chain transactions that may fail. * Live chain forking. For these reasons and more, the scripting engine is a critical part of OP Deployer's architecture. You will see that almost all on-chain interactions initiated by OP Deployer use the scripting engine to call into a Solidity script. The script then uses `vm.broadcast` to signal a transaction that should be sent on-chain. ## Why Use Solidity Scripts? Solidity scripts are much more ergonomic than Go code for complex on-chain interactions. They allow for: * Easy integration with existing Solidity-based tooling and libraries. * Simple ABI encoding/decoding. * Clear separation of concerns between inter-contract calls, and the underlying RPC calls that drive them. The alternative is to encode all on-chain interactions in Go code. This is possible, but it is much more verbose and requires writing bindings between Go and the Solidity ABI. These bindings are error-prone and difficult to maintain. ## Engine Implementation The scripting engine is implemented in the `op-chain-ops/script` package. It extends Geth's EVM implementation with Forge cheatcodes, and defines some tools that allow Go structs to be etched into the EVM's memory. Geth exposes hooks that drive most of the engine's behavior. The best way to understand these further is to read the code. ## Using the Engine OP Deployer uses the etching tooling described above to communicate between OP Deployer and the scripting engine. Most Solidity scripts define an input contract, an output contract, and the script itself. The script reads data from fields on the input contract, then sets fields on the output contract as it runs. OP Deployer defines the input and output contracts as Go structs, like this: ```go theme={null} package foo_script type FooInput struct { Number uint64 Bytes []byte } type FooOutput struct { Result uint64 Bytes []byte } ``` The input and output contracts are then "etched" into the EVM's memory, like this: ```go theme={null} package foo_script // ... struct defs elided func Run(host *script.Host, input FooInput) (FooOutput, error) { // Create a variable to hold our output var output FooOutput // Make new addresses for our input/output contracts inputAddr := host.NewScriptAddress() outputAddr := host.NewScriptAddress() // Inject the input/output contracts into the EVM as precompiles cleanupInput, err := script.WithPrecompileAtAddress[*FooInput](host, inputAddr, &input) if err != nil { return output, fmt.Errorf("failed to insert input precompile: %w", err) } defer cleanupInput() cleanupOutput, err := script.WithPrecompileAtAddress[*FooOutput](host, outputAddr, &output, script.WithFieldSetter[*FooOutput]) if err != nil { return output, fmt.Errorf("failed to insert output precompile: %w", err) } defer cleanupOutput() // ... do stuff with the input/output contracts ... } ``` The script engine will automatically generate getters and setters for the fields on the input and output contracts. You can use the `evm:` struct tag to customize the behavior of these getters and setters. Finally, the script itself gets etched into the EVM's memory and executed, like this: ```go theme={null} package foo_script type FooScript struct { Run func(input, output common.Address) error } func Run(host *script.Host, input FooInput) (FooOutput, error) { // .. see implementation above... deployScript, cleanupDeploy, err := script.WithScript[FooScript](host, "FooScript.s.sol", "FooScript") if err != nil { return output, fmt.Errorf("failed to load %s script: %w", scriptFile, err) } defer cleanupDeploy() if err := deployScript.Run(inputAddr, outputAddr); err != nil { return output, fmt.Errorf("failed to run %s script: %w", scriptFile, err) } return output, nil } ``` You may notice that the script is loaded from a file. To run the scripting engine, contract artifacts (**not** source code) must exist somewhere on disk for the scripting engine to use. For more information on that, see the [Artifacts Locators](/chain-operators/tools/op-deployer/reference/artifacts-locators) page. # Architecture Source: https://docs.optimism.io/chain-operators/tools/op-deployer/reference/architecture/overview Understand OP Deployer's architecture and internals. This section details OP Deployer's architecture and internals. Unless you're contributing directly to OP Deployer, you don't need to read this. * [Deployment Pipeline](/chain-operators/tools/op-deployer/reference/architecture/pipeline): Describes the stages of the deployment pipeline. * [Scripting Engine](/chain-operators/tools/op-deployer/reference/architecture/engine): Describes the scripting engine that OP Deployer uses to interact with the EVM. Full architecture diagram *Full architecture diagram ([source](https://www.figma.com/board/bbp16y6ZwIkxzOoKhDu9kk/op-deployer-architecture?node-id=0-1\&p=f\&t=1Eg9JBP0RuVmdtsM-0))* # Deployment Pipeline Source: https://docs.optimism.io/chain-operators/tools/op-deployer/reference/architecture/pipeline Understand how OP Deployer's pipeline is architected: the intent and state files it consumes and produces, and what each deployment stage is responsible for. This page explains how OP Deployer is architected: a pipeline in which each stage is responsible for a single piece of the deployment process. The pipeline consumes a configuration called an *intent* which describes the desired state of the chain, and produces a file called the *state* which describes the current state of the chain during and after the deployment. The steps of the pipeline are: 1. Initialization 2. Shared Contracts Deployment 3. Implementations Deployment 4. OP Chain Deployment 5. Alt-DA Deployment 6. Dispute Game Deployment 7. L2 Genesis Generation 8. Setting Start Block State is written to disk after each state. This allows the pipeline to be restarted from any point in the event of a recoverable error. We'll cover each of these stages in more detail below. ## Initialization During this step, OP Deployer sets initial values for the pipeline based on the user's intent. These values will be used by downstream stages. For example, if the user is deploying using an existing set of shared contracts, those contracts will be inserted into the state during this step. ## Shared Contracts/Implementations Deployment Next, the base contracts for the chain are deployed. This includes shared management contracts like `SuperchainConfig`, as well as implementation contracts that will be used for the OP Chain deployment in the future like the OP Contracts Manager (OPCM). Most chains will be configured to use existing implementations. In this case, these steps will be skipped. ## OP Chain Deployment The OP Chain itself is deployed during this step. Multiple chains will be deployed if they are specified in the intent. The deployment works by calling into the OPCM, which will emit an event for each successfully-deployed chain. ## Customizations Deployment The next two steps (Alt-DA and Dispute Game) deploy customizations. As their names imply, they deploy Alt-DA and additional dispute game contracts. Typically, these steps will be skipped as they are mostly useful in testing. ## L2 Genesis Generation This step generates the L2 Genesis file which is used to initialize the chain. This file is generated by calling into `L2Genesis.sol`, and dumping the outputted state. ## Setting Start Block Lastly, the start block is set to the current block number on L1. This is done last to ensure that the start block is relatively recent, since the deployment process can take arbitrarily long. # Artifacts Locators Source: https://docs.optimism.io/chain-operators/tools/op-deployer/reference/artifacts-locators Learn how OP Deployer uses artifacts locators to point to contract artifacts. OP Deployer calls into precompiled contract artifacts. To make this work, OP Deployer uses artifacts locators to point to the location of contract artifacts. While locators are nothing more than URLs, they do encode some additional behaviors which are described here. ## Locator Types Locators can be one of three types: * `tag://` locators, which point to a versioned contracts release. These resolve to a known URL. Artifacts downloaded using a tagged locator are validated against a hardcoded checksum in the OP Deployer implementation. This prevents tampering with the contract artifacts once they have been tagged. Additionally, tagged locators are cached on disk to avoid repeated downloads. * ex: `tag://op-contracts/v1.8.0-rc.4` * `https://` locators, which point to a tarball of contract artifacts somewhere on the web. HTTP locators are cached just like tagged locators are, but they are not validated against a checksum. * ex: `https://` * `file://` locators, which point to a directory on local disk containing the artifacts. * ex: `file:///packages/contracts-bedrock/forge-artifacts` # op-deployer versioning and releases Source: https://docs.optimism.io/chain-operators/tools/op-deployer/reference/releases Reference for where to find OP Deployer releases and how each OP Deployer version maps to a supported contract release. ## Latest Releases The latest version of OP Deployer is always available at [releases](https://github.com/ethereum-optimism/optimism/releases?q=op-deployer\&expanded=true). You should search for `op-deployer` to exclude other packages. ## Versioning For all releases after `v0.0.11`, each minor version of OP Deployer will support a single release of the governance-approved smart contracts. If you want to deploy an earlier version of the contracts (which may be dangerous!), you should use an earlier version of OP Deployer. This setup allows our smart contract developers to make breaking changes on `develop`, while still allowing new chains to be deployed and upgraded using production-ready smart contracts. If you deploy from an HTTPS or file [locator](/chain-operators/tools/op-deployer/reference/artifacts-locators), the deployment behavior will match the contract's tag. For example, if version `v0.2.0` supports `v2.0.0` then the deployment will work as if you were deploying `op-contracts/v2.0.0`. Typically, errors like `unknown selector: ` imply that you're using the wrong version of OP Deployer for your contract artifacts. If this happens, we recommend trying different versions until you get one that works. Note that this workflow is **not recommended** for production chains. ## Contributor Workflows Step-by-step procedures for backporting fixes onto earlier OP Deployer versions and adding support for new contract versions live in [Release Workflows](/chain-operators/tools/op-deployer/usage/release-workflows). # Apply Command Source: https://docs.optimism.io/chain-operators/tools/op-deployer/usage/apply Learn how to deploy your OP Chain based on the intent file. Once you have [initialized](/chain-operators/tools/op-deployer/usage/init) your intent and state files, you can use the `apply` command to perform the deployment. ## Usage You can call the `apply` command like this: ```shell theme={null} op-deployer apply \ --workdir \ <... additional arguments ...> ``` You will need to specify additional arguments depending on what you're trying to do. See below for a reference of each supported CLI arg. ## CLI Arguments ### `--deployment-target` **Default:** `live` `--deployment-target` specifies where each chain should be deployed to. It can be one of the following values: * `live`: Deploys to a live L1. Concretely, this means that OP Deployer will send transactions identified by `vm.broadcast` calls to L1. `--l1-rpc-url` and `--private-key` must be specified when using this target. * `genesis`: Deploys to an L1 genesis file. This is useful for testing or local development purposes. You do not need to specify any additional arguments when using this target. * `calldata`: Deploys to a calldata file. This is useful for generating inputs to multisig wallets for future execution. * `noop`: Doesn't deploy anything. This is useful for performing a dry-run of the deployment process prior to another deployment target. ### `--l1-rpc-url` Defines the RPC URL of the L1 chain to deploy to. ### `--private-key` Defines the private key to use for signing transactions. This is only required for deployment targets that involve sending live transactions. Note that ownership over each L2 is transferred to the proxy admin owner specified in the intent after the deployment completes, so it's OK to use a hot key for this purpose. # Bootstrap Commands Source: https://docs.optimism.io/chain-operators/tools/op-deployer/usage/bootstrap Learn how to deploy global singletons and implementation contracts for new OP Stack deployments. If you are joining an existing OP Stack deployment, you can skip to the [`init`](/chain-operators/tools/op-deployer/usage/init) and [`apply`](/chain-operators/tools/op-deployer/usage/apply) commands to create your L2 chain(s). Bootstrap commands are used to deploy global singletons and implementation contracts for new OP Stack deployments. The deployed contracts can then be used with future invocations of `apply` so that new L2 chains can join that deployment. Most users won't need to use these commands, since `op-deployer apply` will automatically use standard predeployed contracts for the L1/settlement-layer you are deploying on. However, you will need to use bootstrap commands if you're creating a new standalone deployment. There are several bootstrap commands available, which you can view by running `op-deployer bootstrap --help`. We'll focus on the most important ones, which should be run in the sequence listed below. **It is safe to call these commands from a hot wallet.** None of the contracts deployed by these command are "ownable," so the deployment address has no further control over the system. ## Bootstrap Shared Contracts ```shell theme={null} op-deployer bootstrap superchain \ --l1-rpc-url="" \ --private-key="" \ --outfile="./.deployer/bootstrap_superchain.json" \ --superchain-proxy-admin-owner="" \ --guardian="" ``` ### CLI Arguments #### `--superchain-proxy-admin-owner`, `--guardian` In a dev environment, these can all be hot wallet EOAs. In a production environment, `--guardian` should be an HSM (hardware security module) protected hot wallet and `--superchain-proxy-admin-owner` should be a multisig cold-wallet (e.g. Gnosis Safe). ### Output This command will deploy several contracts, and output a JSON like the one below: ```json theme={null} { "proxyAdminAddress": "0x269b95a33f48a9055b82ce739b0c105a83edd64a", "superchainConfigImplAddress": "0x2f4c87818d67fc3c365ea10051b94f98893f3c64", "superchainConfigProxyAddress": "0xd0c74806fa114c0ec176c0bf2e1e84ff0a8f91a1" } ``` ## Bootstrap Implementations ```shell theme={null} op-deployer bootstrap implementations \ --l1-rpc-url="" \ --outfile="./.deployer/bootstrap_implementations.json" \ --private-key="" \ --superchain-config-proxy="" \ --superchain-proxy-admin="" \ --challenger="" \ --upgrade-controller="" ``` ### Output This command will deploy implementations, blueprints, and the OPCM. Deployments are (for the most part) deterministic, so contracts will only be deployed once per chain as long as the implementation and constructor args remain the same. This applies to the `op-deployer apply` pipeline - that is, if someone else ran `op-deployer bootstrap implementations` at some point on a given L1 chain, then the `apply` pipeline will re-use those implementations. The command will output a JSON like the one below: ```json theme={null} { "opcmAddress": "0x82879934658738b6d5e8f781933ae7bbae05ba31", "opcmContractsContainerAddress": "0x1e8de1574a2e085b7a292c760d90cf982d3c1a11", "opcmGameTypeAdderAddress": "0xcab868d42d9088b86598a96d010db5819c19b847", "opcmDeployerAddress": "0xf8b6718b28fa36b430334e78adaf97174fed818c", "opcmUpgraderAddress": "0xa4d0a44890fafce541bdc4c1ca36fca1b5d22f56", "opcmInteropMigratorAddress": "0xf0fca53bb450dd2230c7eb58a39a5dbfc8492fb6", "opcmStandardValidatorAddress": "0x1364a02f64f03cd990f105058b8cc93a9a0ab2a1", "delayedWETHImplAddress": "0x570da3694c06a250aea4855b4adcd09505801f9a", "optimismPortalImplAddress": "0x1aa1d3fc9b39d7edd7ca69f54a35c66dcf1168f1", "ethLockboxImplAddress": "0xe6e51fa10d481002301534445612c61bae6b3258", "preimageOracleSingletonAddress": "0x1fb8cdfc6831fc866ed9c51af8817da5c287add3", "mipsSingletonAddress": "0x7a8456ba22df0cb303ae1c93d3cf68ea3a067006", "systemConfigImplAddress": "0x9f2b1fffd8a7aeef7aeeb002fd8477a4868e7e0a", "l1CrossDomainMessengerImplAddress": "0x085952eb0f0c3d1ca82061e20e0fe8203cdd630a", "l1ERC721BridgeImplAddress": "0xbafd2cae054ddf69af27517c6bea912de6b7eb8f", "l1StandardBridgeImplAddress": "0x6abaa7b42b9a947047c01f41b9bcb8684427bf24", "optimismMintableERC20FactoryImplAddress": "0xdd0b293b8789e9208481cee5a0c7e78f451d32bf", "disputeGameFactoryImplAddress": "0xe7ab0c07ee92aae31f213b23a132a155f5c2c7cc", "anchorStateRegistryImplAddress": "0xda4f46fad0e38d763c56da62c4bc1e9428624893", "superchainConfigImplAddress": "0xdaf60e3c5ef116810779719da88410cce847c2a4" } ``` # Custom Deployments Source: https://docs.optimism.io/chain-operators/tools/op-deployer/usage/custom-deployments Learn how to manage custom deployments with OP Deployer. While OP Deployer was designed primarily for use with chains that are governed by Optimism, it also supports managing custom deployments. This is particularly common for RaaS providers, whose customers often request deployments with custom L1s (or L2s, in the case of L3s) or governance. This guide will walk you through the process of managing these chains using OP Deployer. Chains deployed in this way are not subject to Optimism Governance. They may be running customized or unaudited code. Use at your own risk. ## Bootstrapping The first step to deploying a custom OP Stack is to bootstrap it onto an L1. This process will: * Deploy shared management contracts like `SuperchainConfig` and `SuperchainVersions`. * Deploy contract implementations that will be shared among all OP Chains in this deployment. * Set up ownership so that you can control the deployment. You will use the [`bootstrap`](/chain-operators/tools/op-deployer/usage/bootstrap) family of commands on `op-deployer` to do this. ### Bootstrap Shared Contracts Every OP Chain belongs to a logical deployment group. This group consists of a set of shared contracts that control the behavior of a group of OP Chains. This includes: * Pausing bridges * Signaling which protocol versions are required and recommended You can deploy a new set of shared contracts for each OP Chain, or you can deploy them once and share across multiple OP Chains. The choice is up to the deployer. Note that you **cannot** share a set of shared contracts across multiple L1s. To begin, bootstrap the shared contracts onto your chosen L1 with the following command: ```shell theme={null} op-deployer bootstrap superchain \ --l1-rpc-url="" \ --private-key="" \ --artifacts-locator="" \ --outfile="" \ --superchain-proxy-admin-owner="" \ --guardian="" ``` This will output a JSON file containing the addresses of the relevant contracts. Keep track of this file, as you will need it in subsequent steps. We recommend the following these best practices when bootstrapping: 1. Use Gnosis SAFEs for ownership roles like `guardian` and `superchain-proxy-admin-owner`. The owner **must** be a smart contract to support future upgrades, so a SAFE is a sensible default. 2. Use a regular EOA as the deployer. It will not have any control over the deployment once the deployment completes. 3. Use a standard contracts tag (e.g. `tag://op-contracts/v2.0.0`). This will make upgrading easier. ### Bootstrapping Implementations The smart contracts for an OP Chain are deployed using a factory that points to a set of predeployed implementations. You must deploy the factory and the implementations every time you deploy to a new L1 and whenever new smart contract versions are released. Implementations are deployed using `CREATE2`, so addresses may be reused if they already exist on the L1. You may need to use different versions of OP Deployer depending on which contracts version you are deploying. See the [releases guide](/chain-operators/tools/op-deployer/reference/releases) for more information on picking the right release. To deploy the implementations, use the following command: ```shell theme={null} op-deployer bootstrap implementations \ --artifacts-locator="" \ --l1-rpc-url="" \ --outfile="" \ --mips-version="2" \ --private-key="" \ --superchain-config-proxy="
" \ --upgrade-controller="" ``` Similar to the `bootstrap superchain` command, this will output a JSON file containing the addresses of the relevant contracts. Again, keep track of this file. The most important address in the implementations file is the OPCM, or OP Contracts Manager. This contract is the factory that will deploy all the OP Chains belonging to this deployment group. It is also responsible for upgrading between different contracts versions. Please keep the following **very important** invariants in mind with the OPCM: * There is a one-to-one mapping between each OPCM, and contracts version. * Each OPCM is associated with **exactly one** deployment group. This means that you **must** deploy a new OPCM using the `bootstrap implementations` command for each new deployment group you manage. ## Deploying After bootstrapping the contracts and implementations, you can deploy your L2 chains with the `apply` command. You will need to specify a `configType` of `standard-overrides` and set the `opcmAddress` field in your intent to the address of the OPCM above. **Make sure you call the right OPCM.** Failing to call the right OPCM might lead to deploying incorrect contract versions, or associating your chain with the wrong deployment. Make sure that you use the same `l1ContractsLocator` and `l2ContractsLocator` as the ones used in the bootstrap commands. Otherwise, you may run into deployment errors. See the following config for an example: ```toml theme={null} configType = "standard-overrides" l1ChainID = 11155420 opcmAddress = "0x..." l1ContractsLocator = "tag://..." # must match the one used in bootstrap l2ContractsLocator = "tag://..." [[chains]] # Chain configs... ``` Once `apply` completes successfully, you can use the `inspect` family of commands to download your chain's L2 genesis and rollup config files. ## Upgrading The `op-deployer upgrade` command supports upgrades up to `op-contracts/v5.0.0` only. It does **not** support upgrading from `op-contracts/v5.0.0` to `op-contracts/v6.0.0`. For upgrades beyond v5.0.0, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide) or interact with the OPCM directly. See the [notice](/notices/archive/op-deployer-upgrade-deprecation) for details. # Init Command Source: https://docs.optimism.io/chain-operators/tools/op-deployer/usage/init Learn how to initialize intent and state files for your OP Stack deployment. The `init` command is used to create a new intent and state file in the specified directory. This command is the starting point of each new deployment. ## Usage The `init` command is used like this: ```shell theme={null} op-deployer init \ --l1-chain-id \ --l2-chain-ids \ --outdir \ --intent-type ``` You should then see the following files appear in your output directory: ``` outdir ├── intent.toml └── state.json ``` The `intent.toml` file is where you specify the configuration for your deployment. The `state.json` file is where OP Deployer will output the current state of the deployment after each stage of the deployment. ## Intent File Your intent should look something like this: ```toml theme={null} configType = "standard" l1ChainID = 11155420 fundDevAccounts = false useInterop = false l1ContractsLocator = "tag://op-contracts/v1.8.0-rc.4" l2ContractsLocator = "tag://op-contracts/v1.7.0-beta.1+l2-contracts" [superchainRoles] proxyAdminOwner = "0xeAAA3fd0358F476c86C26AE77B7b89a069730570" guardian = "0xeAAA3fd0358F476c86C26AE77B7b89a069730570" [[chains]] id = "0x0000000000000000000000000000000000000000000000000000000000002390" baseFeeVaultRecipient = "0x0000000000000000000000000000000000000000" l1FeeVaultRecipient = "0x0000000000000000000000000000000000000000" sequencerFeeVaultRecipient = "0x0000000000000000000000000000000000000000" operatorFeeVaultRecipient = "0x0000000000000000000000000000000000000000" eip1559DenominatorCanyon = 250 eip1559Denominator = 50 eip1559Elasticity = 6 [chains.roles] l1ProxyAdminOwner = "0x0000000000000000000000000000000000000000" l2ProxyAdminOwner = "0x0000000000000000000000000000000000000000" systemConfigOwner = "0x0000000000000000000000000000000000000000" unsafeBlockSigner = "0x0000000000000000000000000000000000000000" batcher = "0x0000000000000000000000000000000000000000" proposer = "0x0000000000000000000000000000000000000000" challenger = "0x0000000000000000000000000000000000000000" ``` Before you can use your intent file for a deployment, you will need to update all zero values to whatever is appropriate for your chain. For dev environments, it is ok to use all EOAs/hot-wallets. ## Production Setup In production environments, you should use a more secure setup with cold-wallet multisigs (e.g. Gnosis Safes) for the following: * `baseFeeVaultRecipient` * `l1FeeVaultRecipient` * `sequencerFeeVaultRecipient` * `operatorFeeVaultRecipient` * `l1ProxyAdminOwner` * `l2ProxyAdminOwner` * `systemConfigOwner` HSMs (hardware security modules) are recommended for the following hot-wallets: * `unsafeBlockSigner` * `batcher` * `proposer` * `challenger` # Release Workflows Source: https://docs.optimism.io/chain-operators/tools/op-deployer/usage/release-workflows Learn how to backport fixes onto earlier OP Deployer versions and add support for new contract versions. This page is for people developing OP Deployer itself. If you only need to pick the right OP Deployer release for your contract version, see the [releases reference](/chain-operators/tools/op-deployer/reference/releases). ## Backport a Fix to an Earlier Version From time to time, we may backport bugfixes from develop onto earlier versions of OP Deployer. The process for this is as follows: 1. If one doesn't exist already, make a new branch for the version lineage you're patching (e.g. `v0.2.x`). This branch should be protected (not deletable) and should be based on the latest release of that lineage. The branch should be named as follows: `backports/op-deployer/`. 2. Open a PR with the backport against that branch. Be sure to reference the original commit in the backport. 3. Make and push a new tag on that lineage. Example for backporting fix(es) from `develop` to create a new release `op-deployer/v0.2.1`: ``` git checkout -b backports/op-deployer/v0.2.0 op-deployer/v0.2.0 git push origin backports/op-deployer/v0.2.0 git checkout -b fixes/deployer-v0.2.0 backports/op-deployer/v0.2.0 git cherry-pick git push origin fixes/deployer-v0.2.0 1. open pr from fixes/deployer-v0.2.0 targeting backports/op-deployer/v0.2.0 2. merge the pr 3. push a new tag for op-deployer/v0.2.1 on backports/op-deployer/v0.2.0 branch (goreleaser will create the release) ``` ## Add Support for a New Contract Version Adding support for a new contract version is a multi-step process. Here's a high-level overview. For the sake of simplicity we will assume you are adding support for a new `rc` release. ### Step 1: Add Support on Develop First, you need to add support for the new contract version on the `develop` branch. This means ensuring that the deployment pipeline supports whatever changes are required for the new version. Typically, this means passing in new deployment variables, and responding to ABI changes in the Solidity scripts/OPCM. ### Step 2: Add the Published Artifacts Run the following from the root of the monorepo: ```bash theme={null} cd packages/contracts-bedrock just clean just build bash scripts/ops/calculate-checksum.sh # copy the outputted checksum cd ../../op-deployer just calculate-artifacts-hash ``` This will calculate the checksum of your artifacts as well as the hash of the artifacts tarball. OP Deployer uses these values to download and verify tagged contract locators. Now, update `standard/standard.go` with these values so that the new artifacts tarball can be downloaded: ```go theme={null} // Add a new const for your release const ContractsVXTag = "op-contracts/vX.Y.Z" var taggedReleases = map[string]TaggedRelease{ // Other releases... ContractsVXTag: { ArtifactsHash: common.HexToHash(""), ContentHash: common.HexToHash(""), }, } // Update the L1/L2 versions accordingly func IsSupportedL1Version(tag string) bool { return tag == ContractsVXTag } ``` ### Step 3: Update the SR With the New Release Add the new RC to the [standard versions](https://github.com/ethereum-optimism/superchain-registry/tree/main/validation/standard) in the superchain-registry. ### Step 4: Update the Validation Package The SR is pulled into OP Deployer via the `validation` package. Update it by running the following command from the root of the monorepo: ```shell theme={null} go get -u github.com/ethereum-optimism/superchain-registry/validation@ ``` That should be it! # Verify Command Source: https://docs.optimism.io/chain-operators/tools/op-deployer/usage/verify Learn how to verify deployed contract source code on block explorers. Once you have deployed contracts via [`bootstrap`](/chain-operators/tools/op-deployer/usage/bootstrap) or [`apply`](/chain-operators/tools/op-deployer/usage/apply), you can use the `verify` command to verify the source code on block explorers like Etherscan or Blockscout. The command uses the `forge verify-contract` binary, which automatically handles constructor argument detection and source code verification. ## Usage You can call the `verify` command like this: ```shell theme={null} op-deployer verify \ --l1-rpc-url \ --input-file \ --verifier-api-key \ --artifacts-locator \ --verifier etherscan ``` For Blockscout verification (uses default URLs for mainnet/sepolia, no API key required): ```shell theme={null} op-deployer verify \ --l1-rpc-url \ --input-file \ --artifacts-locator \ --verifier blockscout ``` For custom block explorer verification (Etherscan v2-compatible, API key may be required): ```shell theme={null} op-deployer verify \ --l1-rpc-url \ --input-file \ --artifacts-locator \ --verifier custom \ --verifier-url ``` ## CLI Arguments ### `--l1-rpc-url` Defines the RPC URL of the L1 chain to deploy to (currently only supports mainnet and sepolia). ### `--input-file` The full filepath to the input file. This can be either: * A simple JSON file with contract name/address pairs (output from `bootstrap superchain|implementations`) * A complete `state.json` file (output from `apply`) The verifier automatically detects the file format and extracts all contracts. Unless the `--contract-name` flag is passed, all contracts in the input file will be verified. Example: ```json theme={null} { "opcmAddress": "0x437d303c20ea12e0edba02478127b12cbad54626", "opcmContractsContainerAddress": "0xf89d7ce62fc3a18354b37b045017d585f7e332ab", "opcmGameTypeAdderAddress": "0x9aa4b6c0575e978dbe6d6bc31b7e4403ea8bd81d", "opcmDeployerAddress": "0x535388c15294dc77a287430926aba5ba5fe6016a", "opcmUpgraderAddress": "0x68a7a93750eb56dd043f5baa41022306e6cd50fa", "delayedWETHImplAddress": "0x33ddc90167c923651e5aef8b14bc197f3e8e7b56", "optimismPortalImplAddress": "0x54b75cb6f44e36768912e070cd9cb995fc887e6c", "ethLockboxImplAddress": "0x05484deeb3067a5332960ca77a5f5603df878ced", "preimageOracleSingletonAddress": "0xfbcd4b365f97cb020208b5875ceaf6de76ec068b", "mipsSingletonAddress": "0xcc50288ad0d79278397785607ed675292dce37b1", "systemConfigImplAddress": "0xfb24aa6d99824b2c526768e97b23694aa3fe31d6", "l1CrossDomainMessengerImplAddress": "0x957c0bf84fe541efe46b020a6797fb1fb2eaa6ac", "l1ERC721BridgeImplAddress": "0x62786d16978436f5d85404735a28b9eb237e63d0", "l1StandardBridgeImplAddress": "0x6c9b377c00ec7e6755aec402cd1cfff34fa75728", "optimismMintableERC20FactoryImplAddress": "0x3842175f3af499c27593c772c0765f862b909b93", "disputeGameFactoryImplAddress": "0x70ed1725abb48e96be9f610811e33ed8a0fa97f9", "anchorStateRegistryImplAddress": "0xce2206af314e5ed99b48239559bdf8a47b7524d4", "superchainConfigImplAddress": "0x77008cdc99fb1cf559ac33ca3a67a4a2f04cc5ef" } ``` ### `--contract-name` (optional) Specifies a single contract name, matching a contract key within the input file, to verify. If not provided, all contracts in the input file will be verified. ### `--artifacts-locator` The locator to forge-artifacts containing the output of the `forge build` command (i.e. compiled bytecode and solidity source code). This can be a local path (with a `file://` prefix), remote URL (with a `http://` or `https://` prefix), or standard contracts tag (with a `tag://op-contracts/v` prefix). ### `--verifier` The block explorer(s) to use for verification. Supports multiple verifiers separated by commas. Options: * `etherscan` (default): Uses Etherscan for mainnet/sepolia * `blockscout`: Uses default Blockscout URLs for mainnet/sepolia * `custom`: For custom Etherscan v2-compatible instances (requires `--verifier-url`) Examples: * Single verifier: `--verifier etherscan` * Multiple verifiers: `--verifier etherscan,blockscout` (verifies on both) ### `--verifier-url` The verifier API URL. Usage varies by verifier type: * `etherscan`: Ignored (automatically determined from chain ID) * `blockscout`: Optional (defaults to standard Blockscout URLs for mainnet/sepolia) * `custom`: Required. Example: `https://etherscanv2.compat-api.example.com/api` ## Output Output logs will be printed to the console and look something like the following. If the final results show `numFailed=0`, all contracts were verified successfully. ```sh theme={null} INFO [03-05|15:56:55.900] Formatting etherscan verify request name=superchainConfigProxyAddress address=0x805fc6750ec23bdD58f7BBd6ce073649134C638A INFO [03-05|15:56:55.900] Opening artifact path=Proxy.sol/Proxy.json name=superchainConfigProxyAddress INFO [03-05|15:56:55.905] contractName name=src/universal/Proxy.sol:Proxy INFO [03-05|15:56:55.905] Extracting constructor args from initcode address=0x805fc6750ec23bdD58f7BBd6ce073649134C638A argSlots=1 INFO [03-05|15:56:56.087] Contract creation tx hash txHash=0x71b377ccc11304afc32e1016c4828a34010a0d3d81701c7164fb19525ba4fbc4 INFO [03-05|15:56:56.494] Successfully extracted constructor args address=0x805fc6750ec23bdD58f7BBd6ce073649134C638A INFO [03-05|15:56:56.683] Verification request submitted name=superchainConfigProxyAddress address=0x805fc6750ec23bdD58f7BBd6ce073649134C638A INFO [03-05|15:57:02.035] Verification complete name=superchainConfigProxyAddress address=0x805fc6750ec23bdD58f7BBd6ce073649134C638A INFO [03-05|15:57:07.971] --- COMPLETE --- INFO [03-05|15:57:07.971] final results numVerified=2 numSkipped=1 numFailed=0 ``` ## Automatic Verification You can automatically verify contracts after deployment by using the `--verify` flag with `apply` or `bootstrap` commands: ```shell theme={null} op-deployer apply \ --workdir ./.deployer \ --l1-rpc-url \ --private-key \ --verify \ --verifier-api-key ``` This will verify all deployed contracts at the end of the deployment process. ### Multi-Verifier Deployment You can verify on multiple block explorers simultaneously: ```shell theme={null} op-deployer bootstrap superchain \ --l1-rpc-url \ --private-key \ --outfile ./superchain.json \ --superchain-proxy-admin-owner \ --guardian \ --verify \ --verifier etherscan,blockscout \ --verifier-api-key ``` This will: 1. Deploy the shared contracts 2. Verify on Etherscan (using the API key) 3. Verify on Blockscout (no API key required) 4. Report combined results from both verifiers ## Supported Contract Bundles The verify command now supports all contract bundles: * **Shared** contracts (from `bootstrap superchain`) * **Implementations** contracts (from `bootstrap implementations`) * **OpChain** contracts (from `apply` - including all chain-specific contracts) When using a `state.json` file from `apply`, the verifier automatically extracts and verifies contracts from all deployment stages. ## Block Explorer Support The verification command supports both Etherscan and Blockscout block explorers through the forge binary, alongside any Etherscan v2 compatible APIs. # OP Interop Filter Source: https://docs.optimism.io/chain-operators/tools/op-interop-filter Learn how op-interop-filter validates interop executing messages so the execution layer can reject invalid cross-chain transactions before they reach the sequencer. OP Stack interop is in active development. op-interop-filter is the service chain operators will run to validate interop transactions for the execution layer, and the interfaces described here may continue to evolve as the rollout progresses. *op-interop-filter* is a lightweight service that validates interop executing messages so that an execution layer (EL) client — op-reth — can reject invalid cross-chain transactions before they reach the sequencer's transaction pool. It is the service a chain operator runs to answer the `interop_checkAccessList` RPC that the EL calls on every interop transaction. ## What op-interop-filter does An interop transaction carries an *access list* of references to initiating messages on other chains in the dependency set. For the transaction to be valid, every referenced initiating message must exist on its source chain at the safety level the executing chain requires. The EL cannot answer that question on its own. It calls a configured interop verification endpoint over JSON-RPC (`interop_checkAccessList`) and lets that service decide whether the transaction is admissible. op-interop-filter is one such service. It connects to the L2 RPCs of every chain in the dependency set, ingests their logs into a local database, and answers `interop_checkAccessList` against that database. When the answer is no — or when the filter has lost confidence in its own state — the EL rejects the transaction. ## How it fits into an interop deployment op-interop-filter sits between an interop chain's EL and the other chains in its dependency set. ```mermaid theme={null} graph LR classDef filter fill:#FFE classDef transparent fill:none,stroke:none EL["Execution layer
(op-reth)"] Filter["op-interop-filter"] L2A["L2 RPC
Chain A"] L2B["L2 RPC
Chain B"] L2N["L2 RPC
Chain N"] EL -- "interop_checkAccessList" --> Filter Filter --> L2A Filter --> L2B Filter --> L2N class Filter filter ``` The EL points at the filter through op-reth's `--rollup.interop-http` flag and calls the filter's `interop_checkAccessList` method to validate each interop transaction. This is a different job from what [op-supernode](/op-stack/interop/supernode) does. The supernode operates at the consensus layer (CL): it verifies that a block's cross-chain dependencies have been reproduced from L1, then promotes the block to *safe* through the chain's own CL. op-interop-filter works at transaction-admission time instead: it is the separate service the execution layer consults to decide whether an interop transaction may enter the pool in the first place. A chain operator running an interop chain runs both. ## Failsafe behavior op-interop-filter has a *failsafe* that, while active, rejects every `interop_checkAccessList` request with `ErrFailsafeEnabled`. The EL gates interop transactions on that check, so while failsafe is active no interop transactions are admitted. Regular transactions that carry no interop access-list entries are unaffected and keep flowing normally. Failsafe activates in one of two ways: * **Automatically**, when any chain ingester reports an error — a reorg, a database conflict, data corruption, or an invalid executing message — or when the cross-validator reports an error. * **Manually**, when an operator enables it over the admin RPC with `admin_setFailsafeEnabled`. How failsafe clears depends on why it triggered: * A **manual** failsafe clears when the operator calls `admin_setFailsafeEnabled` with `false`. * A **reorg-triggered** failsafe clears automatically only when `--reorg-recovery-enabled` is set: the filter rewinds each affected chain's logs database to its finalized block and clears the error. * Any failsafe that is neither manual nor auto-resolved — a reorg with `--reorg-recovery-enabled` off, a database conflict, data corruption, an invalid executing message, or a cross-validation failure — has no admin RPC to clear it. Recover by wiping the filter's data directory and restarting the service. Disabling the manual override with `admin_setFailsafeEnabled` does not clear an error-triggered failsafe; the underlying error has to be resolved first. ## Configuration op-interop-filter is configured via CLI flags or matching `OP_INTEROP_FILTER_*` environment variables. The full flag set is defined in [`op-interop-filter/flags/flags.go`](https://github.com/ethereum-optimism/optimism/blob/develop/op-interop-filter/flags/flags.go). ### Required flags | Flag | Description | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--l2-rpcs` | L2 RPC endpoints to connect to. The filter queries the chain ID from each endpoint and matches it against a loaded rollup config. | | `--networks` *or* `--rollup-configs` | At least one is required. `--networks` loads rollup configs by name from the superchain registry; `--rollup-configs` loads custom JSON files for dev or test chains. | ### Key optional flags | Flag | Default | Description | | -------------------------- | --------------------- | -------------------------------------------------------------------------------------------------- | | `--data-dir` | (temporary directory) | Directory for the LogsDB. Use a persistent path in production so backfill state survives restarts. | | `--backfill-duration` | `24h` | How far back to backfill on startup. | | `--message-expiry-window` | `168h` (7 days) | Messages older than this window are treated as expired. | | `--poll-interval` | `2s` | How often to poll L2 RPCs for new blocks. | | `--reorg-recovery-enabled` | off | If set, the filter automatically clears reorg-triggered failsafe by rewinding to finalized. | | `--admin.rpc.addr` | (disabled) | Bind address for the JWT-protected admin RPC. When set, `--admin.jwt-secret` is also required. | ### Use-with-caution flags Two flags are marked DANGEROUS in source and should only be used with a deliberate operational reason: | Flag | What it does | | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--dangerously-enable-passthrough` | Lets every transaction through without interop filtering. Disables all executing-message validation. | | `--support-legacy-check-access-list-format` | Accepts `interop_checkAccessList` requests that omit the executing chain ID. Intended only for compatibility with legacy clients; access-list source-chain validation still runs. | ## RPC surface op-interop-filter exposes two HTTP RPC endpoints, configured separately. ### Public RPC Bound by `--rpc.addr` (default `0.0.0.0`) and `--rpc.port` (default `8545`). Exposes the methods an EL or other consumer needs: * `interop_checkAccessList` — validates an executing-message access list at a minimum safety level. This is the method the EL calls on every interop transaction. * `interop_getBlockHashByNumber` — returns the latest ingested block hash for a chain, or the hash at a specific height. * `admin_getFailsafeEnabled` — read-only check of whether failsafe is currently active. ### Admin RPC Disabled by default. Bound by `--admin.rpc.addr` and `--admin.rpc.port` (default `8546`), and protected by a JWT secret loaded from `--admin.jwt-secret`. The admin RPC exposes the operator-only controls: * `admin_setFailsafeEnabled` — manually enable or disable failsafe. * `admin_getFailsafeEnabled` — the authenticated read of the same state available on the public RPC. Admin RPC is intended for operator tooling and should not be exposed publicly. ## Where to go next * Read the [interop explainer](/op-stack/interop/explainer) for how cross-chain messaging and executing-message access lists work at the protocol level. * Read the [op-supernode page](/op-stack/interop/supernode) for the consensus-layer side of an interop deployment — block-safety promotion and the supernode topology. * Read [interop reorg awareness](/op-stack/interop/reorg) for how reorgs interact with cross-chain message safety. * For implementation detail, see the [op-interop-filter source](https://github.com/ethereum-optimism/optimism/tree/develop/op-interop-filter) in the monorepo. # OP Txproxy Source: https://docs.optimism.io/chain-operators/tools/op-txproxy A passthrough proxy service that can apply additional constraints on transactions prior to reaching the sequencer. A [passthrough proxy](https://github.com/ethereum-optimism/infra/tree/main/op-txproxy) for the execution engine endpoint. This proxy does not forward all RPC traffic and only exposes a specific set of methods. Operationally, the ingress router should only re-route requests for these specific methods. [proxyd](./proxyd) as an ingress router supports the mapping of specific methods to unique backends. ## Methods ### **eth\_sendRawTransactionConditional** To safely expose this endpoint publicly, additional stateless constraints are applied. These constraints help scale validation rules horizontally and preemptively reject conditional transactions before they reach the sequencer. Various metrics are emitted to guide necessary adjustments. #### Runtime shutoff This service can be configured with a flag or environment variable to reject conditional transactions without needing to interrupt the execution engine. This feature is useful for diagnosing issues. `--sendRawTxConditional.enabled (default: true) ($OP_TXPROXY_SENDRAWTXCONDITIONAL_ENABLED)` When disabled, requests will fail with the `-32003` (transaction rejected) json rpc error code with a message stating that the method is disabled. #### Rate limits Even though the op-geth implementation of this endpoint includes rate limits, it is instead applied here to terminate these requests early. `--sendRawTxConditional.ratelimit (default: 5000) ($OP_TXPROXY_SENDRAWTXCONDITIONAL_RATELIMIT)` #### Stateless validation * Conditional cost is below the max * Conditional values are valid (i.e min \< max) * Transaction targets are only 4337 Entrypoint contracts The motivating factor for this endpoint is to enable permissionless 4337 mempools, hence the restricted usage of this method to just [Entrypoint](https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/core/EntryPoint.sol) transactions. Please open up an issue if you'd like this restriction to be optional via configuration to broaden usage of this endpoint. When the request passes validation, it is passed through to the configured backend URL `--sendRawTxConditional.backend ($OP_TXPROXY_SENDRAWTXCONDITIONAL_BACKENDS)` Per the [specification](/op-stack/features/send-raw-transaction-conditional), conditional transactions are not gossiped between peers. Thus, if you use replicas in an active/passive sequencer setup, this request must be broadcasted to all replicas. [proxyd](./proxyd) as an egress router for this method supports this broadcasting functionality. ## How it works To start using `op-txproxy`, follow these steps: 1. Run the following command to build the binary ```bash theme={null} make build ``` 2. This will build and output the binary under `/bin/op-txproxy`. The image for this binary is also available as a [docker artifact](https://us-docker.pkg.dev/oplabs-tools-artifacts/images/op-txproxy). The binary accepts configuration through CLI flags, which also settable via environment variables. Either set the flags explicitly when starting the binary or set the environment variables of the host starting the proxy. See [methods](#methods) on the configuration options available for each method. start the service with the following command ```bash theme={null} op-txproxy // ... with flags if env variables are not set ``` # Run proxyd Source: https://docs.optimism.io/chain-operators/tools/proxyd Learn how to build, configure, and run proxyd, the OP Stack RPC request router and proxy. `proxyd` is an important RPC request router and proxy used within the OP Stack infrastructure. It enables operators to efficiently route and manage RPC requests across multiple backend services, ensuring performance, fault tolerance, and security. ## Key features * RPC method whitelisting * Backend request routing * Automatic retries for failed backend requests * Consensus tracking (latest, safe, and finalized blocks) * Request/response rewriting to enforce consensus * Load balancing across backend services * Caching of immutable responses * Metrics for request latency, error rates, and backend health ## How it works To start using `proxyd`, follow these steps: * Run the following command to build the `proxyd` binary: ```bash theme={null} make proxyd ``` * This will build the `proxyd` binary. No additional dependencies are required. * Create a configuration file to define your proxy backends and routing rules. * Refer to [example.config.toml](https://github.com/ethereum-optimism/infra/blob/main/proxyd/example.config.toml) for a full list of options with commentary. Once the configuration file is ready, start the `proxyd` service using the following command: ```bash theme={null} proxyd ``` ## Consensus awareness Version 4.0.0 and later include consensus awareness to minimize chain reorganizations. Set `consensus_aware` to `true` in the configuration to enable: * Polling backends for consensus data (latest block, safe block, peer count, etc.). * Resolving consensus groups based on healthiest backends * Enforcing consensus state across client requests ## Caching and metrics ### Cacheable methods Certain immutable methods, such as `eth_chainId` and `eth_getBlockByHash`, can be cached using Redis to optimize performance. ### Metrics Extensive metrics are available to monitor request latency, error rates, backend health, and more. These can be configured via `metrics.port` and `metrics.host` in the configuration file. ## Next steps * Read about the [OP Stack chain architecture](/chain-operators/guides/management/network-architecture). * Find out how you can support [snap sync](/chain-operators/guides/features/snap-sync). on your chain. * Find out how you can utilize [blob space](/chain-operators/guides/features/blobs) to reduce the transaction fee cost on your chain. # Generating absolute prestate and preimage files Source: https://docs.optimism.io/chain-operators/tutorials/absolute-prestate Generate, verify, and configure the kona-client absolute prestate for permissionless fault proofs. # Overview The absolute prestate is the on-chain commitment to a specific build of `kona-client`. The matching preimage (a gzipped binary) is what `op-challenger` runs at dispute time. This guide is the minimal reproducer. As of [Upgrade 19](/notices/archive/upgrade-19), `CANNON_KONA` (game type `8`) is the respected game type for permissionless fault proofs. If your chain is not yet in the public Superchain Registry, follow [Generating a custom kona-client absolute prestate](/chain-operators/tutorials/kona-custom-prestate) instead. ## Prerequisites * [Docker](https://docs.docker.com/engine/install/) running * [`just`](https://github.com/casey/just) installed ## Generate and verify the prestate ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git cd optimism git checkout kona-node/v ``` ```bash theme={null} just reproducible-prestate-kona ``` The build runs in Docker and writes artifacts to `rust/kona/prestate-artifacts-cannon/`. ```bash theme={null} jq -r .pre rust/kona/prestate-artifacts-cannon/prestate-proof.json ``` Match the printed hash against the `cannon64-kona` entry for your release tag in [`standard-prestates.toml`](https://github.com/ethereum-optimism/superchain-registry/blob/main/validation/standard/standard-prestates.toml). A match confirms your build environment is honest. ## Configure op-challenger Upload the hash-named file `rust/kona/prestate-artifacts-cannon/0x.bin.gz` (produced by the build) to a location reachable by your `op-challenger` instances, then add the kona-specific env vars to your existing challenger config: ```bash theme={null} OP_CHALLENGER_TRACE_TYPE=cannon-kona,permissioned OP_CHALLENGER_CANNON_KONA_PRESTATES_URL= ``` The challenger appends `/0x.bin.gz` to `*_PRESTATES_URL` to resolve the right binary per dispute. Your existing `OP_CHALLENGER_ROLLUP_CONFIG`, `OP_CHALLENGER_L2_GENESIS`, and `OP_CHALLENGER_GAME_FACTORY_ADDRESS` continue to apply unchanged. ## Next Steps * [Generating a custom kona-client absolute prestate](/chain-operators/tutorials/kona-custom-prestate) — for chains not yet in the Superchain Registry. * [Migrating to permissionless fault proofs](/chain-operators/tutorials/migrating-permissionless). * [Fault proofs explainer](/op-stack/fault-proofs/explainer). # Adding attributes to the derivation function Source: https://docs.optimism.io/chain-operators/tutorials/adding-derivation-attributes Learn how to modify the derivation function for an OP Stack chain to track the amount of ETH being burned on L1. OP Stack Hacks are explicitly things that you can do with the OP Stack that are *not* currently intended for production use. OP Stack Hacks are not for the faint of heart. You will not be able to receive significant developer support for OP Stack Hacks. Be prepared to get your hands dirty and to work without support. ## Overview In this tutorial, you'll modify the Bedrock Rollup. Although there are many ways to modify the OP Stack, you're going to spend this tutorial modifying the Derivation function. Specifically, you're going to update the Derivation function to track the amount of ETH being burned on L1! Who's gonna tell [ultrasound.money](http://ultrasound.money) that they should replace their backend with an OP Stack chain? ## Getting the idea Let's quickly recap what you're about to do. The `op-node` is responsible for generating the Engine API payloads that trigger `op-geth` to produce blocks and transactions. The `op-node` already generates a "system transaction" for every L1 block that relays information about the current L1 state to the L2 chain. You're going to modify the `op-node` to add a new system transaction that reports the total burn amount (the base fee multiplied by the gas used) in each block. Although it might sound like a lot, the whole process only involves deploying a single smart contract, adding one new file to `op-node`, and modifying one existing file inside `op-node`. It'll be painless. Let's go! ## Deploy the burn contract You're going to use a smart contract on your Rollup to store the reports that the `op-node` makes about the L1 burn. Here's the code for your smart contract: ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title L1Burn * @notice L1Burn keeps track of the total amount of ETH burned on L1. */ contract L1Burn { /** * @notice Total amount of ETH burned on L1. */ uint256 public total; /** * @notice Mapping of block numbers to total burn. */ mapping (uint64 => uint256) public reports; /** * @notice Allows the system address to submit a report. * * @param _blocknum L1 block number the report corresponds to. * @param _burn Amount of ETH burned in the block. */ function report(uint64 _blocknum, uint64 _burn) external { require( msg.sender == 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001, "L1Burn: reports can only be made from system address" ); total += _burn; reports[_blocknum] = total; } /** * @notice Tallies up the total burn since a given block number. * * @param _blocknum L1 block number to tally from. * * @return Total amount of ETH burned since the given block number; */ function tally(uint64 _blocknum) external view returns (uint256) { return total - reports[_blocknum]; } } ``` Deploy this smart contract to your L2 (using any tool you find convenient). Make a note of the address that the contract is deployed to because you'll need it in a minute. Simple! ## Add the burn transaction Now you need to add logic to the `op-node` to automatically submit a burn report whenever an L1 block is produced. Since this transaction is very similar to the system transaction that reports other L1 block info (found in [l1\_block\_info.go](https://github.com/ethereum-optimism/optimism/blob/develop/op-node/rollup/derive/l1_block_info.go)), you'll use that transaction as a jumping-off point. ```bash theme={null} cd ~/optimism/op-node ``` ```bash theme={null} touch rollup/derive/l1_burn_info.go ``` ```go theme={null} package derive import ( "bytes" "encoding/binary" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum-optimism/optimism/op-node/eth" ) const ( L1BurnFuncSignature = "report(uint64,uint64)" L1BurnArguments = 2 L1BurnLen = 4 + 32*L1BurnArguments ) var ( L1BurnFuncBytes4 = crypto.Keccak256([]byte(L1BurnFuncSignature))[:4] L1BurnAddress = common.HexToAddress("YOUR_BURN_CONTRACT_HERE") ) type L1BurnInfo struct { Number uint64 Burn uint64 } func (info *L1BurnInfo) MarshalBinary() ([]byte, error) { data := make([]byte, L1BurnLen) offset := 0 copy(data[offset:4], L1BurnFuncBytes4) offset += 4 binary.BigEndian.PutUint64(data[offset+24:offset+32], info.Number) offset += 32 binary.BigEndian.PutUint64(data[offset+24:offset+32], info.Burn) return data, nil } func (info *L1BurnInfo) UnmarshalBinary(data []byte) error { if len(data) != L1InfoLen { return fmt.Errorf("data is unexpected length: %d", len(data)) } var padding [24]byte offset := 4 info.Number = binary.BigEndian.Uint64(data[offset+24 : offset+32]) if !bytes.Equal(data[offset:offset+24], padding[:]) { return fmt.Errorf("l1 burn tx number exceeds uint64 bounds: %x", data[offset:offset+32]) } offset += 32 info.Burn = binary.BigEndian.Uint64(data[offset+24 : offset+32]) if !bytes.Equal(data[offset:offset+24], padding[:]) { return fmt.Errorf("l1 burn tx burn exceeds uint64 bounds: %x", data[offset:offset+32]) } return nil } func L1BurnDepositTxData(data []byte) (L1BurnInfo, error) { var info L1BurnInfo err := info.UnmarshalBinary(data) return info, err } func L1BurnDeposit(seqNumber uint64, block eth.BlockInfo, sysCfg eth.SystemConfig) (*types.DepositTx, error) { infoDat := L1BurnInfo{ Number: block.NumberU64(), Burn: block.BaseFee().Uint64() * block.GasUsed(), } data, err := infoDat.MarshalBinary() if err != nil { return nil, err } source := L1InfoDepositSource{ L1BlockHash: block.Hash(), SeqNumber: seqNumber, } return &types.DepositTx{ SourceHash: source.SourceHash(), From: L1InfoDepositerAddress, To: &L1BurnAddress, Mint: nil, Value: big.NewInt(0), Gas: 150_000_000, IsSystemTransaction: true, Data: data, }, nil } func L1BurnDepositBytes(seqNumber uint64, l1Info eth.BlockInfo, sysCfg eth.SystemConfig) ([]byte, error) { dep, err := L1BurnDeposit(seqNumber, l1Info, sysCfg) if err != nil { return nil, fmt.Errorf("failed to create L1 burn tx: %w", err) } l1Tx := types.NewTx(dep) opaqueL1Tx, err := l1Tx.MarshalBinary() if err != nil { return nil, fmt.Errorf("failed to encode L1 burn tx: %w", err) } return opaqueL1Tx, nil } ``` Feel free to take a look at this file if you're interested. It's relatively simple, mainly just defining a new transaction type and describing how the transaction should be encoded. ## Insert the burn transactions Finally, you'll need to update `~/optimism/op-node/rollup/derive/attributes.go` to insert the new burn transaction into every block. You'll need to make the following changes: ```go theme={null} l1InfoTx, err := L1InfoDepositBytes(seqNumber, l1Info, sysConfig) if err != nil { return nil, NewCriticalError(fmt.Errorf("failed to create l1InfoTx: %w", err)) } ``` ```go theme={null} l1BurnTx, err := L1BurnDepositBytes(seqNumber, l1Info, sysConfig) if err != nil { return nil, NewCriticalError(fmt.Errorf("failed to create l1InfoTx: %w", err)) } ``` ```go theme={null} txs := make([]hexutil.Bytes, 0, 1+len(depositTxs)) txs = append(txs, l1InfoTx) ``` to ```go theme={null} txs := make([]hexutil.Bytes, 0, 2+len(depositTxs)) txs = append(txs, l1InfoTx) txs = append(txs, l1BurnTx) ``` All you're doing here is creating a new burn transaction after every `l1InfoTx` and inserting it into every block. ## Rebuild your op-node Before you can see this change take effect, you'll need to rebuild your `op-node`: ```bash theme={null} cd ~/optimism/op-node make op-node ``` Now start your `op-node` if it isn't running or restart your `op-node` if it's already running. You should see the change immediately — new blocks will contain two system transactions instead of just one! ## Checking the result Query the `total` function of your contract, you should also start to see the total slowly increasing. Play around with the `tally` function to grab the amount of gas burned since a given L2 block. You could use this to implement a version of [ultrasound.money](http://ultrasound.money) that keeps track of things with an OP Stack as a backend. One way to get the total is to run these commands: ```bash theme={null} export ETH_RPC_URL=http://localhost:8545 cast call "total()" | cast --from-wei ``` ## Conclusion With just a few tiny changes to the `op-node`, you were just able to implement a change to the OP Stack that allows you to keep track of the L1 ETH burn on L2. With a live Cannon Fault Proof System, you should not only be able to track the L1 burn on L2, you should be able to *prove* the burn to contracts back on L1. That's crazy! The OP Stack is an extremely powerful platform that allows you to perform a large amount of computation trustlessly. It's a superpower for smart contracts. Tracking the L1 burn is just one of the many, many wild things you can do with the OP Stack. If you're looking for inspiration or you want to see what others are building on the OP Stack, check out the OP Stack Hacks page. Maybe you'll find a project you want to work on, or maybe you'll get the inspiration you need to build the next killer smart contract. # Adding a precompile Source: https://docs.optimism.io/chain-operators/tutorials/adding-precompiles Learn how to run an EVM with a new precompile for OP Stack chain operations to speed up calculations that are not currently supported. OP Stack Hacks are explicitly things that you can do with the OP Stack that are *not* currently intended for production use. OP Stack Hacks are not for the faint of heart. You will not be able to receive significant developer support for OP Stack Hacks. Be prepared to get your hands dirty and to work without support. One possible use of OP Stack is to run an EVM with a new precompile for operations to speed up calculations that are not currently supported. In this tutorial, you'll make a simple precompile that returns a constant value if it's called with four or less bytes, or an error if it is called with more than that. To create a new precompile, the file to modify is [`op-geth/core/vm/contracts.go`](https://github.com/ethereum-optimism/op-geth/blob/optimism-history/core/vm/contracts.go). * add a structure named after your new precompile, and * use an address that is unlikely to ever clash with a standard precompile and avoids the [EIP-7587](https://eips.ethereum.org/EIPS/eip-7587) reserved range (0x1337, for example): ```go theme={null} common.BytesToAddress([]byte{0x13,0x37}): &retConstant{}, ``` ```go theme={null} type retConstant struct{} func (c *retConstant) RequiredGas(input []byte) uint64 { return uint64(1024) } var ( errConstInvalidInputLength = errors.New("invalid input length") ) func (c *retConstant) Run(input []byte) ([]byte, error) { // Only allow input up to four bytes (function signature) if len(input) > 4 { return nil, errConstInvalidInputLength } output := make([]byte, 6) for i := 0; i < 6; i++ { output[i] = byte(64+i) } return output, nil } ``` ```bash theme={null} cd ~/op-geth make geth ``` ```bash theme={null} cast call 0x0000000000000000000000000000000000001337 "whatever()" cast call 0x0000000000000000000000000000000000001337 "whatever(string)" "fail" ``` ## How does it work? This is the precompile interface definition: ```go theme={null} type PrecompiledContract interface { RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use Run(input []byte) ([]byte, error) // Run runs the precompiled contract } ``` It means that for every precompile you need two functions: * `RequiredGas` which returns the gas cost for the call. This function takes an array of bytes as input, and returns a single value, the gas cost. * `Run` which runs the actual precompile. This function also takes an array of bytes, but it returns two values: the call's output (a byte array) and an error. For every fork that changes the precompiles you have a [`map`](https://www.w3schools.com/go/go_maps.php) from addresses to the `PrecompiledContract` definitions: ```go theme={null} // PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum // contracts used in the Berlin release. var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{1}): &ecrecover{}, . . . common.BytesToAddress([]byte{9}): &blake2F{}, common.BytesToAddress([]byte{0x13,0x37}): &retConstant{}, } ``` The key of the map is an address. You create those from bytes using `common.BytesToAddress([]byte{})`. In this case you have two bytes, `0x13` and `0x37`. Together you get the address `0x0…1337`. The syntax for a precompiled contract interface is `&{}`. The next step is to define the precompiled contract itself. ```go theme={null} type retConstant struct{} ``` First you create a structure for the precompile. ```go theme={null} func (c *retConstant) RequiredGas(input []byte) uint64 { return uint64(1024) } ``` Then you define a function as part of that structure. Here you just require a constant amount of gas, but of course the calculation can be a lot more sophisticated. ```go theme={null} var ( errConstInvalidInputLength = errors.New("invalid input length") ) ``` Next you define a variable for the error. ```go theme={null} func (c *retConstant) Run(input []byte) ([]byte, error) { ``` This is the function that actually executes the precompile. ```go theme={null} // Only allow input up to four bytes (function signature) if len(input) > 4 { return nil, errConstInvalidInputLength } ``` Return an error if warranted. The reason this precompile allows up to four bytes of input is that any standard call (for example, using `cast`) is going to have at least four bytes for the function signature. `return a, b` is the way we return two values from a function in Go. The normal output is `nil`, nothing, because we return an error. ```go theme={null} output := make([]byte, 6) for i := 0; i < 6; i++ { output[i] = byte(64+i) } return output, nil } ``` Finally, you create the output buffer, fill it, and then return it. ## Conclusion An OP Stack chain with additional precompiles can be useful, for example, to further reduce the computational effort required for cryptographic operations by moving them from interpreted EVM code to compiled Go code. # Generating an op-program absolute prestate (archived) Source: https://docs.optimism.io/chain-operators/tutorials/archive/op-program-prestate Archived: legacy op-program prestate generation flow for chains resolving in-flight CANNON game type 1 disputes. **Archived.** As of [Upgrade 19](/notices/archive/upgrade-19), `CANNON_KONA` (game type `8`) is the respected game type for permissionless fault proofs and `op-program` (game type `0`, `CANNON`) is no longer supported for new fault proofs. This page is retained only for chains that still need to resolve in-flight `CANNON` games created before Upgrade 19. For all current work, see [Generating absolute prestate and preimage files](/chain-operators/tutorials/absolute-prestate) (kona-client) and, if your chain is not yet in the Superchain Registry, [Generating a custom kona-client absolute prestate](/chain-operators/tutorials/kona-custom-prestate). ## Overview Permissionless fault proofs are a critical component of the OP Stack's security model. They allow anyone to challenge invalid state proposals, ensuring the correctness of L2 to L1 withdrawals without relying on trusted third parties. To enable this functionality, chain operators must generate and maintain the necessary absolute prestate and preimage files. The absolute prestate is a commitment to the initial state of the fault proof program, and the preimage is the serialized binary representation of this program state. These files are essential for the op-challenger tool to participate in dispute games when challenging invalid claims. ## Prerequisites Before starting, ensure you have: * [Docker](https://docs.docker.com/engine/install/) running ## Official prestate hashes for superchain-registry chains The superchain-registry maintains official absolute prestate hashes for chains that are part of the registry. These prestates include the configurations of chains that were in the superchain-registry at the time the prestate was created. Important: A prestate listed in the superchain-registry may not be suitable for your chain if: * Your chain was added to the registry after the prestate was created * The configuration for your chain has been updated since the prestate was created Before using a prestate from the registry, verify that it contains the latest configuration for your chain. When in doubt, generating your own prestate with your specific chain configuration is the safest approach. You can find the latest prestate tags in the [Superchain registry](https://github.com/ethereum-optimism/superchain-registry/blob/main/validation/standard/standard-prestates.toml). ## Generating the absolute prestate First, clone the Optimism monorepo and check out the appropriate [release tag](https://github.com/ethereum-optimism/optimism/tags) for op-program: ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git cd optimism # Check out the op-program version that matches the in-flight CANNON game you # need to resolve. Use the version the game's original prestate was generated with. git checkout op-program/v1.6.1 ``` For chains that are not included in the superchain-registry, you'll need to provide the chain rollup configuration file and the L2 genesis file. Add the `rollup.json` and `l2-genesis.json` to the monorepo at `optimism/op-program/chainconfig/configs/-rollup.json` and `optimism/op-program/chainconfig/configs/-genesis-l2.json` respectively. Run the following command from the root of the monorepo: ```bash theme={null} make reproducible-prestate ``` You should see the following logs at the end of the command’s output: ```log theme={null} -------------------- Production Prestates -------------------- Cannon64 Absolute prestate hash: 0x03eb07101fbdeaf3f04d9fb76526362c1eea2824e4c6e970bdb19675b72e4fc8 -------------------- Experimental Prestates -------------------- CannonInterop Absolute prestate hash: 0x03fc3b4d091527d53f1ff369ea8ed65e5e17cc7fc98ebf75380238151cdc949c Cannon64Next Absolute prestate hash: 0x03eb07101fbdeaf3f04d9fb76526362c1eea2824e4c6e970bdb19675b72e4fc8 ``` The output will display production and experimental prestate hashes: * **Production prestates**: Contains the `Cannon64` prestate, which is the current production absolute prestate hash for the 64-bit version of Cannon. This is the hash you should use for permissionless fault proofs. * **Experimental prestates**: These contain prestates for versions that are in development and not yet ready for production use. After generating the prestate, the preimage file will be located in `op-program/bin/prestate-mt64.bin.gz`. The exact name might vary based on the version. Rename this file to include the prestate hash: ```bash theme={null} cd op-program/bin mv prestate-mt64.bin.gz .bin.gz ``` Replace `` with the actual `Cannon64` absolute prestate hash value from the output. This file needs to be uploaded to a location that's accessible by your op-challenger instances. ## Deploying and configuring with the absolute prestate After generating the absolute prestate and preimage files, you'll need to: Upload the preimage file to a location accessible by your op-challenger instances Configure the op-challenger to use the generated prestate. There are two ways to provide prestates: If your prestate files are hosted on a web server, you can simply provide the URL to the directory containing those files: ```bash theme={null} docker run -d --name op-challenger \ -e OP_CHALLENGER_TRACE_TYPE=permissioned,cannon \ -e OP_CHALLENGER_PRESTATES_URL= \ -e OP_CHALLENGER_L1_ETH_RPC= \ -e OP_CHALLENGER_GAME_FACTORY_ADDRESS= \ -e OP_CHALLENGER_PRIVATE_KEY= \ -e OP_CHALLENGER_NETWORK= \ -e OP_CHALLENGER_CANNON_ROLLUP_CONFIG= \ -e OP_CHALLENGER_CANNON_L2_GENESIS= \ us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:latest ``` When using an HTTP URL, no volume mount is required. The challenger will download the prestate files as needed. If you have prestate files stored locally, you'll need to mount them as a volume and use the `file://` protocol: ```bash theme={null} docker run -d --name op-challenger \ -e OP_CHALLENGER_TRACE_TYPE=permissioned,cannon \ -e OP_CHALLENGER_PRESTATES_URL=file:///prestates \ -e OP_CHALLENGER_L1_ETH_RPC= \ -e OP_CHALLENGER_GAME_FACTORY_ADDRESS= \ -e OP_CHALLENGER_PRIVATE_KEY= \ -e OP_CHALLENGER_NETWORK= \ -e OP_CHALLENGER_CANNON_ROLLUP_CONFIG= \ -e OP_CHALLENGER_CANNON_L2_GENESIS= \ -v /path/to/local/prestates:/prestates \ us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:latest ``` When using local files, ensure your prestate files are in the mounted directory and properly named with their hash (e.g., `0x03eb07101fbdeaf3f04d9fb76526362c1eea2824e4c6e970bdb19675b72e4fc8.bin.gz`). * Ensure you're using the latest op-challenger version, see the [release page](https://github.com/ethereum-optimism/optimism/releases). * If your chain uses interoperability features, you'll need to add a `depsets.json` file to the `op-program/chainconfig/configs` directory. * This file contains dependency set configurations. Use the same dependency set definition your interop-enabled chain is already configured with. ## Next steps * Check out the [migrating to permissionless fault proofs guide](/chain-operators/tutorials/migrating-permissionless). * Read the [Fault proofs explainer](/op-stack/fault-proofs/explainer). # L2 Rollup Code Examples Source: https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/code-setup Complete working code examples for the Create L2 Rollup tutorial This page contains complete working code examples for the Create L2 Rollup tutorial. You can find all the code and configuration files in the [create-l2-rollup-example directory](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/). For the complete working implementation, visit the [Create L2 Rollup code on GitHub](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/). ## Quick Start ```bash theme={null} # Copy and configure environment cp .example.env .env # Edit .env with your values # Run the automated setup make init # Download tools make setup # Deploy and configure make up # Start services ``` ## Files * `.example.env` - Environment configuration template * `docker-compose.yml` - Service orchestration * `Makefile` - Automation commands * `scripts/` - Setup and utility scripts * `README.md` - Detailed documentation ## About This Code This implementation provides: * Automated deployment of OP Stack L2 contracts * Complete Docker-based service orchestration * Working examples of all OP Stack components * Production-ready configuration patterns For detailed setup instructions, see the [Create L2 Rollup tutorial](/chain-operators/tutorials/create-l2-rollup). # Creating your own L2 rollup testnet Source: https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/index Learn how to deploy and orchestrate all OP Stack components for a complete testnet deployment. **Learn the OP Stack — stop 5 of 13.** You've covered the foundations: what the stack is, how it differs from Ethereum, and which components make it up. In this first project you deploy a rollup testnet with op-deployer and start each component yourself. Work through every part of the series, then continue to [Transaction flow](/op-stack/transactions/transaction-flow). Welcome to the complete guide for deploying your own OP Stack L2 rollup testnet. This multi-part tutorial will walk you through each component step-by-step, from initial setup to a fully functioning rollup. This tutorial requires **intermediate-level experience working with EVM chains**. You should be comfortable with concepts like smart contracts, private keys, RPC endpoints, gas fees, and command-line operations. Basic familiarity with Docker is also recommended. ## What you'll build By the end of this tutorial, you'll have a complete OP Stack testnet with: * **L1 Smart Contracts** deployed on Sepolia testnet * **Execution Client** (op-reth) processing transactions * **Consensus Client** (op-node) managing rollup consensus * **Batcher** (op-batcher) publishing transaction data to L1 * **Proposer** (op-proposer) submitting state root proposals * **Challenger** (op-challenger) monitoring for disputes ## Before you start Set up the following before you pick a setup path below. Both the automated and manual paths need these dependencies and resources. ### Software dependencies | Dependency | Version | Version check command | | ------------------------------------------------------------- | ------------------------------------ | --------------------- | | [git](https://git-scm.com/) | `^2` | `git --version` | | [go](https://go.dev/) | `^1.26` | `go version` | | [rust](https://rustup.rs/) (source builds only) | pinned by `rust/rust-toolchain.toml` | `rustc --version` | | [just](https://github.com/casey/just) (source builds only) | `^1` | `just --version` | | [zip](https://infozip.sourceforge.net/) (source builds only) | `^3` | `zip --version` | | [node](https://nodejs.org/en/) | `^20` | `node --version` | | [pnpm](https://pnpm.io/installation) | `^8` | `pnpm --version` | | [foundry](https://github.com/foundry-rs/foundry#installation) | `^0.2.0` | `forge --version` | | [make](https://linux.die.net/man/1/make) | `^3` | `make --version` | | [jq](https://github.com/jqlang/jq) | `^1.6` | `jq --version` | | [direnv](https://direnv.net) | `^2` | `direnv --version` | | [Docker](https://docs.docker.com/get-docker/) | `^24` | `docker --version` | ### Notes on specific dependencies Expand each dependency below for details We recommend using the latest LTS version of Node.js (currently v20).\ [`nvm`](https://github.com/nvm-sh/nvm) is a useful tool that can help you manage multiple versions of Node.js on your machine.\ You may experience unexpected errors on older versions of Node.js. We will use cast to generate wallet addresses in this guide. Parts of this tutorial use [`direnv`](https://direnv.net) as a way of loading environment variables from `.envrc` files into your shell.\ This means you won't have to manually export environment variables every time you want to use them.\ `direnv` only ever has access to files that you explicitly allow it to see. After [installing `direnv`](https://direnv.net/docs/installation.html), you will need to **make sure that [`direnv` is hooked into your shell](https://direnv.net/docs/hook.html)**.\ Make sure you've followed [the guide on the `direnv` website](https://direnv.net/docs/hook.html), then **close your terminal and reopen it** so that the changes take effect (or `source` your config file if you know how to do that). Make sure that you have correctly hooked `direnv` into your shell by modifying your shell configuration file (like `~/.bashrc` or `~/.zshrc`).\ If you haven't edited a config file then you probably haven't configured `direnv` properly (and things might not work later). Docker is used extensively in this tutorial for running various OP Stack components.\ Make sure you have both Docker and Docker Compose installed and running on your system.\ On Linux, you may need to [configure Docker to run without sudo](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user). If you're using Docker Desktop, ensure it's running before starting the tutorial.\ You can verify your installation with: ```bash theme={null} docker run hello-world ``` ### Get access to a sepolia node Since you're deploying your OP Stack chain to Sepolia, you'll need to have access to a Sepolia node. You can either use a node provider like [Alchemy](https://www.alchemy.com/) (easier) or run your own Sepolia node (harder). ### Required resources * **Sepolia ETH** - You'll need about 2-3 ETH: * Start with [Superchain Faucet](https://console.optimism.io/faucet) (gives 0.05 ETH) * Get more from: * [Alchemy Faucet](https://sepoliafaucet.com/) * [Infura Faucet](https://www.infura.io/faucet/sepolia) * [Paradigm Faucet](https://faucet.paradigm.xyz/) * **L1 RPC URL** - An RPC endpoint to connect to the Sepolia network. You can get this from node providers like [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/). This is required so `op-deployer` and other services can read from and send transactions to L1. **Testnet Only**: This guide is for **testnet deployment only**. ## Choose your path With your dependencies and resources in place, pick the path that fits how you want to work: * **[Automated setup](#automated-setup)** — the fastest way to a running rollup. Uses the complete working implementation in this repository and handles all configuration and deployment for you. * **[Manual setup](#manual-setup)** — walks through each component step-by-step. Choose this if you want to understand each component in detail or need custom configurations. ## Automated setup If you want to get started quickly, you can use the complete working implementation provided in this repository. This automated setup handles all the configuration and deployment steps for you. **Complete working example** A complete, working implementation is available in the [`create-l2-rollup-example/`](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) directory. This includes all necessary scripts, Docker Compose configuration, and example environment files. ### Automated setup steps 1. **Clone and navigate to the code directory:** ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git cd optimism/docs/public-docs/create-l2-rollup-example ``` 2. **Configure your environment:** ```bash theme={null} cp .example.env .env # Edit .env with your L1_RPC_URL, PRIVATE_KEY, and other settings ``` 3. **Run the automated setup:** ```bash theme={null} make init # Download op-deployer make setup # Deploy contracts and generate configs make up # Start all services make test-l1 # Verify L1 connectivity make test-l2 # Verify L2 functionality ``` 4. **Monitor your rollup:** ```bash theme={null} make logs # View all service logs make status # Check service health ``` The automated setup uses the standard OP Stack environment variable conventions (prefixed with `OP_*`) and handles all the complex configuration automatically. ## Manual setup If you prefer to understand each component in detail or need custom configurations, follow the step-by-step guide below. Each step builds on the previous one, so complete them in order for the best experience. ### Directory structure To keep your rollup deployment organized, we'll create a dedicated directory structure. All components will be set up within this structure: ```bash theme={null} rollup/ ├── deployer/ # op-deployer files and contracts ├── sequencer/ # op-reth and op-node ├── batcher/ # op-batcher configuration ├── proposer/ # op-proposer setup └── challenger/ # op-challenger files ``` Each component's documentation will show you how the directory structure evolves as you add files and configurations. Throughout this tutorial, all file paths will be relative to this `rollup` directory structure. Make sure to adjust any commands if you use different directory names. ### Manual setup steps The manual path is organized into sequential steps that build upon each other: Install op-deployer, deploy L1 contracts, and prepare your environment [Go to op-deployer setup →](/chain-operators/tutorials/create-l2-rollup/op-deployer-setup) Set up and run op-reth and op-node (the execution and consensus layers) [Go to sequencer setup →](/chain-operators/tutorials/create-l2-rollup/op-reth-setup) Configure and start op-batcher for L1 data publishing [Go to batcher setup →](/chain-operators/tutorials/create-l2-rollup/op-batcher-setup) Set up op-proposer for state root submissions [Go to proposer setup →](/chain-operators/tutorials/create-l2-rollup/op-proposer-setup) Configure op-challenger for dispute resolution monitoring [Go to challenger setup →](/chain-operators/tutorials/create-l2-rollup/op-challenger-setup) Already have your dependencies? Get started and spin up op-deployer *** ## Need help? * **Questions or issues**: Ask questions or report bugs and docs problems on the [Optimism monorepo issue tracker](https://github.com/ethereum-optimism/optimism/issues) * **Code examples**: Browse the [complete working example](/chain-operators/tutorials/create-l2-rollup/code-setup) that accompanies this tutorial # Spin up batcher Source: https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/op-batcher-setup Learn how to set up and configure an OP Stack batcher to submit L2 transaction batches to L1. After you have spun up your sequencer, you need to configure a batcher to submit L2 transaction batches to L1. **Step 3 of 5**: This tutorial is designed to be followed step-by-step. Each step builds on the [previous one](/chain-operators/tutorials/create-l2-rollup/op-reth-setup). **Automated Setup Available** For a complete working setup with all components, check out the [automated approach](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) in the code directory. ## Understanding the batcher's role The batcher (`op-batcher`) serves as a crucial component that bridges your L2 chain data to L1. Its primary responsibilities include: * **Batch submission**: Collecting L2 transactions and submitting them as batches to L1 * **Data availability**: Ensuring L2 transaction data is available on L1 for verification * **Cost optimization**: Compressing and efficiently packing transaction data to minimize L1 costs * **Channel management**: Managing data channels for optimal batch submission timing The batcher reads transaction data from your sequencer and submits compressed batches to the `BatchInbox` contract on L1. ## Prerequisites Before setting up your batcher, ensure you have: **Running infrastructure:** * An operational sequencer node * Access to a L1 RPC endpoint **Network information:** * Your L2 chain ID and network configuration * L1 network details (chain ID, RPC endpoints) * `BatchInbox` contract address from your deployment For setting up the batcher, we recommend using Docker as it provides a consistent and isolated environment. Building from source is also available for more advanced users. If you prefer containerized deployment, you can use the official Docker images and do the following: ```bash theme={null} # Create your batcher directory inside rollup cd ../ # Go back to rollup directory if you're in sequencer mkdir batcher cd batcher # Copy configuration files from deployer cp ../deployer/.deployer/state.json . # Extract the BatchInbox address BATCH_INBOX_ADDRESS=$(cat state.json | jq -r '.opChainDeployments[0].systemConfigProxyAddress') echo "BatchInbox Address: $BATCH_INBOX_ADDRESS" ``` **OP Stack Standard Variables** The batcher uses OP Stack standard environment variables following the OP Stack conventions. These are prefixed with `OP_BATCHER_` for batcher-specific settings. ```bash theme={null} # Create .env file with your actual values cat > .env << 'EOF' # L1 Configuration - Replace with your actual RPC URLs OP_BATCHER_L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY # Private key - Replace with your actual private key OP_BATCHER_PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY # L2 Configuration - Should match your sequencer setup OP_BATCHER_L2_ETH_RPC=http://op-reth:8545 OP_BATCHER_ROLLUP_RPC=http://op-node:8547 # Contract addresses - Extract from your op-deployer output OP_BATCHER_BATCH_INBOX_ADDR=YOUR_ACTUAL_BATCH_INBOX_ADDRESS # Batcher configuration OP_BATCHER_POLL_INTERVAL=1s OP_BATCHER_SUB_SAFETY_MARGIN=6 OP_BATCHER_NUM_CONFIRMATIONS=1 OP_BATCHER_SAFE_ABORT_NONCE_TOO_LOW_COUNT=3 OP_BATCHER_MAX_CHANNEL_DURATION=1 OP_BATCHER_DATA_AVAILABILITY_TYPE=calldata # RPC configuration OP_BATCHER_RPC_PORT=8548 EOF ``` **Important**: Replace ALL placeholder values (`YOUR_ACTUAL_*`) with your real configuration values. This configuration assumes your sequencer is running in a Docker container named `sequencer-node` on the same `op-stack` network. Make sure your sequencer is running before starting the batcher. ```yaml theme={null} services: op-batcher: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-batcher:v1.16.11 volumes: - .:/workspace working_dir: /workspace ports: - "8548:8548" env_file: - .env networks: - sequencer-node_default command: > op-batcher --rpc.addr=0.0.0.0 --rpc.enable-admin --resubmission-timeout=30s --log.level=info --log.format=json restart: unless-stopped networks: sequencer-node_default: external: false ``` ```bash theme={null} # Make sure your sequencer network exists # Start the batcher docker-compose up -d # View logs docker-compose logs -f op-batcher ``` ```bash theme={null} # Check container status docker-compose ps ``` ```bash theme={null} rollup/ ├── deployer/ # From previous step │ └── .deployer/ # Contains genesis.json and rollup.json ├── sequencer/ # From previous step └── batcher/ # You are here ├── state.json # Copied from deployer ├── .env # Environment variables └── docker-compose.yml # Docker configuration ``` Your batcher is now operational and will continuously submit L2 transaction batches to L1! To ensure you're using the latest compatible versions of OP Stack components, always check the official [releases page](https://github.com/ethereum-optimism/optimism/releases). Look for the latest `op-batcher/v*` release that's compatible with your sequencer setup. This guide uses `op-batcher/v1.16.11`, the latest release at the time of writing, alongside op-node/v1.19.3 and op-reth/v2.4.0 from the sequencer setup. Always check the [release notes](https://github.com/ethereum-optimism/optimism/releases) for compatibility information. ```bash theme={null} # If you don't already have the optimism repository from the sequencer setup git clone https://github.com/ethereum-optimism/optimism.git cd optimism # Checkout the latest release tag git checkout op-batcher/v1.16.11 # Generate the embedded superchain config bundle (initializes the # superchain-registry submodule; op-batcher embeds this file at compile time) just build-superchain-go # Build op-batcher cd op-batcher just # Binary will be available at ./bin/op-batcher ``` Run this command to verify the installation: ```bash theme={null} ./bin/op-batcher --version ``` For advanced configuration options and fine-tuning your batcher, including: * Batch submission policies * Channel duration settings * Data availability types (blobs vs calldata) * Transaction throttling * Network timeouts Check out the [Batcher configuration reference](/chain-operators/reference/batcher-configuration). This will help you optimize your batcher's performance and cost-efficiency. Create your batcher working directory: ```bash theme={null} # Create batcher directory inside rollup cd ../ # Go back to rollup directory mkdir batcher cd batcher # Create scripts directory mkdir scripts ``` Your final directory structure should look like: ```bash theme={null} rollup/ ├── deployer/ # From previous step │ └── .deployer/ # Contains state.json ├── optimism/ # Contains op-batcher binary ├── sequencer/ # From previous step └── batcher/ # You are here ├── state.json # Copied from deployer ├── .env # Environment variables └── scripts/ # Startup scripts └── start-batcher.sh ``` Extract the `BatchInbox` contract address from your op-deployer output: ```bash theme={null} # Make sure you're in the rollup/batcher directory cd rollup/batcher # Copy the deployment state file from deployer cp ../deployer/.deployer/state.json . # Extract the BatchInbox address BATCH_INBOX_ADDRESS=$(cat state.json | jq -r '.opChainDeployments[0].systemConfigProxyAddress') echo "BatchInbox Address: $BATCH_INBOX_ADDRESS" ``` The batcher submits transaction batches to the `BatchInbox` contract on L1. This contract is responsible for accepting and storing L2 transaction data. Create your `.env` file with the actual values: ```bash theme={null} # Create .env file with your actual values # L1 Configuration - Replace with your actual RPC URL L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY # L2 Configuration - Should match your sequencer setup L2_RPC_URL=http://localhost:8545 ROLLUP_RPC_URL=http://localhost:8547 # Contract addresses - Extract from your op-deployer output BATCH_INBOX_ADDRESS=YOUR_ACTUAL_BATCH_INBOX_ADDRESS # Private key - Replace with your actual private key BATCHER_PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY # Batcher configuration POLL_INTERVAL=1s SUB_SAFETY_MARGIN=6 NUM_CONFIRMATIONS=1 SAFE_ABORT_NONCE_TOO_LOW_COUNT=3 RESUBMISSION_TIMEOUT=30s MAX_CHANNEL_DURATION=25 # RPC configuration BATCHER_RPC_PORT=8548 ``` **Important**: Replace ALL placeholder values (`YOUR_ACTUAL_*`) with your real configuration values! Get a private key from your wallet that will be used for submitting batches to L1. This account needs sufficient ETH to pay for L1 gas costs. The batcher account needs to be funded with ETH on L1 to pay for batch submission transactions. Monitor this account's balance regularly as it will consume ETH for each batch submission. ### Batcher configuration Create `scripts/start-batcher.sh` in the same directory: ```bash theme={null} #!/bin/bash source .env # Path to the op-batcher binary we built ../../optimism/op-batcher/bin/op-batcher \ --l2-eth-rpc=$L2_RPC_URL \ --rollup-rpc=$ROLLUP_RPC_URL \ --poll-interval=$POLL_INTERVAL \ --sub-safety-margin=$SUB_SAFETY_MARGIN \ --num-confirmations=$NUM_CONFIRMATIONS \ --safe-abort-nonce-too-low-count=$SAFE_ABORT_NONCE_TOO_LOW_COUNT \ --resubmission-timeout=$RESUBMISSION_TIMEOUT \ --rpc.addr=0.0.0.0 \ --rpc.port=$BATCHER_RPC_PORT \ --rpc.enable-admin \ --max-channel-duration=$MAX_CHANNEL_DURATION \ --l1-eth-rpc=$L1_RPC_URL \ --private-key=$BATCHER_PRIVATE_KEY \ --batch-type=1 \ --data-availability-type=blobs \ --log.level=info ``` ### Batcher parameters explained * **`--poll-interval`**: How frequently the batcher checks for new L2 blocks to batch * **`--sub-safety-margin`**: Number of confirmations to wait before considering L1 transactions safe * **`--max-channel-duration`**: Maximum time (in L1 blocks) to keep a channel open * **`--batch-type`**: Type of batch encoding (1 for span batches, 0 for singular batches) * **`--data-availability-type`**: Whether to use blobs or calldata for data availability ### Starting the batcher ### Start the batcher ```bash theme={null} # Make the script executable chmod +x scripts/start-batcher.sh # Start the batcher ./scripts/start-batcher.sh ``` For detailed cost analysis and optimization strategies, refer to the [Transaction fees documentation](/op-stack/transactions/fees). Your batcher is now operational and will continuously submit L2 transaction batches to L1! **Understanding common startup messages** When starting your batcher, you might see various log messages: * `Added L2 block to local state`: Normal operation, shows the batcher processing blocks * `SetMaxDASize RPC method unavailable`: Expected if the execution client version used doesn't support this method. * `context canceled` errors during shutdown: Normal cleanup messages * `Failed to query L1 tip`: Can occur during graceful shutdowns Most of these messages are part of normal operation. For detailed explanations of configuration options and troubleshooting, see the [Batcher configuration reference](/chain-operators/reference/batcher-configuration). ## What's Next? Excellent! Your batcher is publishing transaction data to L1. The next step is to set up the proposer to submit state root proposals. **Next**: Configure and start op-proposer to submit L2 state roots to L1 for withdrawal verification. *** ## Need Help? * **Batcher Configuration**: [Batcher configuration reference](/chain-operators/reference/batcher-configuration) * **Monitoring Guide**: [Chain Monitoring](/chain-operators/tools/chain-monitoring) * **Support**: Open an issue in the [Optimism monorepo](https://github.com/ethereum-optimism/optimism/issues) # Spin up challenger Source: https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/op-challenger-setup Learn how to configure challenger for your OP Stack chain. After you have spun up your sequencer, batcher, and proposer, the final step is to configure a challenger to monitor and respond to disputes. **Step 5 of 5**: This tutorial is designed to be followed step-by-step. Each step builds on the previous one, and this is the last part of the tutorial. **Automated Setup Available** For a complete working setup with all components including automated prestate generation, check out the [automated approach](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) in the code directory. The challenger is a critical fault proofs component that monitors dispute games and challenges invalid claims to protect your OP Stack chain. See the [op-challenger explainer](/op-stack/fault-proofs/challenger) for a general overview of this fault proofs feature. The challenger is responsible for: * Monitoring dispute games created by the fault proof system * Challenging invalid claims in dispute games * Defending valid state transitions * Resolving games when possible ## Prerequisites ### Essential requirements Complete these prerequisites before wiring up the challenger: The challenger needs the absolute prestate to participate in dispute games. The prestate is the on-chain commitment to a specific build of `kona-client`, the maintained fault proof program. (`op-program`, which previously filled this role, has reached end-of-support; see [End of Support for op-geth and op-program](/notices/archive/op-geth-deprecation).) Here's how to generate it: 1. **Clone and checkout the correct version**: ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git cd optimism git checkout kona-node/v1.6.1 # Use the latest release ``` 2. **Stage your chain configuration**: Because your chain is not in the public Superchain Registry, the prestate build must embed your chain's configuration. Create the two staging files (`chainList.json` and `configs.json`) from your `rollup.json`, L2 genesis, and `op-deployer` state by following [Generating a custom kona-client absolute prestate](/chain-operators/tutorials/kona-custom-prestate), then point the build at them: ```bash theme={null} # Assuming you're in rollup/challenger/optimism directory export KONA_CUSTOM_CONFIGS_DIR="$PWD/rust/kona/crates/protocol/registry/etc/custom-configs/" ``` 3. **Generate the prestate**: ```bash theme={null} just reproducible-prestate-kona jq -r .pre rust/kona/prestate-artifacts-cannon/prestate-proof.json ``` The build runs in Docker and writes artifacts to `rust/kona/prestate-artifacts-cannon/`, including a preimage file named by its hash (`0x.bin.gz`). The hash printed by the `jq` command is your chain's absolute prestate. 4. **Verify your chain is embedded in the prestate**: ```bash theme={null} gunzip -c rust/kona/prestate-artifacts-cannon/prestate.bin.gz | strings | grep "" ``` Zero matches means the custom configuration was not merged (the build silently produces the standard prestate instead); see the [custom prestate tutorial](/chain-operators/tutorials/kona-custom-prestate) for troubleshooting. * Keep the `0x.bin.gz` file accessible - you'll need it for the challenger setup * For Superchain registry chains, you can find official `cannon64-kona` prestates in the [registry](https://github.com/ethereum-optimism/superchain-registry/blob/main/validation/standard/standard-prestates.toml) Your sequencer stack from the previous steps already provides the L2 endpoints the challenger needs (op-reth and op-node). In addition, the challenger needs: * An L1 RPC endpoint for your settlement layer (Sepolia in this tutorial) * An L1 beacon API endpoint, used to fetch blobs * `0x.bin.gz` - The absolute prestate preimage file generated in step 1 * `rollup.json` - Rollup configuration file from the `op-deployer` guide ## Software installation For challenger deployment, we recommend using Docker as it provides a consistent and isolated environment. Building from source is also available for more advanced users. ### Docker Setup The Docker setup provides a containerized environment for running the challenger. This method uses the official Docker image that includes the embedded `kona` server and Cannon executable. ```bash theme={null} # Create your challenger directory inside rollup cd ../ # Go back to rollup directory if you're in proposer mkdir challenger cd challenger ``` **OP Stack Standard Variables** The challenger uses OP Stack standard environment variables following the OP Stack conventions. These are prefixed with `OP_CHALLENGER_` for challenger-specific settings. ```bash theme={null} # Create .env file with your actual values cat > .env << 'EOF' # Core configuration (required) OP_CHALLENGER_L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY OP_CHALLENGER_L1_BEACON_URL=https://ethereum-sepolia-beacon-api.publicnode.com OP_CHALLENGER_PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY # L2 Configuration - Replace with your actual node endpoints OP_CHALLENGER_L2_ETH_RPC=http://op-reth:8545 OP_CHALLENGER_ROLLUP_RPC=http://op-node:8547 # OP Stack challenger configuration (optional - defaults provided) OP_CHALLENGER_GAME_FACTORY_ADDRESS=YOUR_GAME_FACTORY_ADDRESS OP_CHALLENGER_CANNON_KONA_L2_GENESIS=/workspace/genesis.json OP_CHALLENGER_CANNON_KONA_ROLLUP_CONFIG=/workspace/rollup.json # Prestate configuration - Replace with the file from 'just reproducible-prestate-kona' OP_CHALLENGER_CANNON_KONA_PRESTATE=/workspace/${PRESTATE_HASH}.bin.gz EOF ``` **Important:** Replace every `YOUR_ACTUAL_*` placeholder with the real values from your deployment. Define the challenger service in a `docker-compose.yml`. It mounts several important files: * `prestate-proof.json` and `${PRESTATE_HASH}.bin.gz`: Prestate files required for dispute games (the PRESTATE\_HASH comes from running `just reproducible-prestate-kona`), replace `PRESTATE_HASH` with the actual hash ```yaml theme={null} services: challenger: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:v1.9.4 user: "1000" volumes: - ./challenger-data:/data - ./rollup.json:/workspace/rollup.json:ro - ./genesis-l2.json:/workspace/genesis-l2.json:ro - ./prestate-proof.json:/workspace/prestate-proof.json:ro - ./${PRESTATE_HASH}.bin.gz:/workspace/${PRESTATE_HASH}.bin.gz:ro command: > op-challenger run-trace --trace-type=cannon-kona --datadir=/data --log.level=info --log.format=json restart: unless-stopped networks: - sequencer-node_default networks: sequencer-node_default: external: false ``` Start the challenger service and follow its logs: ```bash theme={null} # Start the challenger service docker-compose up -d # View logs docker-compose logs -f challenger ``` The generic build-from-source walkthrough lives in the "Build from source" tab of the [challenger configuration guide](/chain-operators/guides/configuration/op-challenger-config-guide#software-installation): it covers picking the release, building `op-challenger`, Cannon, and `kona-host`, verifying the binaries, the environment file, and the startup script. Follow it end to end, then adapt it to this tutorial series as follows: * **Workspace**: create the working directory as `rollup/challenger`, next to the `deployer`, `sequencer`, `batcher`, and `proposer` directories from the previous steps. With the monorepo checkout at `rollup/optimism`, the binaries are then reachable from the startup script as `../../optimism/op-challenger/bin/op-challenger` and `CANNON_BIN=../../optimism/cannon/bin/cannon`. * **kona-host**: build it in the checkout you generated the prestate from in the prerequisites (`kona-node/v1.6.1`), so the server matches your chain's absolute prestate, and point `CANNON_KONA_SERVER` at the resulting binary. * **Configuration files**: copy `rollup.json` and `genesis-l2.json` from the op-deployer step into `rollup/challenger`, set `CANNON_ROLLUP_CONFIG=./rollup.json` and `CANNON_L2_GENESIS=./genesis-l2.json` (the guide's startup script passes these to `--cannon-kona-rollup-config` and `--cannon-kona-l2-genesis`), and set `CANNON_KONA_PRESTATE=./0x.bin.gz`, the preimage file generated in the prerequisites. * **Trace type and wallet**: this chain is not in the superchain-registry, so keep `GAME_FACTORY_ADDRESS` explicit, use `--trace-type cannon-kona`, and sign with the funded private key you used for the other components (`--private-key` instead of the guide's mnemonic example). ### Monitoring with op-dispute-mon Consider running [`op-dispute-mon`](/chain-operators/tools/chain-monitoring#dispute-mon) for enhanced security monitoring: * Provides visibility into all game statuses for the last 28 days * Essential for production challenger deployments ## Congratulations You've successfully completed the entire L2 rollup testnet tutorial! Your rollup is now fully operational with all components running: * **op-deployer** - L1 contracts deployed * **Sequencer** - Processing transactions * **Batcher** - Publishing data to L1 * **Proposer** - Submitting state roots * **Challenger** - Monitoring disputes ## Connect your wallet to your chain You now have a fully functioning OP Stack Rollup with a Sequencer node running on `http://localhost:8545`. You can connect your wallet to this chain the same way you'd connect your wallet to any other EVM chain. ## Get ETH on your chain Once you've connected your wallet, you'll probably notice that you don't have any ETH to pay for gas on your chain. The easiest way to deposit Sepolia ETH into your chain is to send ETH directly to the `L1StandardBridge` contract. ### Get the L1StandardBridge address The `L1StandardBridge` proxy address can be found in your deployment state file. To get it, run: ```bash theme={null} # From your project root jq -r .l1StandardBridgeProxyAddress /.deployer/state.json ``` This will output the `L1StandardBridge` proxy address that you should use for deposits. Make sure to use the proxy address, not the implementation address. ### Deposit ETH to your L2 Once you have the `L1StandardBridge` address, send a small amount of Sepolia ETH (0.1 or less) to that address from the wallet you want to use on L2. This will trigger a deposit that will mint ETH into your wallet on L2. It may take up to 5 minutes for the ETH to appear in your wallet on L2. This delay is due to the time needed for the deposit transaction to be processed and finalized. ## See your rollup in action You can interact with your Rollup the same way you'd interact with any other EVM chain. Send some transactions, deploy some contracts, and see what happens! You now have a working testnet. Here is what the distance to production looks like: **Running this in production** ## Need Help? * **OP Challenger Explainer**: [Fault Proofs Overview](/op-stack/fault-proofs/challenger) * **Technical Specs**: [Honest Challenger Specification](https://specs.optimism.io/fault-proof/stage-one/honest-challenger-fdg.html) # Deploy L1 contracts with op-deployer Source: https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/op-deployer-setup Install op-deployer, prepare your environment, and deploy the L1 smart contracts for your rollup. Welcome to the first step of creating your own L2 rollup testnet! In this section, you'll install the op-deployer tool and deploy the necessary L1 smart contracts for your rollup. **Step 1 of 5**: This tutorial is designed to be followed step-by-step. Each step builds on the previous one. **Quick Setup Available** For a complete automated setup that includes op-deployer deployment, check out the [`code/`](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) directory. The automated setup handles all contract deployment and configuration automatically. ## About op-deployer `op-deployer` simplifies the process of deploying the OP Stack. You define a declarative config file called an "**intent**," then run a command to apply it. `op-deployer` compares your chain's current state against the intent and makes the necessary changes to match. ## Installation There are a couple of ways to install `op-deployer`: The recommended way to install `op-deployer` is to download the latest release from the monorepo's [release page](https://github.com/ethereum-optimism/optimism/releases). **Quick Setup Available** For automated installation, you can use the download script from the [code directory](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/). This script automatically downloads the latest version for your system. 1. Go to the [release page](https://github.com/ethereum-optimism/optimism/releases) 2. Find the **latest** release that includes `op-deployer` (look for releases tagged with `op-deployer/v*`) 3. Under **assets**, download the binary that matches your system: * For Linux: `op-deployer-linux-amd64` * For macOS: * Apple Silicon (M1/M2): `op-deployer-darwin-arm64` * Intel processors: `op-deployer-darwin-amd64` * For Windows: `op-deployer-windows-amd64.exe` **Always download the latest version** to ensure you have the most recent features and bug fixes. Not sure which macOS version to use? * Open Terminal and run `uname -m` * If it shows `arm64`, use the arm64 version * If it shows `x86_64`, use the amd64 version 1. Create the rollup directory structure and enter the deployer directory: ```bash theme={null} # Create main rollup directory mkdir rollup && cd rollup # Create and enter the deployer directory mkdir deployer && cd deployer ``` Your directory structure will now look like this: ```bash theme={null} rollup/ └── deployer/ # You are here ``` 2. Move and rename the downloaded binary: The downloaded file is likely in your Downloads folder: * macOS/Linux: `/Users/YOUR_USERNAME/Downloads` * Windows WSL: `/mnt/c/Users/YOUR_USERNAME/Downloads` ```bash theme={null} # Step 1: Extract the downloaded archive in the deployer directory # Replace FILENAME with the actual downloaded file name (includes version and arch) tar -xvzf /Users/USERNAME/Downloads/FILENAME.tar.gz # Step 2: Make the binary executable # Replace FILENAME with the extracted binary name chmod +x FILENAME # Step 3: Remove macOS quarantine attribute (fixes "can't be opened" warning) sudo xattr -dr com.apple.quarantine FILENAME # Step 4: Move the binary to your PATH # For Intel Macs: sudo mv FILENAME /usr/local/bin/op-deployer # For Apple Silicon Macs: sudo mv FILENAME /opt/homebrew/bin/op-deployer # Step 5: Verify installation (should print version info) op-deployer --version ``` **Pro Tip**: Use the automated download script from the [code directory](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) to avoid manual version management. It automatically detects your platform and downloads the latest version. To install from source, you will need [Go](https://go.dev/doc/install), `just`, and `git`. After installing all of that, run following: ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git # you can skip this if you already have the repo cd optimism/op-deployer just build cp ./bin/op-deployer /usr/local/bin/op-deployer # or any other directory in your $PATH # Verify installation op-deployer --version ``` ## L1 network requirements Before deploying your L1 contracts, you'll need: **L1 RPC URL**: An Ethereum RPC endpoint for your chosen L1 network ```bash theme={null} # Examples: # Sepolia (recommended for testing) L1_RPC_URL=https://sepolia.infura.io/v3/YOUR-PROJECT-ID # or https://eth-sepolia.g.alchemy.com/v2/YOUR-API-KEY # Local network L1_RPC_URL=http://localhost:8545 ``` For testing, we recommend using Sepolia testnet. You can get free RPC access from: * [Infura](https://infura.io) (create account, get API key) * [Alchemy](https://alchemy.com) (create account, get API key) * [Ankr](https://ankr.com) (create account, get API key) ## Generate deployment addresses Your rollup needs several addresses for different roles. Let's generate them first: ```bash theme={null} # Create a address directory inside the deployer directory mkdir -p address cd address ``` Your directory structure will now look like this: ```bash theme={null} rollup/ └── deployer/ └── address/ # You are here ``` ```bash theme={null} # Generate 8 new wallet addresses for role in admin base_Fee_Vault_Recipient l1_Fee_Vault_Recipient sequencer_Fee_Vault_Recipient system_config unsafe_block_signer batcher proposer ; do wallet_output=$(cast wallet new) echo "$wallet_output" | grep "Address:" | awk '{print $2}' > ${role}_address.txt echo "Created wallet for $role" done ``` This will save the various addresses for your intent file into files in your current directory. To view them later you can use `cat *_address.txt`. **Important**: * Save these address - you'll need them to operate your chain * You can use any address for the purpose of testing, for production, use proper key management solutions (HSMs, multisigs addresses) ## Create and configure intent file The intent file defines your chain's configuration. Inside the `deployer` folder, run this command: ```bash theme={null} #You can use a 2-7 digit random number for your `` op-deployer init \ --l1-chain-id 11155111 \ --l2-chain-ids \ --workdir .deployer \ --intent-type standard-overrides ``` `op-deployer` supports three intent types: * `standard`: Uses default OP Stack configuration, minimal customization * `standard-overrides`: Recommended. Uses defaults but allows overriding specific values * `custom`: Full customization, requires manual configuration of all values For most users, `standard-overrides` provides the best balance of simplicity and flexibility. Edit `.deployer/intent.toml` with your generated addresses. The `op-deployer init` command automatically populates this file with sensible defaults. Update the addresses while keeping the auto-generated contract locator values: ```toml theme={null} configType = "standard-overrides" l1ChainID = 11155111 # Sepolia fundDevAccounts = false # Set to false for production/testnet useInterop = false opcmAddress = "0x3bb6437aba031afbf9cb3538fa064161e2bf2d78" # OPCM contract address on Sepolia # Contract locators - REQUIRED fields, automatically populated by op-deployer init # Keep these default values unless you need specific contract versions (advanced use case) l1ContractsLocator = "tag://op-contracts/v2.0.0" l2ContractsLocator = "tag://op-contracts/v1.7.0-beta.1+l2-contracts" # Shared contract roles - only define if creating a standalone chain not part of the OP Stack ecosystem # For standard OP Stack deployments, these are predefined and should not be set # [superchainRoles] # proxyAdminOwner = "0x..." # admin address # guardian = "0x..." # admin address [[chains]] id = "0x000000000000000000000000000000000000000000000000000000000016de8d" baseFeeVaultRecipient = "0x..." # receives base fees l1FeeVaultRecipient = "0x..." # receives L1 data fees sequencerFeeVaultRecipient = "0x..." # receives priority fees (tips) operatorFeeVaultRecipient = "0x..." # receives operator fees eip1559DenominatorCanyon = 250 eip1559Denominator = 50 eip1559Elasticity = 6 [chains.roles] l1ProxyAdminOwner = "0x1eb2ffc903729a0f03966b917003800b145f56e2" l2ProxyAdminOwner = "0x2fc3ffc903729a0f03966b917003800b145f67f3" systemConfigOwner = "0x..." # system_config address unsafeBlockSigner = "0x..." # unsafe_block_signer address batcher = "0x..." # batcher address proposer = "0x..." # proposer address challenger = "0xfd1d2e729ae8eee2e146c033bf4400fe75284301" ``` **Global Settings:** * `l1ChainID`: The L1 network ID (11155111 for Sepolia) * `fundDevAccounts`: Creates test accounts with ETH if true (set to false for production) * `useInterop`: Enable interoperability features (false for standard deployments) * `opcmAddress`: OP Contracts Manager (OPCM) contract address on the L1 network (automatically populated for supported networks) **Contract Locators (Required):** These fields are **required** and automatically populated by `op-deployer init` with default values compatible with your `op-deployer` version. Removing them will cause the error: "Application failed: L1ContractsLocator undefined". Keep the auto-generated values unless you specifically need different contract versions. For version compatibility details, see the [op-deployer release notes](https://github.com/ethereum-optimism/optimism/releases). **Shared Contract Roles (Advanced):** These are commented out because for standard OP Stack deployments, shared contract roles are predefined by the protocol. Only uncomment and define custom roles if you're creating a standalone chain not part of the OP Stack ecosystem. **Chain Configuration:** * `id`: Unique identifier for your chain * `*FeeVaultRecipient`: Addresses receiving protocol fees (required — deployment fails if any are set to the zero address). See [fee vaults](/op-stack/transactions/fee-vaults) for details on each vault. * `eip1559*`: Parameters for dynamic gas price calculation **Fee Vault Optional Overrides:** Each vault also supports optional parameters that can be set via deploy overrides. If not specified, the following defaults apply: | Parameter | Default | | -------------------------- | ------------ | | `*MinimumWithdrawalAmount` | 10 ETH | | `*WithdrawalNetwork` | `local` (L2) | **Chain Roles:** * `l1ProxyAdminOwner`: Can upgrade L1 contract implementations (usually same as superchain proxyAdminOwner) * `l2ProxyAdminOwner`: Can upgrade L2 contract implementations * `systemConfigOwner`: Manages system configuration parameters * `unsafeBlockSigner`: Signs pre-confirmation blocks (can be same as batcher) * `batcher`: Submits L2 transaction batches to L1 * `proposer`: Submits L2 state roots to L1 for verification * `challenger`: Monitors dispute games and defends valid states Replace all `0x...` with actual addresses from your `addresses.txt` file. Never use the default test mnemonic addresses in production or public testnets! ## Create environment file Before deploying, create a `.env` file in your `deployer` directory to store your environment variables: ```bash theme={null} # Create .env file cat << 'EOF' > .env # Your L1 RPC URL (e.g., from Alchemy, Infura) L1_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_API_KEY # Private key for deployment. # Get this from your self-custody wallet, like Metamask. PRIVATE_KEY=WALLET_PRIVATE_KEY EOF ``` Never commit your `.env` file to version control. Add it to your `.gitignore`: ```bash theme={null} echo ".env" >> .gitignore ``` Load the environment variables: ```bash theme={null} source .env ``` ## Deploy L1 Contracts Now that your intent file and environment variables are configured, let's deploy the L1 contracts: ```bash theme={null} op-deployer apply \ --workdir .deployer \ --l1-rpc-url $L1_RPC_URL \ --private-key $PRIVATE_KEY ``` This will: 1. Deploy all required L1 contracts 2. Configure them according to your intent file 3. Save deployment information to `.deployer/state.json` The deployment can take 10-15 seconds and requires multiple transactions. ## Generate chain configuration After successful deployment, generate your chain configuration files: ```bash theme={null} # Generate genesis and rollup configs op-deployer inspect genesis --workdir .deployer > .deployer/genesis.json op-deployer inspect rollup --workdir .deployer > .deployer/rollup.json ``` ## What's Next? Great! You've successfully: 1. Installed `op-deployer` using the `init` and `apply` command. 2. Created and configured your intent file 3. Deployed L1 smart contracts 4. Generated chain artifacts Your final directory structure should look like this: ```bash theme={null} rollup/ └── deployer/ ├── .deployer/ # Contains deployment state and configs │ ├── genesis.json # L2 genesis configuration │ ├── intent.toml # Your chain configuration │ ├── rollup.json # Rollup configuration │ └── state.json # Deployment state ├── .env # Environment variables └── address/ # Generated address pairs ├── admin_address.txt ├── base_Fee_Vault_Recipient_address.txt ├── batcher_address.txt ├── l1_Fee_Vault_Recipient_address.txt ├── proposer_address.txt ├── sequencer_Fee_Vault_Recipient_address.txt ├── system_config_address.txt └── unsafe_block_signer_address.txt ``` Now you can move on to setting up your sequencer node. **Next**: Set up op-reth and op-node, essential building blocks of the execution and consensus layers in your rollup. *** ## Need Help? * **op-deployer Documentation**: [op-deployer overview](/chain-operators/tools/op-deployer/overview) * **op-deployer Repository**: [GitHub](https://github.com/ethereum-optimism/optimism/tree/develop/op-deployer) * **OPCM Documentation**: [OP Contracts Manager](/chain-operators/reference/opcm) * **Support**: Open an issue in the [Optimism monorepo](https://github.com/ethereum-optimism/optimism/issues) # Spin up proposer Source: https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/op-proposer-setup Learn how to set up and configure an OP Stack proposer to post L2 state roots. After you have spun up your sequencer and batcher, you need to attach a proposer to post your L2 state roots data back onto L1 so we can prove withdrawal validity. The proposer is a critical component that enables trustless L2-to-L1 messaging and creates the authoritative view of L2 state from L1's perspective. **Step 4 of 5**: This tutorial is designed to be followed step-by-step. Each step builds on the previous one. **Automated Setup Available** For a complete working setup with all components, check out the [automated approach](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) in the code directory. This guide assumes you already have a functioning sequencer, batcher, and the necessary L1 contracts deployed using [`op-deployer`](./op-deployer-setup). If you haven't set up your sequencer and batcher yet, please refer to the [sequencer guide](./op-reth-setup) and [batcher guide](./op-batcher-setup) first. To see configuration info for the proposer, check out the [configuration page](/chain-operators/guides/configuration/proposer). ## Understanding the proposer's role The proposer (`op-proposer`) serves as a crucial bridge between your L2 chain and L1. Its primary responsibilities include: * **State commitment**: Proposing L2 state roots to L1 at regular intervals * **Withdrawal enablement**: Providing the necessary commitments for users to prove and finalize withdrawals The proposer creates dispute games via the `DisputeGameFactory` contract. ## Prerequisites Before setting up your proposer, ensure you have: **Running infrastructure:** * An operational sequencer node * Access to a L1 RPC endpoint **Network information:** * Your L2 chain ID and network configuration * L1 network details (chain ID, RPC endpoints) For setting up the proposer, we recommend using Docker as it provides a consistent and isolated environment. Building from source is also available as an option. If you prefer containerized deployment, you can use the official Docker images and do the following: ```bash theme={null} # Create a proposer directory inside rollup cd ../ # Go back to rollup directory if you're in batcher mkdir proposer cd proposer # inside the proposer directory, copy the state.json file from the op-deployer setup # Copy configuration files from deployer cp ../deployer/.deployer/state.json . # Extract the DisputeGameFactory address GAME_FACTORY_ADDRESS=$(cat state.json | jq -r '.opChainDeployments[0].DisputeGameFactoryProxy') echo "DisputeGameFactory Address: $GAME_FACTORY_ADDRESS" ``` **OP Stack Standard Variables** The proposer uses OP Stack standard environment variables following the OP Stack conventions. These are prefixed with `OP_PROPOSER_` for proposer-specific settings. ```bash theme={null} # Create .env file with your actual values cat > .env << 'EOF' # L1 Configuration - Replace with your actual RPC URLs OP_PROPOSER_L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY # L2 Configuration - Should match your sequencer setup OP_PROPOSER_ROLLUP_RPC=http://op-node:8547 # Contract addresses - Extract from your op-deployer output OP_PROPOSER_GAME_FACTORY_ADDRESS=YOUR_ACTUAL_GAME_FACTORY_ADDRESS # Private key - Replace with your actual private key OP_PROPOSER_PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY # OP Stack proposer configuration (optional - defaults provided) OP_PROPOSER_PROPOSAL_INTERVAL=3600s OP_PROPOSER_GAME_TYPE=0 OP_PROPOSER_POLL_INTERVAL=20s OP_PROPOSER_ALLOW_NON_FINALIZED=true OP_PROPOSER_WAIT_NODE_SYNC=true EOF ``` **Important**: Replace ALL placeholder values (`YOUR_ACTUAL_*`) with your real configuration values. If you get "failed to dial address" errors, ensure your proposer is in the same Docker network as your sequencer. Common fixes: * Add `networks: - sequencer-node_default` to your proposer's docker-compose.yml * Use service names like `op-reth:8545` and `op-node:8547` in your `.env` file * Verify your sequencer network name with `docker network ls` ```yaml theme={null} services: op-proposer: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-proposer:v1.16.3 volumes: - .:/workspace working_dir: /workspace ports: - "8560:8560" env_file: - .env command: > op-proposer --rpc.port=8560 --log.level=info --log.format=json restart: unless-stopped networks: - sequencer-node_default networks: sequencer-node_default: external: false ``` ```bash theme={null} # Make sure your sequencer network exists docker network create op-stack 2>/dev/null || true # Start the proposer docker-compose up -d # View logs docker-compose logs -f op-proposer ``` ```bash theme={null} # Check container status docker-compose ps ``` ```bash theme={null} rollup/ ├── deployer/ # From previous step │ └── .deployer/ # Contains state.json ├── sequencer/ # From previous step ├── batcher/ # From previous step └── proposer/ # You are here ├── state.json # Copied from deployer ├── .env # Environment variables └── docker-compose.yml # Docker configuration ``` When you first start your proposer, you'll see several types of log messages: 1. **Initialization messages** (normal): ``` lvl=info msg="Initializing L2Output Submitter" lvl=info msg="Connected to DisputeGameFactory" lvl=info msg="Starting JSON-RPC server" ``` 2. **Sync status messages** (expected during startup): ``` msg="rollup current L1 block still behind target, retrying" current_l1=...:9094035 target_l1=9132815 ``` This is normal! It means: * Your rollup is still syncing with L1 (e.g., Sepolia) * The proposer is waiting until sync is closer to L1 tip * You'll see the `current_l1` number increasing as it catches up * Once caught up, the proposer will start submitting proposals Don't worry about the "retrying" messages - they show healthy progress as your rollup catches up to the latest L1 blocks. **Common log patterns:** * Startup: You'll see initialization messages as services start * Sync: "block still behind target" messages while catching up * Normal operation: Regular proposal submissions once synced * Network: Connection messages to L1/L2 endpoints If you see errors about "failed to dial" or connection issues: * For source build: Verify your localhost ports and services Your proposer is now operational and will continuously submit state roots to L1! ### Finding the current stable releases To ensure you're using the latest compatible versions of OP Stack components, always check the official [releases page](https://github.com/ethereum-optimism/optimism/releases). Look for the latest `op-proposer/v*` release that's compatible with your sequencer setup. This guide uses `op-proposer/v1.16.3`, the latest release at the time of writing, alongside op-node/v1.19.3 and op-reth/v2.4.0 from the sequencer setup. Always check the [release notes](https://github.com/ethereum-optimism/optimism/releases) for compatibility information. Building from source gives you full control over the binaries. ```bash theme={null} # If you don't already have the optimism repository from the sequencer setup git clone https://github.com/ethereum-optimism/optimism.git cd optimism # Checkout the latest release tag git checkout op-proposer/v1.16.3 # Build op-proposer cd op-proposer just # Binary will be available at ./bin/op-proposer ``` Run this command to verify the installation: ```bash theme={null} ./bin/op-proposer --version ``` ## Configuration setup The rest of this guide assumes you're using the **build-from-source** approach. If you chose Docker, all the necessary configuration was covered in the Docker tab above. Create your proposer working directory at the same level as your sequencer: ```bash theme={null} # Create proposer directory inside rollup cd ../ # Go back to rollup directory mkdir proposer cd proposer # Create scripts directory mkdir scripts ``` Extract the `DisputeGameFactory` contract address from your op-deployer output: ```bash theme={null} # Make sure you're in the rollup/proposer directory cd rollup/proposer # Copy the state.json from deployer cp ../deployer/.deployer/state.json . # Extract the DisputeGameFactory address GAME_FACTORY_ADDRESS=$(cat state.json | jq -r '.opChainDeployments[0].disputeGameFactoryProxyAddress') echo "DisputeGameFactory Address: $GAME_FACTORY_ADDRESS" ``` The proposer only needs the `DisputeGameFactory` address to submit proposals. The `GAME_TYPE=0` represents the standard fault proof game type. Create your `.env` file with the actual values: ```bash theme={null} # Create .env file with your actual values # L1 Configuration - Replace with your actual RPC URL L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY # L2 Configuration - Should match your sequencer setup L2_RPC_URL=http://localhost:8545 ROLLUP_RPC_URL=http://localhost:8547 # Contract addresses - Extract from your op-deployer output GAME_FACTORY_ADDRESS=YOUR_ACTUAL_GAME_FACTORY_ADDRESS # Private key - Replace with your actual private key PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY # Proposer configuration PROPOSAL_INTERVAL=3600s GAME_TYPE=0 POLL_INTERVAL=20s # RPC configuration PROPOSER_RPC_PORT=8560 ``` **Important**: Replace ALL placeholder values (`YOUR_ACTUAL_*`) with your real configuration values! Get a private key from your wallet that will be used for submitting proposals to L1. This account needs sufficient ETH to pay for L1 gas costs. The proposer account needs to be funded with ETH on L1 to pay for proposal submission transactions. Monitor this account's balance regularly as it will consume ETH for each proposal submission. ## Proposer configuration Create `scripts/start-proposer.sh`: ```bash theme={null} #!/bin/bash source .env # Path to the op-proposer binary we built ../../optimism/op-proposer/bin/op-proposer \ --poll-interval=$POLL_INTERVAL \ --rpc.port=$PROPOSER_RPC_PORT \ --rpc.enable-admin \ --rollup-rpc=$ROLLUP_RPC_URL \ --l1-eth-rpc=$L1_RPC_URL \ --private-key=$PRIVATE_KEY \ --game-factory-address=$GAME_FACTORY_ADDRESS \ --game-type=$GAME_TYPE \ --proposal-interval=$PROPOSAL_INTERVAL \ --num-confirmations=1 \ --resubmission-timeout=30s \ --wait-node-sync=true \ --log.level=info ``` Your final directory structure should look like: ```bash theme={null} rollup/ ├── deployer/ # From previous step │ └── .deployer/ # Contains state.json ├── optimism/ # Contains op-proposer binary ├── sequencer/ # From previous step ├── batcher/ # From previous step └── proposer/ # You are here ├── state.json # Copied from deployer ├── .env # Environment variables └── scripts/ # Startup scripts └── start-proposer.sh ``` ## Starting the proposer ```bash theme={null} # Make the script executable chmod +x scripts/start-proposer.sh # Start the proposer ./scripts/start-proposer.sh ``` When you first start your proposer, you'll see several types of log messages: 1. **Initialization messages** (normal): ``` lvl=info msg="Initializing L2Output Submitter" lvl=info msg="Connected to DisputeGameFactory" lvl=info msg="Starting JSON-RPC server" ``` 2. **Sync status messages** (expected during startup): ``` msg="rollup current L1 block still behind target, retrying" current_l1=...:9094035 target_l1=9132815 ``` This is normal! It means: * Your rollup is still syncing with L1 (e.g., Sepolia) * The proposer is waiting until sync is closer to L1 tip * You'll see the `current_l1` number increasing as it catches up * Once caught up, the proposer will start submitting proposals Don't worry about the "retrying" messages - they show healthy progress as your rollup catches up to the latest L1 blocks. **Common log patterns:** * Startup: You'll see initialization messages as services start * Sync: "block still behind target" messages while catching up * Normal operation: Regular proposal submissions once synced * Network: Connection messages to L1/L2 endpoints If you see errors about "failed to dial" or connection issues: * For Docker: Check your network configuration and service names Your proposer is now operational! ## What's Next? Perfect! Your proposer is submitting state roots to L1. The final step is to set up the challenger to monitor and respond to disputes. **Next**: Configure and start op-challenger to monitor disputes and maintain your rollup's security. *** ## Need Help? * **Proposer Configuration**: [op-proposer Configuration Reference](/chain-operators/guides/configuration/proposer) * **Dispute Games**: [Deploying Dispute Games with OPCM](/chain-operators/tutorials/dispute-games) # Spin up sequencer Source: https://docs.optimism.io/chain-operators/tutorials/create-l2-rollup/op-reth-setup Set up and run op-reth and op-node, the execution and consensus layers for your rollup. Now that you have op-deployer configured, it's time to spin up the sequencer for your rollup. This involves running both `op-reth` and `op-node` to create a functioning sequencer. **Step 2 of 5**: This tutorial builds on [Spin up op-deployer](./op-deployer-setup). Make sure you've completed that first. **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. This tutorial previously taught `op-geth` as the execution client; this page now uses `op-reth` throughout. ## What you'll set up The sequencer node consists of two core components: * `op-reth`: Execution layer that processes transactions and maintains state * `op-node`: Consensus layer that orders transactions and creates L2 blocks The sequencer is responsible for: * Ordering transactions from users * Building L2 blocks * Signing blocks on the P2P network ## Software installation For spinning up a sequencer, we recommend using Docker, as it provides a simpler setup and consistent environment. In this guide, building from source is also provided as an alternative for those who need more control and easier debugging. The versions used in this guide (**op-node/v1.19.3** and **op-reth/v2.4.0**) were the latest releases at the time of writing. Check the [op-node releases](https://github.com/ethereum-optimism/optimism/releases?q=op-node) and [op-reth releases](https://github.com/ethereum-optimism/optimism/releases?q=op-reth) for the current versions, and always read the release notes for compatibility information. If you prefer containerized deployment, you can use the official Docker images, and do the following: ```bash theme={null} # Create your sequencer directory inside rollup cd ../ # Go back to rollup directory if you're in deployer mkdir sequencer cd sequencer # Copy configuration files from deployer cp ../deployer/.deployer/genesis.json . cp ../deployer/.deployer/rollup.json . # Generate JWT secret openssl rand -hex 32 > jwt.txt chmod 600 jwt.txt ``` ```bash theme={null} # Create .env file with your actual values cat > .env << 'EOF' # L1 Configuration - Replace with your actual RPC URLs L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY L1_BEACON_URL=https://ethereum-sepolia-beacon-api.publicnode.com # Private keys - Replace with your actual private key PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY # P2P configuration - Replace with your actual public IP # Run `curl ifconfig.me` in a separate shell to obtain the value, then paste it below P2P_ADVERTISE_IP=YOUR_ACTUAL_PUBLIC_IP EOF ``` **Important**: Replace ALL placeholder values (`YOUR_ACTUAL_*`) with your real configuration values. Create a `docker-compose.yml` file in the same directory: ```yaml theme={null} services: op-reth: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-reth:v2.4.0 volumes: # Mount entire directory to avoid file mounting issues - .:/workspace working_dir: /workspace ports: - "8545:8545" - "8546:8546" - "8551:8551" command: - "node" - "--chain=/workspace/genesis.json" - "--datadir=/workspace/op-reth-data" - "--http" - "--http.addr=0.0.0.0" - "--http.port=8545" - "--http.corsdomain=*" - "--http.api=admin,debug,eth,net,txpool,web3" - "--ws" - "--ws.addr=0.0.0.0" - "--ws.port=8546" - "--ws.origins=*" - "--ws.api=admin,debug,eth,net,txpool,web3" - "--authrpc.addr=0.0.0.0" - "--authrpc.port=8551" - "--authrpc.jwtsecret=/workspace/jwt.txt" - "--rollup.disable-tx-pool-gossip" - "--builder.deadline=2" - "--builder.interval=100ms" op-node: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-node:v1.19.3 depends_on: - op-reth volumes: - .:/workspace working_dir: /workspace ports: - "8547:8547" - "9222:9222" environment: - L1_RPC_URL=${L1_RPC_URL} - L1_BEACON_URL=${L1_BEACON_URL} - PRIVATE_KEY=${PRIVATE_KEY} - P2P_ADVERTISE_IP=${P2P_ADVERTISE_IP} command: - "op-node" - "--l1=${L1_RPC_URL}" - "--l1.beacon=${L1_BEACON_URL}" - "--l2=http://op-reth:8551" - "--l2.jwt-secret=/workspace/jwt.txt" - "--l2.enginekind=reth" - "--rollup.config=/workspace/rollup.json" - "--sequencer.enabled=true" - "--sequencer.stopped=false" - "--sequencer.max-safe-lag=3600" - "--verifier.l1-confs=4" - "--p2p.listen.ip=0.0.0.0" - "--p2p.listen.tcp=9222" - "--p2p.listen.udp=9222" - "--p2p.advertise.ip=${P2P_ADVERTISE_IP}" - "--p2p.advertise.tcp=9222" - "--p2p.advertise.udp=9222" - "--p2p.sequencer.key=${PRIVATE_KEY}" - "--rpc.addr=0.0.0.0" - "--rpc.port=8547" - "--rpc.enable-admin" - "--log.level=info" - "--log.format=json" ``` A few flags worth understanding: * `--chain=/workspace/genesis.json` points op-reth at the genesis file generated by op-deployer. Unlike op-geth, op-reth needs no separate `init` step — it initializes its database from the chain spec on first startup. * `--l2.enginekind=reth` tells op-node it is driving a reth-based execution client. * `--rollup.disable-tx-pool-gossip` is the op-reth equivalent of op-geth's `--rollup.disabletxpoolgossip=true`. * `--builder.deadline=2` and `--builder.interval=100ms` tune op-reth's block builder for the 2-second L2 block time (the defaults target Ethereum's 12-second slots). * op-reth runs as an archive node by default, so there is no `--gcmode=archive` equivalent to set. ```bash theme={null} # Start both services docker-compose up -d # View logs docker-compose logs -f ``` ```bash theme={null} rollup/ ├── deployer/ # From previous step │ └── .deployer/ # Contains genesis.json and rollup.json └── sequencer/ # You are here ├── jwt.txt # Generated JWT secret ├── genesis.json # Copied from deployer ├── rollup.json # Copied from deployer ├── .env # Environment variables ├── docker-compose.yml # Docker configuration ├── opnode_discovery_db/ # Created by Docker ├── opnode_peerstore_db/ # Created by Docker └── op-reth-data/ # Created by Docker (op-reth database) ``` Your sequencer node is now operational and ready to process transactions. To ensure you're using the latest compatible versions of OP Stack components, always check the official [release page](https://github.com/ethereum-optimism/optimism/releases). The main components you'll need for sequencer deployment are: * `op-node`: Look for the latest `op-node/v*` [release](https://github.com/ethereum-optimism/optimism/releases?q=op-node) * `op-reth`: Look for the latest `op-reth/v*` [release](https://github.com/ethereum-optimism/optimism/releases?q=op-reth) Both components live in the [optimism monorepo](https://github.com/ethereum-optimism/optimism). Building op-node requires [Go](https://go.dev/dl/) and [just](https://github.com/casey/just); building op-reth requires a [Rust toolchain](https://rustup.rs/) (the build picks up the version pinned in `rust/rust-toolchain.toml` automatically). Building from source gives you full control over the binaries. ```bash theme={null} # Clone the optimism monorepo git clone https://github.com/ethereum-optimism/optimism.git cd optimism # Checkout the latest op-node release tag git checkout op-node/v1.19.3 # Generate the embedded superchain config bundle (initializes the # superchain-registry submodule; op-node embeds this file at compile time) just build-superchain-go # Build op-node cd op-node just # Binary will be available at ./bin/op-node cd .. ``` ```bash theme={null} # Still inside the optimism monorepo: # checkout the latest op-reth release tag git checkout op-reth/v2.4.0 # Sync the superchain-registry submodule to this tag # (the op-reth build generates its chain configs from it) just update-superchain-registry-submodule # Build op-reth (release build; this can take a while) cd rust cargo build --release --bin op-reth # Binary will be available at ./target/release/op-reth cd .. ``` op-node and op-reth release from the same repository on different tags, so the two builds check out different tags in sequence. The `--version` checks below confirm what you actually built. If you prefer, use two separate clones of the monorepo instead. Check that you have properly installed the needed components. ```bash theme={null} # From the optimism monorepo root ./op-node/bin/op-node --version ./rust/target/release/op-reth --version ``` ## Configuration setup After building the binaries, you should have the following directory structure: ```bash theme={null} rollup/ ├── deployer/ # From previous step │ └── .deployer/ # Contains genesis.json and rollup.json └── optimism/ # Optimism monorepo ├── op-node/ │ └── bin/ │ └── op-node └── rust/ └── target/ └── release/ └── op-reth ``` Now create your sequencer working directory: ```bash theme={null} cd ../ mkdir sequencer cd sequencer ``` ```bash theme={null} openssl rand -hex 32 > jwt.txt chmod 600 jwt.txt ``` ```bash theme={null} mkdir scripts cp ../deployer/.deployer/genesis.json . cp ../deployer/.deployer/rollup.json . ``` You'll need to gather several pieces of information before creating your configuration. You need access to the L1 network (Ethereum mainnet or Sepolia testnet) and its beacon node. **L1 RPC URL options:** * **Infura**: [infura.io](https://infura.io) * **Alchemy**: [alchemy.com](https://alchemy.com) **L1 Beacon URL options:** * `https://ethereum-sepolia-beacon-api.publicnode.com` * `https://ethereum-beacon-api.publicnode.com` For this basic sequencer setup, you only need a private key during op-node initialization. ```bash theme={null} curl ifconfig.me curl ipinfo.io/ip ``` * `8545`: op-reth HTTP RPC * `8546`: op-reth WebSocket RPC * `8551`: op-reth Auth RPC (Engine API) * `8547`: op-node RPC * `9222`: P2P networking ```bash theme={null} L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY L1_BEACON_URL=https://ethereum-sepolia-beacon-api.publicnode.com SEQUENCER_ENABLED=true SEQUENCER_STOPPED=false PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY P2P_LISTEN_PORT=9222 P2P_ADVERTISE_IP=YOUR_ACTUAL_PUBLIC_IP OP_NODE_RPC_PORT=8547 OP_RETH_HTTP_PORT=8545 OP_RETH_WS_PORT=8546 OP_RETH_AUTH_PORT=8551 JWT_SECRET=./jwt.txt ``` ## Sequencer specific configuration ### op-reth configuration for sequencer Create `scripts/start-op-reth.sh`: ```bash theme={null} #!/bin/bash source .env ../optimism/rust/target/release/op-reth node \ --chain=./genesis.json \ --datadir=./op-reth-data \ --http \ --http.addr=0.0.0.0 \ --http.port=$OP_RETH_HTTP_PORT \ --http.corsdomain="*" \ --http.api=admin,debug,eth,net,txpool,web3 \ --ws \ --ws.addr=0.0.0.0 \ --ws.port=$OP_RETH_WS_PORT \ --ws.origins="*" \ --ws.api=admin,debug,eth,net,txpool,web3 \ --authrpc.addr=0.0.0.0 \ --authrpc.port=$OP_RETH_AUTH_PORT \ --authrpc.jwtsecret=$JWT_SECRET \ --rollup.disable-tx-pool-gossip \ --builder.deadline=2 \ --builder.interval=100ms ``` op-reth initializes its database from the genesis file on first startup — there is no separate `geth init`-style step. It also runs as an archive node by default. ### op-node configuration for sequencer Create `scripts/start-op-node.sh`: ```bash theme={null} #!/bin/bash source .env ../optimism/op-node/bin/op-node \ --l1=$L1_RPC_URL \ --l1.beacon=$L1_BEACON_URL \ --l2=http://localhost:$OP_RETH_AUTH_PORT \ --l2.jwt-secret=$JWT_SECRET \ --l2.enginekind=reth \ --rollup.config=./rollup.json \ --sequencer.enabled=$SEQUENCER_ENABLED \ --sequencer.stopped=$SEQUENCER_STOPPED \ --sequencer.max-safe-lag=3600 \ --verifier.l1-confs=4 \ --p2p.listen.ip=0.0.0.0 \ --p2p.listen.tcp=$P2P_LISTEN_PORT \ --p2p.listen.udp=$P2P_LISTEN_PORT \ --p2p.advertise.ip=$P2P_ADVERTISE_IP \ --p2p.advertise.tcp=$P2P_LISTEN_PORT \ --p2p.advertise.udp=$P2P_LISTEN_PORT \ --p2p.sequencer.key=$PRIVATE_KEY \ --rpc.addr=0.0.0.0 \ --rpc.port=$OP_NODE_RPC_PORT \ --rpc.enable-admin \ --log.level=info \ --log.format=json ``` ## Starting the sequencer ```bash theme={null} cd rollup/sequencer chmod +x scripts/start-op-reth.sh chmod +x scripts/start-op-node.sh ./scripts/start-op-reth.sh ``` In a second terminal: ```bash theme={null} ./scripts/start-op-node.sh ``` ```bash theme={null} curl -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ http://localhost:8545 curl -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"admin_sequencerActive","params":[],"id":1}' \ http://localhost:8547 ``` Your sequencer node is now operational and ready to process transactions. ## What's Next? Great! Your sequencer is running and processing transactions. The next step is to set up the batcher to publish transaction data to L1. **Next**: Configure and start op-batcher to publish L2 transaction data to L1 for data availability. *** ## Need Help? * **Running op-reth**: [Execution client configuration](/node-operators/guides/configuration/execution-clients) * **op-reth CLI reference**: [op-reth node command](/node-operators/op-reth/cli/op-reth/node) * **Best Practices**: [Chain Operator Best Practices](/chain-operators/guides/management/best-practices) * **Support**: [Report an issue or ask a question](https://github.com/ethereum-optimism/optimism/issues) in the Optimism monorepo # Deploying new dispute games with OPCM Source: https://docs.optimism.io/chain-operators/tutorials/dispute-games Learn how to deploy new dispute games to an OP Stack chain using OPCM This guide provides instructions on how to deploy new dispute games to an OP Stack chain using the [OPCM (OP Contracts Manager)](/chain-operators/reference/opcm). This process is particularly relevant for teams looking to upgrade their chains to support permissionless dispute games. ## Prerequisites Before you begin, ensure that: * Run op-contracts/v2.0.0 or higher on your chain * Own the chain's L1 `ProxyAdmin` contract * Install the Forge toolkit (see [Foundry docs](https://getfoundry.sh/)) ## Understanding dispute games The OP Stack uses two types of dispute games: * **Permissioned dispute game**: Limited to specific proposer and challenger addresses * **Permissionless dispute game**: Open to anyone to propose or challenge In the Permissioned dispute game (PDG), the [challenger role](/op-stack/protocol/privileged-roles) is a protocol-level permission assigned to specific addresses, allowing them to initiate or respond to disputes. This role is distinct from the op-challenger service, which is an off-chain monitoring service responsible for automatically detecting discrepancies and submitting challenges. While the op-challenger service typically operates using an address that has been assigned the challenger role, the protocol-level role itself can be independently assigned, regardless of whether the op-challenger service is in use. Refer to the [OP Stack configurability spec](https://specs.optimism.io/protocol/configurability.html) for more details. All chains deployed with `op-deployer` only initially include the permissioned dispute game. This guide explains how to add the permissionless game. ## The `addGameType` function The OPCM contract contains an `addGameType` function that handles the deployment of new dispute games. This function: 1. Deploys a new dispute game implementation 2. Optionally deploys a new [`DelayedWETH`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/DelayedWETH.sol) contract 3. Registers the game with the `DisputeGameFactory` 4. Sets the initial bond amount ### 1. Finding the correct OPCM instance Each OP Contracts release has its own OPCM instance. You must use the OPCM corresponding exactly to your chain's contract version. For example, if your system uses contracts version **v3.0.0**, you must use the OPCM for **v3.0.0**. To find the correct OPCM address: * For **Mainnet**, refer to the [standard-versions-mainnet.toml](https://github.com/ethereum-optimism/superchain-registry/blob/main/validation/standard/standard-versions-mainnet.toml) file in the superchain-registry. * For **Sepolia**, refer to the [standard-versions-sepolia.toml](https://github.com/ethereum-optimism/superchain-registry/blob/main/validation/standard/standard-versions-sepolia.toml) file in the superchain-registry. These registry files contain mappings between OP contract versions and their corresponding OPCM addresses. ### 2. Preparing the `addGameType` Call The `addGameType` function expects an array of `AddGameInput` structs. Here is the structure: ```solidity theme={null} struct AddGameInput { string saltMixer; ISystemConfig systemConfig; IProxyAdmin proxyAdmin; IDelayedWETH delayedWETH; GameType disputeGameType; Claim disputeAbsolutePrestate; uint256 disputeMaxGameDepth; uint256 disputeSplitDepth; Duration disputeClockExtension; Duration disputeMaxClockDuration; uint256 initialBond; IBigStepper vm; bool permissioned; } ``` **Key parameters explained:** * **saltMixer:** A string used to create unique contract addresses * **systemConfig:** The address of your chain's `SystemConfig` contract * **proxyAdmin:** The Address of your chain's `ProxyAdmin` contract * **delayedWETH:** The Address of the `DelayedWETH` contract (use zero address to deploy a new one) * **disputeGameType:** For permissionless games, use `GameTypes.CANNON` * **disputeAbsolutePrestate:** The absolute prestate hash for the game * **permissioned:** Set to `false` for a permissionless game For a permissionless game, you'll generally want to mirror most parameters from your existing permissioned game, but set permissioned to `false` and use the GameType `CANNON`. 3. Execute the addGameType function The following is a template for calling the addGameType function using Forge's cast: The most recommended way is to use a script to execute this call, rather than manual execution. ```bash theme={null} # Retrieve existing values from chain for reference # Get permissioned game implementation PERMISSIONED_GAME=$(cast call --rpc-url $RPC_URL $DISPUTE_GAME_FACTORY "gameImpls(uint32)" $PERMISSIONED_GAME_TYPE) # Retrieve parameters from existing permissioned game ABSOLUTE_PRESTATE=$(cast call --rpc-url $RPC_URL $PERMISSIONED_GAME "absolutePrestate()") MAX_GAME_DEPTH=$(cast call --rpc-url $RPC_URL $PERMISSIONED_GAME "maxGameDepth()") SPLIT_DEPTH=$(cast call --rpc-url $RPC_URL $PERMISSIONED_GAME "splitDepth()") CLOCK_EXTENSION=$(cast call --rpc-url $RPC_URL $PERMISSIONED_GAME "clockExtension()") MAX_CLOCK_DURATION=$(cast call --rpc-url $RPC_URL $PERMISSIONED_GAME "maxClockDuration()") VM=$(cast call --rpc-url $RPC_URL $PERMISSIONED_GAME "vm()") ANCHOR_STATE_REGISTRY=$(cast call --rpc-url $RPC_URL $PERMISSIONED_GAME "anchorStateRegistry()") L2_CHAIN_ID=$(cast call --rpc-url $RPC_URL $PERMISSIONED_GAME "l2ChainId()") # Create call data for addGameType function # Note: Set delayedWETH to 0x0 to deploy a new one CALLDATA=$(cast calldata "addGameType((string,address,address,address,uint32,bytes32,uint256,uint256,uint64,uint64,uint256,address,bool)[])" \ "[(\ \"unique_salt_mixer\",\ $SYSTEM_CONFIG,\ $PROXY_ADMIN,\ 0x0000000000000000000000000000000000000000,\ $CANNON_GAME_TYPE,\ $ABSOLUTE_PRESTATE,\ $MAX_GAME_DEPTH,\ $SPLIT_DEPTH,\ $CLOCK_EXTENSION,\ $MAX_CLOCK_DURATION,\ $INITIAL_BOND,\ $VM,\ false\ )]") # Execute the transaction cast send --rpc-url $RPC_URL --private-key $PRIVATE_KEY $OPCM_ADDRESS $CALLDATA ``` 4. Setting the respected game type After deploying the permissionless dispute game, you'll need to update the respectedGameType in the OptimismPortal to start using it. For detailed instructions on setting the respected game type and migrating your chain from permissioned to permissionless fault proofs, refer to the [migrating to permissionless fault proofs guide](/chain-operators/tutorials/migrating-permissionless). ## Next Steps * For more detail on deploying new dispute games with OPCM, [see the docs](/chain-operators/tutorials/dispute-games). * Learn about [absolute prestate](/chain-operators/tutorials/absolute-prestate) * checkout the [migrating to permissionless fault proofs](/chain-operators/tutorials/migrating-permissionless) guide * [Fault proofs explainer](/op-stack/fault-proofs/explainer) # Integrating a new DA layer with Alt-DA Source: https://docs.optimism.io/chain-operators/tutorials/integrating-da-layer Learn how to add support for a new DA Layer within the OP Stack. The Alt-DA Mode feature is currently in Beta within the MIT-licensed OP Stack. Beta features are built and reviewed by Optimism Collective core contributors, and provide developers with early access to highly requested configurations. These features may experience stability issues, and we encourage feedback from our early users. [Alt-DA Mode](/op-stack/features/experimental/alt-da-mode) enables seamless integration of any DA Layer, regardless of their commitment type, into the OP Stack. After a DA Server is built for a DA Layer, any chain operator can launch an OP Stack chain using that DA Layer for sustainably low costs. ## Build your DA server Our suggestion is for every DA Layer to build and maintain their own DA Server, with support from the OP Labs team along the way. The DA Server will need to be run by every node operator, so we highly recommend making your DA Server open source and MIT licensed. * It must point to the data on your layer (like block height / hash). * It must be able to validate the data returned from the data (i.e., include a cryptographic commitment to the data like a hash, merkle proof, or polynomial commitment, this could be done against the block hash with a complex proof). See the [specs](https://specs.optimism.io/experimental/alt-da.html?highlight=input-commitment-submission?utm_source=op-docs\&utm_medium=docs#input-commitment-submission) for more info on commitment submission. * Claim your [byte](https://github.com/ethereum-optimism/specs/discussions/135) * Write a simple HTTP server which supports `get` and `put` * `put` is used by the batcher and can return the commitment to the batcher in the body. It should not return until the data is known to be submitted to your DA layer. * `get` should fetch the data. If the data is not available, it should return a `404` not found. If there are other errors, a different error should be returned. ## Run Alt-DA Follow our guide on [how to operate an Alt-DA Mode chain](/chain-operators/guides/features/alt-da-mode-guide), except instead of using the S3 DA server, use the DA server that you built. ## Next steps * For more detail on implementing the DA Server, [see the specification](https://specs.optimism.io/experimental/alt-da.html?utm_source=op-docs\&utm_medium=docs#da-server). # Generating a custom kona-client absolute prestate Source: https://docs.optimism.io/chain-operators/tutorials/kona-custom-prestate How to build a kona-client absolute prestate that embeds a chain configuration not yet in the public Superchain Registry. # Overview For chains that are part of the public [`superchain-registry`](https://github.com/ethereum-optimism/superchain-registry), the standard `kona-client` absolute prestate published in [`standard-prestates.toml`](https://github.com/ethereum-optimism/superchain-registry/blob/main/validation/standard/standard-prestates.toml) already embeds your chain configuration. No custom build is needed. This tutorial is for the rarer case: a partner chain whose `RollupConfig` is not yet in the public registry but which still needs to run permissionless fault proofs (`cannon-kona` game type). In that case you must build a custom `kona-client` that embeds your chain's configuration, generate the absolute prestate hash from that build, and host the resulting binary at a URL `op-challenger` can fetch. Most chains are in the Superchain Registry and should use the standard prestate; follow [Generating absolute prestate and preimage files](/chain-operators/tutorials/absolute-prestate) instead. Only follow this tutorial if your chain is **not yet** in the registry. Once the chain is added to the public registry, future releases will cover it via the standard prestate and you can stop maintaining a custom build. ## Prerequisites Before starting, ensure you have: * [Docker](https://docs.docker.com/engine/install/) running * [`just`](https://github.com/casey/just) installed * Your chain's `rollup.json`, L2 genesis, and deployment artifacts (typically produced by `op-deployer`) ## How kona-client picks up custom chain configurations `kona-client` reads its embedded chain registry from the [`kona-registry` crate](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/crates/protocol/registry). At build time, the crate's `build.rs` can merge additional chains on top of the canonical Superchain Registry snapshot. The merge is gated by two environment variables: ```bash theme={null} KONA_CUSTOM_CONFIGS=true KONA_CUSTOM_CONFIGS_DIR=/absolute/path/to/your/configs ``` When set, the build script reads two files from `KONA_CUSTOM_CONFIGS_DIR`: * `chainList.json` — light-weight `Chain` entries for your custom chains * `configs.json` — full `ChainConfig` + `RollupConfig` entries grouped under a `Superchain` bucket The full schema and an end-to-end example are documented in the [`kona-registry` README](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/crates/protocol/registry#custom-chain-configurations). The compiled `kona-client` binary embeds the merged registry via `include_str!()`, so the resulting absolute prestate hash differs from the standard one. Any honest challenger participating in your chain's dispute games will need to run this same binary. ## Generating the custom prestate Use the same `kona-node/v` tag that your chain's nodes are running. The native `KONA_CUSTOM_CONFIGS_DIR` support documented below requires **`kona-node/v1.5.2` or later**; on older tags, additional justfile patches are needed. ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git cd optimism git checkout kona-node/v ``` Create a directory for your custom configs: ```bash theme={null} mkdir -p rust/kona/crates/protocol/registry/etc/custom-configs/ ``` Add two files inside it — `chainList.json` (lightweight chain entry) and `configs.json` (full rollup config). Replace every `` with your chain's value. Notes: * **``**: `mainnet` if your L1 is Ethereum mainnet, `sepolia` if your L1 is Sepolia. The bucket groups chains by L1 network, not by governance — your custom-chain status is expressed via `governedByOptimism: false` and `superchainLevel: 0`. * **`faultProofs.status`**: `permissionless` for chains running the `cannon-kona` game type publicly, `permissioned` for chains that only allow whitelisted challengers. ```json theme={null} [ { "name": "", "identifier": "/", "chainId": , "rpc": [], "explorers": [], "superchainLevel": 0, "governedByOptimism": false, "dataAvailabilityType": "eth-da", "parent": { "type": "L2", "chain": "" }, "faultProofs": { "status": "" } } ] ``` ```json theme={null} { "superchains": [ { "name": "", "config": { "name": "", "l1": { "chain_id": , "public_rpc": "", "explorer": "" }, "hardforks": { "canyon_time": 0, "delta_time": 0, "ecotone_time": 0, "fjord_time": 0, "granite_time": 0, "holocene_time": 0, "isthmus_time": 0, "jovian_time": 0 }, "superchain_config_addr": null, "op_contracts_manager_proxy_addr": null }, "chains": [ { "Name": "", "PublicRPC": "", "SequencerRPC": "", "Explorer": "", "SuperchainLevel": 0, "GovernedByOptimism": false, "SuperchainTime": 0, "DataAvailabilityType": "eth-da", "l2_chain_id": , "batch_inbox_address": "", "block_time": 2, "seq_window_size": 3600, "max_sequencer_drift": 600, "GasPayingToken": null, "hardfork_configuration": { "canyon_time": 0, "delta_time": 0, "ecotone_time": 0, "fjord_time": 0, "granite_time": 0, "holocene_time": 0, "isthmus_time": 0, "jovian_time": 0 }, "optimism": { "eip1559Elasticity": 6, "eip1559Denominator": 50, "eip1559DenominatorCanyon": 250 }, "alt_da": null, "genesis": { "l1": { "number": , "hash": "" }, "l2": { "number": 0, "hash": "" }, "l2_time": , "system_config": { "batcherAddr": "", "overhead": "0x0000000000000000000000000000000000000000000000000000000000000000", "scalar": "", "gasLimit": 60000000 } }, "Roles": { "SystemConfigOwner": "", "ProxyAdminOwner": "", "Guardian": "", "Challenger": "", "Proposer": "", "UnsafeBlockSigner": "", "BatchSubmitter": "" }, "Addresses": { "AddressManager": "", "L1CrossDomainMessengerProxy": "", "L1Erc721BridgeProxy": "", "L1StandardBridgeProxy": "", "L2OutputOracleProxy": "0x0000000000000000000000000000000000000000", "OptimismMintableErc20FactoryProxy": "", "OptimismPortalProxy": "", "SystemConfigProxy": "", "ProxyAdmin": "", "AnchorStateRegistryProxy": "", "DelayedWethProxy": "", "DisputeGameFactoryProxy": "", "FaultDisputeGame": "", "PermissionedDisputeGame": "" } } ] } ] } ``` Source the values from your chain's existing artifacts: * `genesis.*`, `block_time`, `seq_window_size`, `max_sequencer_drift`, `batch_inbox_address`, hardfork timestamps → your chain's `rollup.json` * `Addresses.*` → your `op-deployer` state (`opChainDeployments[]`) * `Roles.*` → your `op-deployer` state's per-chain `roles` block Cross-check each L1 contract address onchain (`cast call`) before committing. From the root of the monorepo, point `KONA_CUSTOM_CONFIGS_DIR` at the directory you created in Step 2, then run the canonical build: ```bash theme={null} export KONA_CUSTOM_CONFIGS_DIR="$PWD/rust/kona/crates/protocol/registry/etc/custom-configs/" just reproducible-prestate-kona jq -r .pre rust/kona/prestate-artifacts-cannon/prestate-proof.json ``` The hash printed is your chain's custom kona absolute prestate. The build also writes a hash-named gzipped binary at `rust/kona/prestate-artifacts-cannon/0x.bin.gz` — this is the file `op-challenger` needs to fetch at dispute time. A custom-config build that silently fails to merge your chain produces the *standard* prestate hash — and an `op-challenger` pointed at it will never agree with your games. Always confirm your chain actually made it in: ```bash theme={null} # 1. The build log must list every custom chain that was merged: # cargo:warning=...: inserting new custom chain : [chain-a,chain-b] # (or "merging custom chains : [...]" if the bucket already exists) # # 2. The chain name must appear inside the prestate image itself: gunzip -c rust/kona/prestate-artifacts-cannon/prestate.bin.gz | strings | grep "" ``` Run the `grep` once per chain in your `chainList.json` and confirm at least one match for **every** chain — a build that embeds chain A but drops chain B still produces a valid-looking hash. Zero matches means `KONA_CUSTOM_CONFIGS=true` was not set in the build shell, or `KONA_CUSTOM_CONFIGS_DIR` was a relative path. From a fresh checkout of the same tag with the same custom-configs files in place, repeat the build and confirm the hash is bit-identical. Anyone who wants to participate as an honest challenger on your chain must be able to reproduce this hash from the same inputs. ## Deploying and configuring with the custom prestate Upload `0x.bin.gz` to wherever you serve preimage files for `op-challenger` — typically a GCS bucket or HTTP endpoint. Files must be named by their absolute prestate hash so the challenger can resolve them on demand. On the current (v2.4+) dispute-game contracts the absolute prestate is **not** a constructor argument — it lives in the `DisputeGameFactory`'s per-game-type `gameArgs`, appended to each game via clones-with-immutable-args. So you do **not** deploy a new implementation for a new prestate. Reuse the existing permissionless `FaultDisputeGame` implementation (a fresh op-deployer chain deploys one but leaves it unregistered) and register it for game type 8 with `gameArgs` that carry your prestate. `gameArgs` for a permissionless game is the packed encoding (124 bytes): ``` abi.encodePacked(absolutePrestate, vm, anchorStateRegistry, weth, l2ChainId) ``` Reuse `vm` / `anchorStateRegistry` / `weth` / `l2ChainId` from an existing registered game type (e.g. read `gameArgs(1)` and swap in your prestate), then register from the `DisputeGameFactory` owner: ```solidity theme={null} // GAME_TYPE_CANNON_KONA == 8 DisputeGameFactory.setImplementation(8, faultDisputeGameImpl, gameArgs); DisputeGameFactory.setInitBond(8, initBond); // 0 is fine for a dev/test chain ``` Then make game type 8 the respected type from the Guardian role — `respectedGameType` lives on the `AnchorStateRegistry`, not the `OptimismPortal` (the portal proxies to it): ```solidity theme={null} AnchorStateRegistry.setRespectedGameType(8); ``` See [Migrating to permissionless fault proofs](/chain-operators/tutorials/migrating-permissionless) for the full role/transaction walkthrough. (On older, pre-v2.4 contracts where `absolutePrestate` was a constructor immutable, each prestate did require a fresh implementation deployment instead.) Add the kona-specific env vars to your existing challenger config: ```bash theme={null} OP_CHALLENGER_TRACE_TYPE=cannon-kona,permissioned OP_CHALLENGER_CANNON_KONA_PRESTATES_URL= ``` The challenger appends `/0x.bin.gz` to `*_PRESTATES_URL` to resolve the right binary per dispute. Your existing `OP_CHALLENGER_ROLLUP_CONFIG`, `OP_CHALLENGER_L2_GENESIS`, and `OP_CHALLENGER_GAME_FACTORY_ADDRESS` continue to apply unchanged. ## Next Steps * [Upgrade 19 notice](/notices/archive/upgrade-19) — the `cannon-kona` game type promotion and reference build commands for the standard prestate. * [Generating absolute prestate and preimage files](/chain-operators/tutorials/absolute-prestate): the standard `kona-client` prestate flow for chains in the Superchain Registry. * [Generating an op-program absolute prestate (archived)](/chain-operators/tutorials/archive/op-program-prestate): the legacy `op-program` flow, kept only for resolving in-flight `CANNON` (game type `0`) disputes created before [Upgrade 19](/notices/archive/upgrade-19). `op-program` has reached end-of-support; see [End of Support for op-geth and op-program](/notices/archive/op-geth-deprecation). # Upgrade L1 contracts using op-deployer Source: https://docs.optimism.io/chain-operators/tutorials/l1-contract-upgrades/op-deployer-upgrade Version availability and migration paths for the op-deployer upgrade command, which supports L1 contract upgrades up to op-contracts/v5.0.0. The `op-deployer upgrade` command can be used for upgrades up to `op-contracts/v5.0.0`. It does **not** support upgrading from `op-contracts/v5.0.0` to `op-contracts/v6.0.0`. For upgrades beyond v5.0.0, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide) or interact with the OPCM directly. See the [deprecation notice](/notices/archive/op-deployer-upgrade-deprecation) for details. ## Version availability The `op-deployer upgrade` command supports the following contract upgrade paths (upgrades must be performed in steps): | Upgrade path | op-deployer version | Status | | ------------------------------------------ | ------------------- | --------- | | op-contracts/v1.8.0 to op-contracts/v2.0.0 | v0.2.x | Available | | op-contracts/v2.0.0 to op-contracts/v3.0.0 | v0.3.x | Available | | op-contracts/v3.0.0 to op-contracts/v4.0.0 | v0.4.x | Available | | op-contracts/v4.0.0 to op-contracts/v5.0.0 | v0.5.x | Available | Each minor version of `op-deployer` supported a single release of the governance-approved smart contracts. See the [releases guide](/chain-operators/tools/op-deployer/reference/releases) for more information on versioning. ## Migration For L1 contract upgrades beyond `op-contracts/v5.0.0`, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide). For non-Optimism governed chains, you can interact with the OPCM directly using your own tooling. # Upgrade using superchain-ops Source: https://docs.optimism.io/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide Upgrade your chain's L1 contracts with superchain-ops by creating a task from a template, configuring and simulating it, then executing it or submitting it for review. This guide outlines the process for upgrading Optimism chains using the `superchain-ops` repository. It's intended primarily for OP Stack chains managed by the Security Council, those with the Foundation or Security Council as signers, and/or chains requiring a highly secure process. For chains that don't require the enhanced security of superchain-ops or security council signing, alternative upgrade tooling may be used. Note that the `op-deployer upgrade` command only supports upgrades [up to `op-contracts/v5.0.0`](/notices/archive/op-deployer-upgrade-deprecation). For non-Optimism governed chains, you can use your own tooling to interact with the OPCM directly to upgrade your chain. `superchain-ops` is a highly secure service designed for Optimism chains. It provides a structured and security-focused approach to chain upgrades. The process involves creating tasks that use predefined templates to generate the necessary upgrade transactions. ## Who should use `superchain-ops` `superchain-ops` is primarily intended for: 1. **OP Stack chains managed by the Security Council**: For standard chains managed by the Optimism Security Council, upgrades are typically handled through `superchain-ops`. 2. **Chains with Foundation or Security Council as signers**: If your chain has the Foundation multi-sig or Security Council as signers, your upgrade tasks should go through `superchain-ops`. 3. **Chains requiring a highly secure process**: For chains that prioritize security over automation, `superchain-ops` provides an intentionally manual workflow with thorough verification steps (e.g. EVM state diff inspection). For chains that don't fall into these categories, you'll need to generate appropriate call data for upgrades through other means or develop your own upgrade process for non-OPCM upgrades. ## Understanding templates and tasks `superchain-ops` uses two key concepts: * **Templates**: Define what the upgrade is and contain the code for specific upgrade paths (e.g., [`op-contracts/v1.8.0` to `op-contracts/v2.0.0`](https://github.com/ethereum-optimism/superchain-ops/blob/main/src/improvements/template/OPCMUpgradeV200.sol)). Templates are version-specific and live in the [/src/improvements/template](https://github.com/ethereum-optimism/superchain-ops/tree/main/src/improvements/template) directory. * **Tasks**: Use a template to define a specific upgrade transaction for a chain. Multiple tasks can use the same template. Tasks are organized by network (`eth` or `sep`) in the [/src/improvements/tasks](https://github.com/ethereum-optimism/superchain-ops/tree/main/src/improvements/tasks) directory. ## General upgrade process The following process outlines how to upgrade a chain using `superchain-ops`, using the [`op-contracts/v1.8.0` to `op-contracts/v2.0.0`](https://github.com/ethereum-optimism/superchain-ops/blob/main/src/improvements/template/OPCMUpgradeV200.sol) upgrade as an example. This same pattern applies to other OPCM-based upgrades (like [`op-contracts/v2.0.0` to `op-contracts/v3.0.0`](https://github.com/ethereum-optimism/superchain-ops/blob/main/src/improvements/template/OPCMUpgradeV300.sol)). ### Step 1: Clone the `superchain-ops` repository ```bash theme={null} git clone https://github.com/ethereum-optimism/superchain-ops.git cd superchain-ops/src/improvements ``` ### Step 1a: One-time Install Dependencies Setup Follow the 'Install Dependencies' instructions in the ['Quick Start'](https://github.com/ethereum-optimism/superchain-ops/blob/main/README.md#quick-start) section of the `README.md` file. ### Step 2: Create a new task using the quick start ```bash theme={null} just new task ``` Follow the prompts to select the appropriate template (e.g., `OPCMUpgradeV200` for a `op-contracts/v1.8.0` to `op-contracts/v2.0.0` upgrade) and provide the necessary details. This will create a new task directory containing a `config.toml` and `README` file. The config file will look like this: ```bash theme={null} l2chains = [] # e.g. [{name = "OP Mainnet", chainId = 10}] templateName = "OPCMUpgradeV200" ``` ### Step 3: Configure the task You'll have to add additional properties to your `config.toml` file to fully configure your task. For example, when upgrading from `op-contracts/v1.8.0` to `op-contracts/v2.0.0`, you can look at a previous task for reference: [src/improvements/tasks/eth/002-opcm-upgrade-v200/config.toml](https://github.com/ethereum-optimism/superchain-ops/blob/main/src/improvements/tasks/eth/002-opcm-upgrade-v200/config.toml): This is an example task. You must figure out which values you'll need for your own specific task. Ensure you replace all addresses and other values in the example below. ```bash theme={null} l2chains = [ {name = "Unichain", chainId = 130} ] templateName = "OPCMUpgradeV200" [opcmUpgrades] absolutePrestates = [ {absolutePrestate = "0x039facea52b20c605c05efb0a33560a92de7074218998f75bcdf61e8989cb5d9", chainId = 130}, ] [addresses] OPCM = "0x026b2F158255Beac46c1E7c6b8BbF29A4b6A7B76" StandardValidatorV200 = "0xecabaeaa1d58261f1579232520c5b460ca58a164" ``` ### Step 5: Simulate the task Before executing the upgrade, simulate it to ensure everything is configured correctly: ```bash theme={null} just --dotenv-path $(pwd)/.env simulate [child-safe-name-depth-1] [child-safe-name-depth-2] # Both [child-safe-name-depth-1] and [child-safe-name-depth-2] are optional. You'll only need to specify # [child-safe-name-depth-2] if it's a nested safe and [child-safe-name-depth-2] if it has multiple levels of nesting. # Omit both arguments if it's a single safe. ``` This will run through the upgrade process without actually executing the transaction. For more information on the simulate command, please reference the [README](https://github.com/ethereum-optimism/superchain-ops/blob/main/README.md#quick-start). ### Step 6: Execute or submit for review For OP Stack chains managed by the Security Council, submit a pull request to have your task reviewed. If your chain is not managed by the Security Council, execute the transaction yourself. # Upgrading Smart Contracts from v1.3.0 to v1.8.0 Source: https://docs.optimism.io/chain-operators/tutorials/l1-contract-upgrades/upgrade-op-contracts-1-3-1-8 Upgrade your OP Stack chain's L1 contracts from op-contracts/v1.3.0 to v1.8.0, moving from the L2 Output Oracle to the permissioned Fault Proof System. This guide provides specific instructions for upgrading the OP Stack's Layer 1 contracts from `op-contracts/v1.3.0` to `op-contracts/v1.8.0`. This upgrade includes important changes to the system configuration and introduces the Fault Proof System. ## Overview of the Holocene upgrade The Holocene upgrade is a protocol upgrade. Learn more about it in the [Holocene notice page](https://docs.optimism.io/notices/holocene-changes). This guide shows you how to take your OP Stack chain from the L2 Output Oracle System to a permissioned Fault Proof System contract version associated with the Holocene upgrade. After upgrading to OP Stack contracts v1.8.0 and enabling permissioned fault proofs, all pending (unfinalized) withdrawal proofs created on L1 are invalidated. This means that withdrawals must be manually reproven by users after the upgrade; the process is not automatic. ### Formatting config files You need your chain's `deployments.json` and `deploy-config.json` Ensure both files are correctly formatted, using the exact field names shown in the below examples, with **ALL** values - particularly the relevant ones - updated for **your specific chain**: `deployments.json`: ```json theme={null} { "AddressManager": "0xEF8115F2733fb2033a7c756402Fc1deaa56550Ef", "L2OutputOracleProxy": "0x9E6204F750cD866b299594e2aC9eA824E2e5f95c", "OptimismMintableERC20FactoryProxy": "0xc52BC7344e24e39dF1bf026fe05C4e6E23CfBcFf", "L1StandardBridgeProxy": "0x3e2Ea9B92B7E48A52296fD261dc26fd995284631", "ProxyAdmin": "0xD4ef175B9e72cAEe9f1fe7660a6Ec19009903b49", "L1CrossDomainMessengerProxy": "0xdC40a14d9abd6F410226f1E6de71aE03441ca506", "L1ERC721BridgeProxy": "0x83A4521A3573Ca87f3a971B169C5A0E1d34481c3", "OptimismPortalProxy": "0x1a0ad011913A150f69f6A19DF447A0CfD9551054", "SystemConfigProxy": "0xA3cAB0126d5F504B071b81a3e8A2BBBF17930d86" } ``` `deploy-config.json`: ```json theme={null} { "l1StartingBlockTag": "0x10aa183", "l1ChainID": 1, "l2ChainID": 7777777, "l2BlockTime": 2, "finalizationPeriodSeconds": 604800, "controller": "0xEe729F57F0111FD0F660867d0F522f983202a5aF", "baseFeeVaultRecipient": "0xe900b3Edc1BA0430CFa9a204A1027B90825ac951", "l1FeeVaultRecipient": "0xe900b3Edc1BA0430CFa9a204A1027B90825ac951", "sequencerFeeVaultRecipient": "0xe900b3Edc1BA0430CFa9a204A1027B90825ac951", "l2GenesisBlockBaseFeePerGas": "0x3b9aca00", "governanceTokenOwner": "0xC72aE5c7cc9a332699305E29F68Be66c73b60542", "governanceTokenSymbol": "OP", "governanceTokenName": "Optimism", "maxSequencerDrift": 600, "sequencerWindowSize": 3600, "channelTimeout": 300, "p2pSequencerAddress": "0x3Dc8Dfd0709C835cAd15a6A27e089FF4cF4C9228", "optimismL2FeeRecipient": "0x63AA492609175d1824dD668BDadF0042E74b0fC8", "batchInboxAddress": "0x6F54Ca6F6EdE96662024Ffd61BFd18f3f4e34DFf", "batchSenderAddress": "0x625726c858dBF78c0125436C943Bf4b4bE9d9033", "l2GenesisRegolithTimeOffset": "0x0", "l2OutputOracleSubmissionInterval": 180, "l2OutputOracleStartingTimestamp": -1, "l2OutputOracleStartingBlockNumber": "0x0", "l2GenesisBlockGasLimit": "0x1c9c380", "fundDevAccounts": false, "gasPriceOracleOverhead": 188, "gasPriceOracleScalar": 684000, "eip1559Denominator": 50, "eip1559Elasticity": 6, "optimismBaseFeeRecipient": "0xea4591A6e5a31CF0b822A4f563163CeeBeEe4eb1", "optimismL1FeeRecipient": "0xdD7aCF916c3E3Fb959CA3bB29beFffcAD2e90be6", "l2CrossDomainMessengerOwner": "0xA53EF9bBec25fdA4b6Da7EF5617565794369A2A5", "gasPriceOracleOwner": "0x9c3651E0B3CE47A0b17d775077E3d9B712582be0", - RELEVANT VALUES "systemConfigOwner": "0xC72aE5c7cc9a332699305E29F68Be66c73b60542", "finalSystemOwner": "0xC72aE5c7cc9a332699305E29F68Be66c73b60542", "superchainConfigGuardian": "0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A", "portalGuardian": "0xC72aE5c7cc9a332699305E29F68Be66c73b60542", "l2OutputOracleProposer": "0x48247032092e7b0ecf5dEF611ad89eaf3fC888Dd", "l2OutputOracleOwner": "0xDA1F62857EA7f10444725c6c435235243D623540", "proxyAdmin": "0x027860cA56cF779371461C14c3a483c94e1aA8a0", "proxyAdminOwner": "0xb0cCdbD6fe09D2199171BE19450aF249250518A0", "l2OutputOracleChallenger": "0xcA4571b1ecBeC86Ea2E660d242c1c29FcB55Dc72", - add the below default values, if you expect different values for your chain reach out to OP Labs support for clarification before proceeding "useFaultProofs": true, "faultGameMaxDepth": 73, "faultGameSplitDepth": 30, "faultGameWithdrawalDelay": 604800, "faultGameMaxClockDuration": 302400, "faultGameClockExtension": 10800, - You can update this to the latest absolute prestate hash in the superchain-registry; however, the permissioned Fault Proof System doesn't use this. This comes into play when you upgrade your chain to the permissionless Fault Proof System. "faultGameAbsolutePrestate": "0x03925193e3e89f87835bbdf3a813f60b2aa818a36bbe71cd5d8fd7e79f52bafe", - add the below default values, if you expect different values for your chain, reach out to OP Labs support for clarification before proceeding "faultGameGenesisBlock": 0, "faultGameGenesisOutputRoot": "0xdead000000000000000000000000000000000000000000000000000000000000", "respectedGameType": 1, "preimageOracleMinProposalSize": 126000, "preimageOracleChallengePeriod": 86400, "proofMaturityDelaySeconds": 604800, "disputeGameFinalityDelaySeconds": 302400, "enableGovernance": false, "systemConfigStartBlock": 0, "requiredProtocolVersion": "0x0000000000000000000000000000000000000003000000010000000000000000", "recommendedProtocolVersion": "0x0000000000000000000000000000000000000003000000010000000000000000", - make sure to add the below if not present already, these values won't matter but the script needs them to be present in the config "sequencerFeeVaultWithdrawalNetwork": 0, "baseFeeVaultWithdrawalNetwork": 0, "l1FeeVaultWithdrawalNetwork": 0, "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000" } ``` Make sure that important addresses (like the `ProxyAdmin`, `ProxyAdminOwner`, all L1 addresses, `L2OO`) are actually up to date by cross checking the superchain-registry and on-chain (you can do this easily with [`op-fetcher`](https://github.com/ethereum-optimism/optimism/tree/develop/op-fetcher), especially for the `deployments.json`. ## Step-by-step upgrade process ### 1. Create your working directory Create a working directory: ```shell theme={null} mkdir upgrade-dir cd upgrade-dir ``` And then create an outputs directory: ```shell theme={null} mkdir outputs ``` ### 2. Copy config files Copy your `deployments.json` and `deploy-config.json` into the working directory ### 3. Configure and deploy environment Create and update an `.env` file with the required information: ```json theme={null} ############################################## # ↓ Required ↓ # ############################################## # Can be "mainnet" or "sepolia" NETWORK= # Etherscan API key used to verify contract bytecode ETHERSCAN_API_KEY= # RPC URL for the L1 network that matches $NETWORK ETH_RPC_URL= # Private key used to deploy the new contracts for this upgrade PRIVATE_KEY= # Base fee scalar for the SystemConfig BASE_FEE_SCALAR= # Blob base fee scalar for the SystemConfig BLOB_BASE_FEE_SCALAR= # Check if required files and folders exist if [ ! -f "./deploy_config.json" ]; then echo "Error: deploy_config.json not found" fi if [ ! -f "./deployments.json" ]; then echo "Error: deployments.json not found" fi if [ ! -d "./outputs" ]; then echo "Error: outputs folder not found" fi ``` ### 4. Run the deployment process Run the deployment process with the following command: ```docker theme={null} docker run -t --env-file .env -v ./deploy_config.json:/deploy_config.json -v ./deployments.json:/deployments.json -v ./outputs:/outputs kfoplabs/upgrade-v1.3.0-v1.8.0-permissioned /deploy_config.json /deployments.json ``` The source code for the `kfoplabs/upgrade-v1.3.0-v1.8.0-permissioned` image is available in the [`perm/op-contracts/v1.8.0` branch of the Optimism monorepo](https://github.com/ethereum-optimism/optimism/tree/perm/op-contracts/v1.8.0). If you need to fork or customize the upgrade script (e.g. to support L3s), start from that branch. ### 5. Verify outputs The deployment should output four files: * `deploy.log` is a log of the deployment process * `deployments.json` includes the newly deployed contract addresses * `bundle.json` is the safe transaction bundle * `transactions.json` is the summary of the executed deployment transactions * `standard-addresses.json` is the addresses of `SystemConfigImpl`, `OptimismPortal2Impl`, `L1CrossDomainMessengerImpl`, `L1StandardBridgeImpl`, `L1ERC721BridgeImpl`, and `OptimismMintableERC20FactoryImpl` * `validation.txt` is used for Tenderly state diff validation. Some info needed for the superchain-ops task might be missing from this file, and will instead be generated during the Tenderly simulation. ### 6. Verify outputs Now you have the calldata that can be executed onchain to perform the L1 contract upgrade. You should simulate this upgrade and make sure the changes are expected. You can reference the validation files of previously executed upgrade tasks in the [superchain-ops repo](https://github.com/ethereum-optimism/superchain-ops/blob/main/tasks/eth/022-holocene-fp-upgrade/NestedSignFromJson.s.sol) to see what the expected changes are. Once you're confident the state changes are expected, you can sign and execute the upgrade. ## Additional Resources * [superchain-ops Repository](https://github.com/ethereum-optimism/superchain-ops) * [Optimism Monorepo](https://github.com/ethereum-optimism/optimism) * [Upgrade script source code (`perm/op-contracts/v1.8.0` branch)](https://github.com/ethereum-optimism/optimism/tree/perm/op-contracts/v1.8.0) # Merging Two Chains Into a Shared Dispute Game Source: https://docs.optimism.io/chain-operators/tutorials/merge-shared-dispute-game Merge two pre-interop OP Stack chains into a shared DisputeGameFactory and AnchorStateRegistry with opcm.migrate, then cut over op-proposer, op-challenger, and op-dispute-mon to the shared factory. # Merging Two Chains Into a Shared Dispute Game This guide depends on the interop feature, which is still in development. Do not follow it on production chains. This runbook walks you through merging two existing OP Stack chains into a shared dispute game by calling `OPContractsManagerMigrator.migrate` (`opcm.migrate`). After migration, both chains share a newly deployed `DisputeGameFactory`, `AnchorStateRegistry`, and `ETHLockbox`. New proposals are super-root claims defended on the shared factory; the per-chain dispute game factories are emptied of implementations and exist only to let still-in-flight games resolve so their bonds can be reclaimed. By the end you will have one `op-proposer` proposing super-root claims to the shared factory against an `op-supernode` that derives both chains, one `op-challenger` defending super-root games on the shared factory, one `op-dispute-mon` watching it, and per-chain `op-challenger` and `op-dispute-mon` "drain" instances — each using that shared op-supernode's `//` endpoint — winding down the retired games on the old per-chain factories. `opcm.migrate` is a one-way operation that invalidates every withdrawal proof submitted but not finalized on either chain. Affected users must re-prove against a new super-root game after migration. Announce the migration window to users at least seven days in advance—long enough for a withdrawal proven just before the announcement to mature past `PROOF_MATURITY_DELAY_SECONDS` and finalize. If you instead want to swap a single chain's proof method from output roots to super roots without merging chains, follow [Upgrading a Chain From Output Roots to Super Roots](/chain-operators/tutorials/upgrade-chain-to-super-roots). This runbook is for two chains that are merging into a shared interop set. ## Before You Begin This runbook assumes: * Exactly two chains, referred to below as `chainA` and `chainB`, are being merged. * Neither chain has activated interop yet. * Both chains run permissionless fault proofs with `SUPER_CANNON_KONA` (game type `9`) as the respected game type today. * The per-chain `op-proposer`, `op-challenger`, and `op-dispute-mon` instances stood up by the [single-chain super-roots upgrade](/chain-operators/tutorials/upgrade-chain-to-super-roots) are running for both chains. The per-chain challengers and monitors keep running through migration cutover and the subsequent drain window. * A separate `op-supernode` instance is in sync and derives **exactly `chainA` and `chainB`** (and no other chains) in the same process. This is the supernode the new shared `op-proposer`, `op-challenger`, and `op-dispute-mon` point at after migration; it must not double as a multi-chain supernode for any other chain or interop cluster. * Both chains have already been upgraded to a release that exposes `OPContractsManagerMigrator.migrate` and have `Features.INTEROP` and `Features.ETH_LOCKBOX` enabled on their `SystemConfig`. These features are turned on automatically by `OPContractsManagerV2.upgrade()` when the OPCM container has the `OPTIMISM_PORTAL_INTEROP` dev feature set; that pre-upgrade is a prerequisite for this runbook. ### Install Required Tooling The versions below are the ones the optimism repo's `mise.toml` pins; older versions of `cast` in particular may not parse the function-selector syntax used in this runbook. | Tool | Minimum version | | --------------------------- | --------------- | | `foundry` (`cast`, `forge`) | `1.2.3` | | `just` | `1.46.0` | | `jq` | `1.7.1` | | `go` | `1.26.5` | | `curl` | any | ### Gather the Required Inputs Collect everything below before you start. Replace `` and `` placeholders with the actual values for each chain. Anywhere this runbook says `` it means a value you must capture. **Per-chain identity, addresses, and roles.** For each chain, open the entry under `superchain/configs//.toml` in `superchain-registry` and read `chain_id`, `addresses.SystemConfigProxy`, and `addresses.L1StandardBridgeProxy`. Pass those two proxies to [`op-fetcher`](https://github.com/ethereum-optimism/optimism/tree/develop/op-fetcher) to resolve the rest in a single L1 call, writing the JSON to a file you can reference later: ```bash theme={null} op-fetcher fetch \ --l1-rpc-url $L1_RPC \ --system-config \ --l1-standard-bridge \ --output-file .json ``` The portal-derived lookups return the chain's current `DisputeGameFactory`, `AnchorStateRegistry`, and `ETHLockbox` while migration has not yet run; after migration, the same selectors return the new shared addresses, so capture both chains' values now. Capture the following fields from each chain's JSON output: | Item | Source | | -------------------------------------------------------- | -------------------------------------------------------------- | | L2 chain ID | `chain_id` in the chain's registry TOML | | `SystemConfig` proxy | `addresses.SystemConfigProxy` in the chain's registry TOML | | `L1StandardBridge` proxy | `addresses.L1StandardBridgeProxy` in the chain's registry TOML | | `OptimismPortal2` proxy | `addresses.OptimismPortalProxy` in `.json` | | Existing `AnchorStateRegistry` proxy (``) | `addresses.AnchorStateRegistryProxy` in `.json` | | Existing `DisputeGameFactory` proxy (``) | `addresses.DisputeGameFactoryProxy` in `.json` | | Existing `ETHLockbox` proxy | `addresses.EthLockboxProxy` in `.json` | | `SuperchainConfig` proxy | `addresses.SuperchainConfigProxy` in `.json` | | `ProxyAdmin` owner Safe | `roles.OpChainProxyAdminOwner` in `.json` | `migrate` reads each chain's `DelayedWETH` directly from `SystemConfig.delayedWETH()` at execution time, so there is nothing to capture for it here. **Init bonds.** The migration registers two super game types on the new shared factory. `SUPER_PERMISSIONED` (game type `5`) is bondless and must use an `initBond` of `0`. `SUPER_CANNON_KONA` (game type `9`) uses `0.08 ether` (`80000000000000000` wei). **Release artifacts and infrastructure.** | Item | Source | | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `OPCM` address for the migrate-feature container | The same OPCM the chains ran for the prerequisite `OPCMv2.upgrade()`. The container has `OPTIMISM_PORTAL_INTEROP` set in `devFeatureBitmap`, which is what enables both `Features.INTEROP` and `Features.ETH_LOCKBOX` on each `SystemConfig`. | | `SUPER_CANNON_KONA` absolute prestate hash | `validation/standard/standard-prestates.toml` in `superchain-registry`. Use the entry with `type="interop"` for the OPCM release version. | | Prestate artifact URL | The `cannon-kona-prestates-url` server, with the kona-interop prestate uploaded ahead of the migration. | | Shared `op-supernode` RPC URL | Your infrastructure team. The instance must derive **exactly `chainA` and `chainB`** (and no other chains). The shared `op-proposer`, `op-challenger`, and `op-dispute-mon` for the merged factory all point at this same instance. The per-chain services will be pointed to chain-specific endpoints under this URL. | | Privileged `proposer` for `SUPER_PERMISSIONED` | The address authorized to post proposals to the permissioned super game. `op-proposer` is configured to sign with this key. | ### Verify the Preconditions Run every check below. Each one corresponds to an invariant the migrator enforces; resolve any failure before proceeding. * **Confirm the same `ProxyAdmin` owner across both chains.** `migrate` reverts with `OPContractsManagerMigrator_ProxyAdminOwnerMismatch` otherwise. Each chain's `ProxyAdmin` proxy may differ as long as the owner Safe is identical on both. ```bash theme={null} diff <(jq -r '.roles.OpChainProxyAdminOwner' .json) <(jq -r '.roles.OpChainProxyAdminOwner' .json) # Expect: no output (identical). ``` * **Confirm the same `SuperchainConfig` across both chains.** `migrate` reverts with `OPContractsManagerMigrator_SuperchainConfigMismatch` otherwise. ```bash theme={null} diff <(jq -r '.addresses.SuperchainConfigProxy' .json) <(jq -r '.addresses.SuperchainConfigProxy' .json) # Expect: no output (identical). ``` * **Confirm both chains have `Features.INTEROP` and `Features.ETH_LOCKBOX` enabled.** `_migratePortal` reverts with `OPContractsManagerMigrator_InteropFeatureNotEnabled` or `OPContractsManagerMigrator_EthLockboxFeatureNotEnabled` if either is missing. These flip automatically during the prerequisite `OPCMv2.upgrade()` against an `OPTIMISM_PORTAL_INTEROP`-enabled OPCM container; if any of the four checks below returns `false`, run that prerequisite upgrade first. `Features` constants are short-string `bytes32` values, so feed them through `cast format-bytes32-string`. ```bash theme={null} for SC in ; do for F in INTEROP ETH_LOCKBOX; do echo "$SC $F = $(cast call $SC 'isFeatureEnabled(bytes32)(bool)' "$(cast format-bytes32-string $F)" --rpc-url $L1_RPC)" done done # Expect: every line ends in true. ``` * **Confirm neither chain runs in Custom Gas Token mode.** `_migratePortal` reverts with `OPContractsManagerMigrator_CustomGasTokenNotSupported` for any CGT chain. ```bash theme={null} cast call 'isCustomGasToken()(bool)' --rpc-url $L1_RPC cast call 'isCustomGasToken()(bool)' --rpc-url $L1_RPC # Expect: both false. ``` * **Confirm the current respected game type on both chains is `SUPER_CANNON_KONA` (`9`).** ```bash theme={null} cast call 'respectedGameType()(uint32)' --rpc-url $L1_RPC cast call 'respectedGameType()(uint32)' --rpc-url $L1_RPC # Expect: 9 for both. ``` * **Confirm the shared supernode derives exactly the two merging chains.** Verify with your infrastructure team that the instance behind `$SUPERNODE_RPC` has `chainA` and `chainB` in its dependency set and **no** other chains. A supernode that also tracks an unrelated chain (or an interop cluster that includes one) computes super roots over that broader set, and those roots will not match what the shared `SUPER_CANNON_KONA` and `SUPER_PERMISSIONED` games verify. * **Confirm the shared supernode is in sync.** It must report a finalized L2 head within both chains' expected finality windows: ```bash theme={null} cast rpc supernode_syncStatus --rpc-url $SUPERNODE_RPC | jq -r '.finalized_timestamp' ``` If the supernode is materially behind either chain, postpone the migration. * **Confirm the prestate server serves the `SUPER_CANNON_KONA` prestate.** ```bash theme={null} curl -fI "$PRESTATE_URL/$SUPER_CANNON_KONA_PRESTATE.bin.gz" ``` * **Note the chain B `DelayedWETH` divergence.** `migrate` reuses chain A's `DelayedWETH` for the new shared super games and does not touch chain B's. After migration, chain B's `SystemConfig.delayedWETH()` still references chain B's old `DelayedWETH`, which is no longer attached to any super game. Future `OPCMv2.upgrade()` calls against chain B that read `SystemConfig.delayedWETH()` will therefore reference a different contract than the shared games use. Track this in your operational runbook so future upgrades do not surprise you. The bonds posted by chain B's still-in-flight pre-migration games continue to claim out of chain B's old `DelayedWETH`, so the divergence does not block the drain described in [Drain Pre-Migration Games and Reclaim Bonds](#drain-pre-migration-games-and-reclaim-bonds). ## Stage the Off-Chain Configuration Apply these changes before you submit the on-chain migration. The pre-migration `op-challenger` and `op-dispute-mon` instances per chain must keep running to defend and watch in-flight games on the per-chain factories until those games resolve. Add a third instance of each component for the shared factory. Stop both per-chain `op-proposer` instances at cutover time, in [Execute the Migration](#execute-the-migration). ### Point Per-Chain Services at the Shared op-supernode Before migration, point every existing per-chain service at its chain's RPC namespace on the shared op-supernode: | Service flag | chainA value | chainB value | | -------------------------------- | --------------------------------- | --------------------------------- | | `op-proposer --superroot-rpcs` | `$SUPERNODE_RPC/$CHAIN_A_CHAINID` | `$SUPERNODE_RPC/$CHAIN_B_CHAINID` | | `op-challenger --supernode-rpc` | `$SUPERNODE_RPC/$CHAIN_A_CHAINID` | `$SUPERNODE_RPC/$CHAIN_B_CHAINID` | | `op-dispute-mon --supernode-rpc` | `$SUPERNODE_RPC/$CHAIN_A_CHAINID` | `$SUPERNODE_RPC/$CHAIN_B_CHAINID` | Do not point these per-chain instances at `$SUPERNODE_RPC` without the chain ID suffix; the root endpoint returns a two-chain super root. Restart each service and confirm it connects successfully before continuing. This removes the operational dependency on separate single-chain op-node or op-supernode processes before interop activation. ### Stand Up a Shared op-challenger A single `op-challenger` process can only watch one `DisputeGameFactory`, so the existing per-chain instances cannot also cover the new shared factory. Run a third `op-challenger` instance dedicated to the shared factory in addition to the existing per-chain instances. Configure the new shared instance with the flags below. | Flag (env var) | Value | | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--game-factory-address` (`OP_CHALLENGER_GAME_FACTORY_ADDRESS`) | The new shared `` (capture from chain A's portal after [Execute the Migration](#execute-the-migration)) | | `--superroot-rpc` (`OP_CHALLENGER_SUPERNODE_RPC`) | `$SUPERNODE_RPC` | | `--l2-eth-rpc` (`OP_CHALLENGER_L2_ETH_RPC`) | `,` (comma-separated) | | `--game-types` (`OP_CHALLENGER_GAME_TYPES`) | `super-cannon-kona`. Do not add `super-permissioned`; the simplified `SUPER_PERMISSIONED` game does not require `op-challenger` to post claims. `op-challenger` is still required by permissioned only networks and will automatically update the `AnchorStateRegistry` as games are finalized. | | `--network` (`OP_CHALLENGER_NETWORK`) | `,` (the registry chain names; the challenger loads the depset from `superchain-registry` the same way `op-supernode` does) | | `--cannon-kona-prestates-url` (`OP_CHALLENGER_CANNON_KONA_PRESTATES_URL`) | The prestate server URL validated in the preconditions | If either chain is not in `superchain-registry`, omit `--network` and instead pass each chain's rollup config and L2 genesis as comma-separated paths via `--rollup-config` (`OP_CHALLENGER_ROLLUP_CONFIG`) and `--l2-genesis` (`OP_CHALLENGER_L2_GENESIS`), plus the shared depset via `--depset-config` (`OP_CHALLENGER_DEPSET_CONFIG`). The shared instance's `--game-factory-address` is the new shared factory, which only exists once `migrate` has been broadcast. Stage the deployment now with every other flag set; the address is filled in and the process is started in [Start the Shared op-challenger and op-dispute-mon](#start-the-shared-op-challenger-and-op-dispute-mon) after the migration is verified on-chain. Keep the per-chain `op-challenger` instances running with the namespaced RPC configuration for the duration of the drain window. ### Stand Up a Shared op-dispute-mon `op-dispute-mon` is also single-factory per process. Run a third instance pointed at the new shared factory in addition to the two per-chain instances. | Flag (env var) | Value | | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `--game-factory-address` (`OP_DISPUTE_MON_GAME_FACTORY_ADDRESS`) | The new shared `` | | `--superroot-rpc` (`OP_DISPUTE_MON_SUPERNODE_RPC`) | `$SUPERNODE_RPC` or a comma-separated list of high-availability root endpoints for the same dependency set | | `--l1-eth-rpc` (`OP_DISPUTE_MON_L1_ETH_RPC`) | unchanged | As with the shared `op-challenger`, stage the deployment now with every flag except `--game-factory-address`; the address is filled in and the process is started in [Start the Shared op-challenger and op-dispute-mon](#start-the-shared-op-challenger-and-op-dispute-mon) after the migration is verified on-chain. Keep both per-chain `op-dispute-mon` instances running with the namespaced RPC configuration so they continue to track in-flight pre-migration games to resolution. ### Leave Other op-proposer Settings Unchanged for Now After switching the per-chain `op-proposer` RPC endpoints above, leave their other settings unchanged until [Execute the Migration](#execute-the-migration). Stop both per-chain proposers at cutover and replace them with a single shared one; see [Cut Over to a Single Shared op-proposer](#cut-over-to-a-single-shared-op-proposer). ## Generate the Starting Anchor Super Root The new shared `AnchorStateRegistry` is initialized with a starting anchor super root. Compute the value from the supernode using `superroot_atTimestamp`. Pick the supernode's current finalized timestamp (or any recent finalized timestamp), then ask the supernode for the super root at that timestamp: ```bash theme={null} # .finalized_timestamp is a JSON number (decimal unix seconds). TS=$(cast rpc supernode_syncStatus --rpc-url $SUPERNODE_RPC | jq -r '.finalized_timestamp') # superroot_atTimestamp expects a hex-encoded JSON string (hexutil.Uint64); cast 2h handles the conversion. cast rpc superroot_atTimestamp "$(cast 2h $TS)" --rpc-url $SUPERNODE_RPC | jq -r '.data.super_root' echo "timestamp=$TS" ``` Capture two values: * `super_root` (a `bytes32` hash from `.data.super_root`)—passed as `Proposal.root` in `startingAnchorRoot`. * `timestamp` (the uint64 you passed in)—passed as `Proposal.l2SequenceNumber`. For super games this field is the timestamp itself, not a block number. ## Build the superchain-ops Task Author a new task directory under `superchain-ops/src/tasks///` using the `OPCMMigrateInterop` template, which wraps `OPContractsManagerMigrator.migrate(MigrateInput)` and runs `OPContractsManagerMigrationValidator` over the resulting state. ### Configure config.toml ```toml theme={null} l2chains = [ {name = "t stat", chainId = }, {name = "", chainId = }, ] templateName = "OPCMMigrateInterop" [addresses] OPCM = "0x" # One stanza per chain, both required. [[migrateChains]] chainId = systemConfigProxy = "0x" [[migrateChains]] chainId = systemConfigProxy = "0x" # Starting anchor for the new shared AnchorStateRegistry, computed in the previous step. [startingAnchorRoot] root = "0x" l2SequenceNumber = # 9 = SUPER_CANNON_KONA. Required because both chains run permissionless fault proofs today. startingRespectedGameType = 9 # Both super game types must be registered. The migration validator requires it. # The template assembles the on-chain DisputeGameConfig.gameArgs bytes from these # fields: abi.encode(absolutePrestate) for game type 9, and # abi.encode(proposer) for game type 5. [[disputeGameConfigs]] gameType = 9 # SUPER_CANNON_KONA enabled = true initBond = 80000000000000000 # match the value gathered in the inputs absolutePrestate = "0x" [[disputeGameConfigs]] gameType = 5 # SUPER_PERMISSIONED enabled = true initBond = 0 # SUPER_PERMISSIONED does not charge init bonds proposer = "0x" expectedValidationErrors = "" # fill in after the dry run if any structurally expected codes appear ``` ### Capture expectedValidationErrors Run the task in simulation mode against an L1 fork from inside the task directory: ```bash theme={null} cd superchain-ops/src/tasks// just simulate ``` The validator behind `OPContractsManagerMigrationValidator` returns a comma-separated string of error codes when something is structurally wrong. The default expectation is no errors—`expectedValidationErrors = ""` and a clean simulation. The codes you may see fall into the families below. Resolve every code rather than copy-pasting it into `expectedValidationErrors`; a code added to that field must have an inline TOML comment explaining why it is structurally expected for this migration. | Code | Meaning | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `MIG-DGF-10` | `SUPER_PERMISSIONED` is not registered on the shared factory. | | `MIG-DGF-20` | `SUPER_CANNON_KONA` is not registered on the shared factory. | | `MIG-DGF-30` | `CANNON` is still registered on the shared factory. | | `MIG-DGF-40` | `PERMISSIONED_CANNON` is still registered on the shared factory. | | `MIG-DGF-50` | `CANNON_KONA` is still registered on the shared factory. | | `MIG-SDGF-10` to `-40` | Shared factory version, proxy implementation pointer, owner, or `ProxyAdmin` does not match the expected configuration. | | `MIG-SASR-RGT` | Shared `AnchorStateRegistry.respectedGameType()` is not a super game type. | | `MIG-SLOCKBOX-10` to `-30` | Shared lockbox version, proxy implementation pointer, or `ProxyAdmin` mismatch. | | `MIG-CHAIN-EMPTY` | The validator received an empty chain list. | | `MIG-LOCKBOX-MISSING` | Chain A's portal does not point at the shared lockbox. | | `MIG-CHAIN-{i}-10` | Chain `i`'s portal does not reference the shared `AnchorStateRegistry`. | | `MIG-CHAIN-{i}-20` | Chain `i`'s per-chain factory still has `CANNON` registered. | | `MIG-CHAIN-{i}-30` | Chain `i`'s per-chain factory still has `PERMISSIONED_CANNON` registered. | | `MIG-CHAIN-{i}-40` | Chain `i`'s per-chain factory still has `CANNON_KONA` registered. | | `MIG-CHAIN-{i}-60` | Chain `i`'s per-chain factory still has `SUPER_PERMISSIONED` registered. | | `MIG-CHAIN-{i}-70` | Chain `i`'s per-chain factory still has `SUPER_CANNON_KONA` registered. | | `MIG-CHAIN-{i}-80` | Shared lockbox does not list chain `i`'s portal as authorized. | | `MIG-CHAIN-{i}-90` | Chain `i`'s portal `ethLockbox` does not equal the shared lockbox. | | `MIG-CHAIN-{i}-100` | Chain `i`'s `SystemConfig` does not have `Features.INTEROP` enabled. | | `MIG-CHAIN-{i}-110` | Chain `i`'s `SystemConfig` does not have `Features.ETH_LOCKBOX` enabled. | | `MIG-SPDG-*` or `MIG-SCKDG-*` | Super game drill-down. The first prefix covers `SUPER_PERMISSIONED` and the second covers `SUPER_CANNON_KONA`. `MIG-SPDG-*` subcodes cover the simplified permissioned game's args, proposer, and `AnchorStateRegistry`; `MIG-SCKDG-*` covers the fault-proof game checks. | ## Execute the Migration Verify that the user announcement has gone out and at least seven days have elapsed since the announcement before broadcasting. Withdrawals proven against either chain's old games will not finalize against the new shared registry; users must re-prove or finalize ahead of cutover. 1. Stop both per-chain `op-proposer` processes. Once the migration broadcasts, the per-chain factories no longer have `SUPER_CANNON_KONA` registered, so `DisputeGameFactory.create` reverts. Stopping the proposers first prevents wasted gas. 2. Leave both per-chain `op-challenger` and `op-dispute-mon` instances running. They continue to defend and observe in-flight pre-migration games on the per-chain factories. 3. Sign and broadcast the task using your team's standard `superchain-ops` signing workflow. 4. Wait for the L1 transaction to confirm. The on-chain effect: * `OPCM` deploys and initializes new `ETHLockbox`, `DisputeGameFactory`, and `AnchorStateRegistry` proxies. The new `AnchorStateRegistry` binds to the new factory and sets `retirementTimestamp` to `block.timestamp` at initialization. * `OPCM` calls `OptimismPortal2.migrateToSharedDisputeGame` on each chain to repoint the portal at the new lockbox and the new `AnchorStateRegistry`. It also authorizes each chain's existing portal on the shared lockbox, authorizes each chain's existing lockbox to forward liquidity, and migrates that liquidity into the shared lockbox. * `OPCM` zeroes every implementation pointer on each chain's existing per-chain `DisputeGameFactory`. Already-deployed game proxies on those factories are unaffected and continue to resolve. Capture the new shared addresses by re-running op-fetcher against each chain. After migration, `optimismPortal().anchorStateRegistry()`, `disputeGameFactory()`, and `ethLockbox()` all return the new shared proxies, so the same op-fetcher inputs you used in [Gather the Required Inputs](#gather-the-required-inputs) now resolve the post-migration addresses. Write the post-migration output to new files (do not overwrite the pre-migration ones — you still need them to reference the per-chain `` and `` during the drain). ```bash theme={null} op-fetcher fetch \ --l1-rpc-url $L1_RPC \ --system-config \ --l1-standard-bridge \ --output-file -postmigrate.json op-fetcher fetch \ --l1-rpc-url $L1_RPC \ --system-config \ --l1-standard-bridge \ --output-file -postmigrate.json ``` Capture the shared addresses from chain A's post-migration output: ```bash theme={null} SHARED_ASR=$(jq -r '.addresses.AnchorStateRegistryProxy' -postmigrate.json) SHARED_DGF=$(jq -r '.addresses.DisputeGameFactoryProxy' -postmigrate.json) SHARED_LOCKBOX=$(jq -r '.addresses.EthLockboxProxy' -postmigrate.json) ``` Confirm chain B's portal resolves to the same shared proxies: ```bash theme={null} diff <(jq -r '.addresses.AnchorStateRegistryProxy, .addresses.DisputeGameFactoryProxy, .addresses.EthLockboxProxy' -postmigrate.json) \ <(jq -r '.addresses.AnchorStateRegistryProxy, .addresses.DisputeGameFactoryProxy, .addresses.EthLockboxProxy' -postmigrate.json) # Expect: no output (identical). ``` ## Verify the Migration On-Chain Run every check below before you start the new `op-proposer`. If any check fails, stop and escalate via your standard incident-response channel; recovery from a half-cut state with a misbehaving proposer is materially harder than recovery from one that is paused. ### Verify the Shared Registry and Factory ```bash theme={null} # Respected game type on the new ASR cast call $SHARED_ASR 'respectedGameType()(uint32)' --rpc-url $L1_RPC # Expect: 9 (SUPER_CANNON_KONA) # Anchor root and timestamp on the new ASR cast call $SHARED_ASR 'getAnchorRoot()(bytes32,uint256)' --rpc-url $L1_RPC # Expect: (, ) from "Generate the Starting Anchor Super Root" # Retirement timestamp on the new ASR cast call $SHARED_ASR 'retirementTimestamp()(uint64)' --rpc-url $L1_RPC # Expect: equal to the migration block's timestamp # Game implementations registered on the shared factory cast call $SHARED_DGF 'gameImpls(uint32)(address)' 5 --rpc-url $L1_RPC # SUPER_PERMISSIONED cast call $SHARED_DGF 'gameImpls(uint32)(address)' 9 --rpc-url $L1_RPC # SUPER_CANNON_KONA # Expect both: non-zero # Init bonds match each game type's configuration cast call $SHARED_DGF 'initBonds(uint32)(uint256)' 5 --rpc-url $L1_RPC # Expect: 0 cast call $SHARED_DGF 'initBonds(uint32)(uint256)' 9 --rpc-url $L1_RPC # Expect: 80000000000000000 # No legacy implementations registered on the shared factory cast call $SHARED_DGF 'gameImpls(uint32)(address)' 0 --rpc-url $L1_RPC # CANNON cast call $SHARED_DGF 'gameImpls(uint32)(address)' 1 --rpc-url $L1_RPC # PERMISSIONED_CANNON cast call $SHARED_DGF 'gameImpls(uint32)(address)' 8 --rpc-url $L1_RPC # CANNON_KONA # Expect each: 0x0000000000000000000000000000000000000000 ``` ### Confirm Per-Chain Factories Are Cleared ```bash theme={null} for OLD_DGF in ; do for GT in 0 1 5 8 9; do echo "$OLD_DGF gameImpls($GT)= $(cast call $OLD_DGF 'gameImpls(uint32)(address)' $GT --rpc-url $L1_RPC)" done done # Expect every entry: 0x0000000000000000000000000000000000000000 ``` ### Confirm the Shared Lockbox Is Authorized ```bash theme={null} cast call $SHARED_LOCKBOX 'authorizedPortals(address)(bool)' --rpc-url $L1_RPC cast call $SHARED_LOCKBOX 'authorizedPortals(address)(bool)' --rpc-url $L1_RPC # Expect both: true ``` ## Start the Shared op-challenger and op-dispute-mon Both shared instances were staged in [Stage the Off-Chain Configuration](#stage-the-off-chain-configuration) with every flag except `--game-factory-address` set. Now that `$SHARED_DGF` is known and the migration is verified on-chain, fill in the address on both and start the processes as soon as practical. `SUPER_CANNON_KONA` is a permissionless game type, so the moment the shared factory is live anyone can create a game against it — not just `op-proposer`. Once a game is created, its clock runs and it resolves whether or not anyone challenges. `op-challenger` must be running to defend invalid claims before their game clocks expire, and `op-dispute-mon` must be running to observe and alert. This is independent of [Cut Over to a Single Shared op-proposer](#cut-over-to-a-single-shared-op-proposer) below — complete it first regardless of when the proposer cutover happens. 1. **Set the shared `op-challenger`'s `--game-factory-address` (`OP_CHALLENGER_GAME_FACTORY_ADDRESS`) to `$SHARED_DGF` and start the process.** Confirm the startup log lists `super-cannon-kona` as a registered trace type and shows no errors connecting to the shared supernode root RPC endpoint. 2. **Set the shared `op-dispute-mon`'s `--game-factory-address` (`OP_DISPUTE_MON_GAME_FACTORY_ADDRESS`) to `$SHARED_DGF` and start the process.** Confirm the supernode root connection is healthy and the metrics endpoint is serving. Healthy startup logs and a quiet error stream are the bar for proceeding. Both instances discover existing games on startup, so it does not matter whether a super-root game already exists in the shared factory by the time they come up. ## Cut Over to a Single Shared op-proposer Start one new `op-proposer` process for the shared factory. A single proposer replaces both per-chain ones because the supernode produces one super root per timestamp covering both chains. Configure the new instance with the flags below. | Flag (env var) | Value | | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | | `--game-factory-address` (`OP_PROPOSER_GAME_FACTORY_ADDRESS`) | the new shared `` | | `--superroot-rpcs` (`OP_PROPOSER_SUPERROOT_RPCS`) | `$SUPERNODE_RPC` or high-availability root endpoints for the same dependency set | | `--game-type` (`OP_PROPOSER_GAME_TYPE`) | `9` (SUPER\_CANNON\_KONA) | | `--l1-eth-rpc` (`OP_PROPOSER_L1_ETH_RPC`) | as for the existing proposers | | `--proposal-interval`, `--poll-interval`, `--mnemonic` or `--private-key` | as for the existing proposers | After start-up, verify: * The logs show the proposer polling the supernode and writing to the shared factory. * Within one `--proposal-interval`, the proposer submits a new game on the shared factory. Inspect it: ```bash theme={null} COUNT=$(cast call $SHARED_DGF 'gameCount()(uint256)' --rpc-url $L1_RPC) echo "gameCount=$COUNT" read -r GAME_TYPE CREATED_AT GAME_PROXY < <(cast call $SHARED_DGF 'gameAtIndex(uint256)(uint32,uint64,address)' $((COUNT-1)) --rpc-url $L1_RPC) # Expect: GAME_TYPE=9 and GAME_PROXY non-zero. echo "gameType=$GAME_TYPE createdAt=$CREATED_AT gameProxy=$GAME_PROXY" cast call $GAME_PROXY 'rootClaim()(bytes32)' --rpc-url $L1_RPC cast call $GAME_PROXY 'l2SequenceNumber()(uint256)' --rpc-url $L1_RPC ``` * Recompute the super root for the proposed timestamp and confirm it matches the proposal: ```bash theme={null} cast rpc superroot_atTimestamp "$(cast 2h )" \ --rpc-url $SUPERNODE_RPC | jq -r '.data.super_root' # Expect: equals rootClaim from above. ``` Once the proposer is stable, do not stop the per-chain `op-challenger` or `op-dispute-mon` instances—they are still needed for the drain window described next. ## Drain Pre-Migration Games and Reclaim Bonds The migration cleared the per-chain factories' implementation pointers so no new pre-migration games can be created, but every game proxy that already existed on those factories at migration time continues to function. Each game's implementation, `AnchorStateRegistry`, and `DelayedWETH` references were captured as immutable arguments on the proxy when it was created, so the cleared factory pointer does not affect resolution. Bond claims through `FaultDisputeGame.claimCredit` flow into the same `DelayedWETH` the bonds were posted into, independent of the portal or the new shared factory. Concretely: * The two per-chain `op-challenger` instances continue to play retired games to `DEFENDER_WINS` or `CHALLENGER_WINS` and schedule bond claims as games finalize. * Bond claims succeed without operator intervention. Chain A's retired games claim through chain A's `DelayedWETH` (which is also the one used by the new shared games); chain B's retired games claim through chain B's `DelayedWETH`, which is otherwise unused after migration. * The two per-chain `op-dispute-mon` instances keep observing those games. The per-game-type metric `op_dispute_mon_games{game_type="super-cannon-kona"}` and the equivalent for `super-permissioned` should monotonically decrease toward zero across the drain window. * `op-challenger`'s default `--game-window` is 28 days, sized to cover up to 16 days of game play plus a seven-day `DelayedWETH` withdrawal delay plus a five-day buffer. Do not shrink it on the per-chain instances; doing so risks dropping games before their bonds are claimable. Pick a still-in-flight pre-migration game and watch it through to resolution and bond claim: ```bash theme={null} cast call 'status()(uint8)' --rpc-url $L1_RPC # 0 = IN_PROGRESS, 1 = CHALLENGER_WINS, 2 = DEFENDER_WINS cast call 'resolvedAt()(uint64)' --rpc-url $L1_RPC # Non-zero once the game has resolved. ``` Once a game is resolved and the `DelayedWETH` finality window has elapsed, the challenger schedules `claimCredit`. Confirm bonds reach the configured claimant by watching the `op_challenger_bonds_total` metric on the per-chain instance, alongside `op_challenger_claim_failures_total` staying flat. ## Verify After the Migration Run these checks once the new proposer is stable. * **Confirm the shared `op-challenger` is defending super-root games.** The challenger does not break metrics down by game type, so verify by way of the startup log (every configured trace type, including `super-cannon-kona` and `super-permissioned`, must be listed as registered) and by ongoing logs (no scheduler or game-poll errors as super games appear on the shared factory). The aggregate `op_challenger_tracked_games{status="in_progress"}` becomes non-zero as super games are created and remains non-zero while games are in progress. * **Confirm the shared `op-dispute-mon` reports super-root games.** On the shared instance, `op_dispute_mon_games{game_type="super-cannon-kona"}` and `op_dispute_mon_games{game_type="super-permissioned"}` are non-zero once games are created. `op_dispute_mon_failed_games` stays near zero; a non-zero value typically points at missing `--supernode-rpc` or supernode unavailability. * **Confirm new pre-migration games cannot be created.** Optionally call `DisputeGameFactory.create` with one of the cleared game types on either per-chain factory and confirm it reverts. * **Watch for the first super-game finalization.** The first anchor update typically lands roughly seven days after the first super-root game is created (game duration plus `DISPUTE_GAME_FINALITY_DELAY_SECONDS`). Do not block the rollout on this—schedule a follow-up to re-run `getAnchorRoot()` after that window and confirm it returns the new game's claim instead of the starting anchor. ## Tear Down After the Drain A per-chain instance is safe to retire when its `op_dispute_mon_games{game_type="super-cannon-kona"}` and `op_dispute_mon_games{game_type="super-permissioned"}` have been zero for at least one full `--game-window` (default 28 days) and `op_challenger_tracked_games{status="in_progress"}` on the matching per-chain `op-challenger` is zero with bond-claim metrics stable. For each chain when both conditions hold, stop the per-chain `op-challenger` and `op-dispute-mon` instances. Once both chains are drained, the steady-state operational footprint is one `op-proposer`, one `op-challenger`, and one `op-dispute-mon`, all pointed at the shared factory and a single supernode that derives both chains. ## Next Steps * Plan the full interop activation milestone—`migrate` joins the chains under a shared dispute game, but turning on cross-chain messaging is a separate step. See [Interop Explainer](/op-stack/interop/explainer) when you are ready. * Schedule a follow-up to verify the anchor advances on the first super-game finalization, roughly seven days after the new proposer's first proposal. Re-run `cast call $SHARED_ASR 'getAnchorRoot()(bytes32,uint256)' --rpc-url $L1_RPC` and confirm it returns the new game's claim. # Migrating to permissionless fault proofs on OP Stack Source: https://docs.optimism.io/chain-operators/tutorials/migrating-permissionless Migrate your OP Stack chain from permissioned to permissionless fault proofs: configure the dispute components, deploy the contracts with OPCM, test the off-chain agents, and switch the respected game type. This guide shows you how to transition your OP Stack chain from permissioned to permissionless fault proofs. It walks chain operators through the four migration phases: configuring the dispute components, deploying the smart contracts with OPCM, testing the off-chain agents, and switching the respected game type. ## Overview The OP Stack architecture uses Fault Proofs to ensure the validity of withdrawals from L2 to L1. Transitioning from permissioned to permissionless proofs represents a significant security upgrade, allowing any participant to propose and challenge state output roots. Permissioned games previously relied on a single trusted validator, this is typically the proposer which is configured in the PermissionedDisputeGame, and is usually the network's only sequencer. This migration involves several key components: * Configuring security-critical dispute [monitoring services](/chain-operators/tools/chain-monitoring) * Deploying and configuring smart contracts using [op-deployer](/chain-operators/tools/op-deployer/overview) * Testing the new system before activation * Setting the respected game type to permissionless fault proofs, specifically using the [`FaultDisputeGame`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol) ## Prerequisites Before beginning this transition, your chain should: * Be running a standard OP Stack implementation * It's recommended to use the latest contracts version, minimum required [**v5.0.0**](https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv5.0.0). * Be operating with the required infrastructure services including [`op-challenger`](/op-stack/fault-proofs/challenger) and [`op-dispute-mon`](/chain-operators/tools/chain-monitoring#dispute-mon). ## Migration steps The process of migrating from permissioned to permissionless fault proofs involves four main phases: configuring off-chain dispute components, deploying the necessary smart contracts, testing the system thoroughly, and finally switching the chain to use permissionless proofs. Each step builds on the previous one to ensure a smooth and secure transition. Let's begin with configuring the dispute components that will interact with the new permissionless game. ## 1. Configure the dispute components The `op-challenger` and `op-dispute-mon` services are critical security components that participate in the dispute game process to challenge invalid proposals and monitor active games. ### Upgrade to the latest `op-challenger` Upgrade to the [latest release](https://github.com/ethereum-optimism/optimism/releases), which contains important improvements to simplify the upgrade process. You can use the official Docker image for reliability and ease of deployment: ```bash theme={null} # Pull a specific stable release version docker pull us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger: ``` Then run the image, for example: ```bash theme={null} # Run with all required flags docker run -d --name op-challenger \ -e OP_CHALLENGER_GAME_TYPES=permissioned,cannon-kona \ -e OP_CHALLENGER_PRESTATES_URL= \ -e OP_CHALLENGER_L1_ETH_RPC= \ -e OP_CHALLENGER_GAME_FACTORY_ADDRESS= \ -e OP_CHALLENGER_PRIVATE_KEY= \ -e OP_CHALLENGER_NETWORK= \ -v /path/to/local/prestates:/prestates \ us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:latest # Replace all placeholder values with your actual configuration ``` Replace `` with your actual prestates URL. If your deployment requires building from source, you can alternatively use: ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism -b op-challenger/ --recurse-submodules cd optimism make op-challenger ``` ### Update network configuration Configure `op-challenger` to load your chain configuration. Even if your chain is not included in the [superchain-registry](/op-stack/protocol/superchain-registry), you can specify a custom configuration: ```bash theme={null} # For chains in the registry --network # For chains not in the registry, provide a path to your rollup configuration - `rollup.json` - Your rollup configuration - `genesis-l2.json` - Your L2 genesis file ``` ### Enable the cannon-kona game type From the Karst upgrade, `cannon-kona` (the kona-client program run inside the Cannon VM) is the respected permissionless game type, replacing op-program. Configure `op-challenger` to support both permissioned and permissionless games by setting: ```bash theme={null} --game-types permissioned,cannon-kona ``` Or by setting the environment variable: ```bash theme={null} OP_CHALLENGER_GAME_TYPES=permissioned,cannon-kona ``` ### Configure prestates access Replace the `--cannon-kona-prestate` flag with `--prestates-url`, which points to a source containing all required prestates: ```bash theme={null} --prestates-url ``` The URL can use `http`, `https`, or `file` protocols. Each prestate should be named as `.bin.gz`. ### Building required prestates for chains not in the superchain-registry You'll need a new absolute prestate to register with the `FaultDisputeGame` and `PermissionedDisputeGame` (see [Section 2](#2-deploy-and-configure-smart-contracts-using-opcm)). The initial prestate used for permissioned games doesn't include the necessary chain configuration for the Fault Proof System. The assumption is that the chain operator, the single permissioned actor, will not challenge their own games. So the absolute prestate on the initial `PermissionedDisputeGame` will never be used. When deploying a new chain, you must first deploy the L1 contracts and then generate the chain genesis file and rollup configuration files. These are inputs to the creation of the absolute prestate and this circular dependency is the reason chains cannot be deployed directly to the permissionless Fault Proof System. For chains not in the superchain-registry, you need to build custom prestates with your chain's configuration: Build the kona-client absolute prestate with `just reproducible-prestate-kona` (see the [absolute prestate tutorial](/chain-operators/tutorials/absolute-prestate)). The artifacts are written to: * `rust/kona/prestate-artifacts-cannon/prestate-proof.json` — the proof file; its `pre` field is the absolute prestate hash (`jq -r .pre ...`) * `rust/kona/prestate-artifacts-cannon/.bin.gz` — the preimage file `op-challenger` loads Register the kona-client absolute prestate with your `FaultDisputeGame` and `PermissionedDisputeGame`. The challenger refuses to interact with games whose on-chain absolute prestate doesn't match the one it has, so the hash must match exactly. ### Ensure sufficient funds for bonds Bonds are required for both permissioned and permissionless games. However, with permissioned games, you typically don't post claims regularly, making bond requirements less noticeable. In contrast, the challenger in permissionless games will frequently need to post bonds with each claim it makes. Therefore, ensure your challenger has sufficient funds available. As a general guideline: * Maintain a minimum balance of 50 ETH * Have access to a large pool of ETH for potential attack scenarios * Implement monitoring to ensure sufficient funds are always available ### Ensure there is disk space for the challenger to use `op-challenger`, particularly in permissionless mode, should have access to disk. About 50GB is enough to cover a couple of `invalid_ games`. Though the storage requirements will increase if the challenger needs to respond to more invalid dispute games. Nominally, the challenger does not use disk space as long as there aren’t any invalid proposals being made. One way to gain more confidence that the op-challenger was configured correctly is to operate the op-challenger in “runner” mode. Using the same op-challenger configuration, invoke the `op-challenger run-trace --run cannon-kona` subcommand. This will run op-challenger in a mode where it runs the kona-client program in a Cannon VM on live L2 blocks to ensure those were configured correctly. This command runs forever, checking every couple of L2 blocks. But it suffices to let it run until it has completed one loop and kill it. Wait you see `Successfully verified output root` in the logs before shutting it down. Any errors indicate a misconfiguration. ### Set up `op-dispute-mon` Ensure `op-dispute-mon` is properly configured by following the [steps](/chain-operators/tools/chain-monitoring#dispute-mon) in the documentation. ## 2. Deploy and configure smart contracts using OPCM This section requires privileged actions by the `ProxyAdminOwner` and the `Guardian` role. ### Understanding ProxyAdmin Owner and Guardian roles This migration requires actions by privileged roles in your system: * The **ProxyAdmin Owner** has the authority to upgrade proxy contracts. * The **Guardian** has emergency powers like pausing withdrawals and changing the respected game type. For detailed information about privileged roles and their security implications, refer to the [privileged roles documentation](/op-stack/protocol/privileged-roles). ### Adding the PermissionlessDisputeGame to a chain To enable the permissionless dispute game, call the `upgrade()` function on the `OPContractsManagerV2` (OPCM) contract with the appropriate `DisputeGameConfig` entries. This is typically done via `op-deployer manage add-game-type-v2`. The upgrade will: 1. Register the `FaultDisputeGame` implementation on the `DisputeGameFactory` with the correct game arguments (absolute prestate, VM, anchor state registry, delayed WETH, chain ID). 2. Set the initial bond for the new game type. See a high‐level implementation from this [docs](/chain-operators/tutorials/dispute-games) or [this superchain-ops template](https://github.com/ethereum-optimism/superchain-ops/blob/main/src/template/AddGameTypeTemplate.sol). ## 3. Testing off-chain agents After you've set the permissionless `FaultDisputeContract` implementations on the `DisputeGameFactory` and before you set the respected game type to it (game type 0), you can test `op-challenger` and `op-dispute-mon` to ensure they are working correctly with permissionless games. There are a number of useful `op-challenger` subcommands that can be used for testing, particularly `list-games`, `list-claims` and `create-game`. See the [README](https://github.com/ethereum-optimism/optimism/tree/develop/op-challenger#subcommands) and `op-challenger --help` output for further details. The two tests below are basic sanity tests: ### Test defending valid proposals Create a valid proposal using the permissionless game type `0`: 1. Ensure the proposal is from a block at or before the `safe` head: ```bash theme={null} cast block --rpc-url safe ``` 2. Get a valid output root (from op-node): ```bash theme={null} cast rpc --rpc-url optimism_outputAtBlock \ $(cast 2h ) | jq -r .outputRoot ``` 3. Create a test game: ```bash theme={null} ./op-challenger/bin/op-challenger create-game \ --l1-eth-rpc= \ --game-factory-address \ --l2-block-num \ --output-root \ ``` 4. Verify: * `op-challenger` logs a message showing the game is in progress * `op-challenger` doesn't post a counter claim (as this is a valid proposal) * `dispute-mon` includes the new game with `status="agree_defender_ahead"` ### Test countering invalid claims Post an invalid counter claim to the valid proposal created above: ```bash theme={null} ./op-challenger/bin/op-challenger move \ --l1-eth-rpc \ --game-address \ --attack \ --parent-index 0 \ --claim 0x0000000000000000000000000000000000000000000000000000000000000000 \ ``` Verify that `op-challenger` posts a counter-claim to the invalid claim. You can view claims using: ```bash theme={null} ./op-challenger/bin/op-challenger list-claims \ --l1-eth-rpc \ --game-address ``` There should be 3 claims in the game after this test. ## Switch to permissionless proofs After completing all previous steps and verifying their successful operation, you need to update the `respectedGameType` in the `AnchorStateRegistry`. This requires execution through the appropriate privileged role (typically the Guardian). You have two main options for executing this step: ### Option 1: Execute using a multisig If your privileged role (such as the Guardian) is controlled by a multisig or DAO governance system, use the provided JSON payload (`input.json`): ```json theme={null} { "chainId": "", "metadata": { "name": "Deputy Guardian - Enable Permissionless Dispute Game", "description": "This task updates the `respectedGameType` in the `AnchorStateRegistry` to `CANNON` (game type 0), enabling users to permissionlessly propose outputs as well as for anyone to participate in the dispute of these proposals. This action requires all in-progress withdrawals to be re-proven against a new `FaultDisputeGame` that was created after this update occurs." }, "transactions": [ { "metadata": { "name": "Update `respectedGameType` in the `AnchorStateRegistry`", "description": "Updates the `respectedGameType` to `CANNON` in the `AnchorStateRegistry`, enabling permissionless proposals and challenging." }, "to": "", "value": "0x0", "data": "0x7fc485040000000000000000000000000000000000000000000000000000000000000000", "contractMethod": { "type": "function", "name": "setRespectedGameType", "inputs": [ { "name": "_gameType", "type": "uint32" } ], "outputs": [], "stateMutability": "nonpayable" }, "contractInputsValues": { "_gameType": "0" } } ] } ``` * **Submit this JSON payload** through your interface (e.g., Safe transaction builder). * **Simulate** this transaction using Tenderly before execution to ensure the expected state changes: * The `respectedGameType` in the `AnchorStateRegistry` should change from `1` (PERMISSIONED) to `0` (CANNON). *** ### Option 2: Direct execution via `cast` (Forge CLI) Alternatively, if you're executing directly from a single-privileged wallet or want quicker execution, use the following `cast` commands: 1. First, encode the transaction calldata using `cast calldata`: ```bash theme={null} CALLDATA=$(cast calldata "setRespectedGameType(uint32)" 0) ``` 2. Send the transaction: ```bash theme={null} # Execute the transaction cast send --rpc-url --private-key "$CALLDATA" ``` 3. After execution, verify the respected game type: ```bash theme={null} cast call --rpc-url "respectedGameType()(uint32)" # The value should now be 0 (CANNON) ``` ### Post-execution configuration: After updating, configure `op-proposer` to create proposals using the permissionless `CANNON` game type: Via command-line argument: ```bash theme={null} --game-type 0 ``` Or via environment variable: ```bash theme={null} OP_PROPOSER_GAME_TYPE=0 ``` This action requires all in-progress withdrawals to be re-proven against a new `FaultDisputeGame` created after this update occurs. ## Next steps * For more detail on deploying new dispute games with OPCM, [see the docs](/chain-operators/tutorials/dispute-games). * Deploy new dispute games with OPCM via [this tutorial](/chain-operators/tutorials/dispute-games). * Generate an absolute prestate using the [absolute prestate guide](/chain-operators/tutorials/absolute-prestate). * Understand fault proofs in the [Fault proofs explainer](/op-stack/fault-proofs/explainer). # Modifying predeployed contracts Source: https://docs.optimism.io/chain-operators/tutorials/modifying-predeploys Learn how to modify predeployed contracts for an OP Stack chain by upgrading the proxy. OP Stack Hacks are explicitly things that you can do with the OP Stack that are *not* currently intended for production use. OP Stack Hacks are not for the faint of heart. You will not be able to receive significant developer support for OP Stack Hacks. Be prepared to get your hands dirty and to work without support. OP Stack blockchains have a number of [predeployed contracts](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/libraries/Predeploys.sol) that provide important functionality. Most of those contracts are proxies that can be upgraded using the `proxyAdminOwner` which was configured when the network was initially deployed. ## Before you begin In this tutorial, you learn how to modify predeployed contracts for an OP Stack chain by upgrading the proxy. The predeploys are controlled from a predeploy called [`ProxyAdmin`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/ProxyAdmin.sol), whose address is `0x4200000000000000000000000000000000000018`. The function to call is [`upgrade(address,address)`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/ProxyAdmin.sol#L152-L168). The first parameter is the proxy to upgrade, and the second is the address of a new implementation. ## Modify the legacy `L1BlockNumber` contract For example, the legacy `L1BlockNumber` contract is at `0x420...013`. To disable this function, we'll set the implementation to `0x00...00`. We do this using the [Foundry](https://book.getfoundry.sh/) command `cast`. * Set these addresses as variables in your terminal. ```sh theme={null} L1BLOCKNUM=0x4200000000000000000000000000000000000013 PROXY_ADMIN=0x4200000000000000000000000000000000000018 ZERO_ADDR=0x0000000000000000000000000000000000000000 ``` * Set `PRIVKEY` to the private key of your ADMIN address. * Set `ETH_RPC_URL`. If you're on the computer that runs the blockchain, use this command. ```sh theme={null} export ETH_RPC_URL=http://localhost:8545 ``` See that when you call the contract you get a block number, and twelve seconds later you get the next one (block time on L1 is twelve seconds). ```sh theme={null} cast call $L1BLOCKNUM 'number()' | cast --to-dec sleep 12 && cast call $L1BLOCKNUM 'number()' | cast --to-dec ``` ```sh theme={null} L1BLOCKNUM_IMPLEMENTATION=`cast call $L1BLOCKNUM "implementation()" | sed 's/000000000000000000000000//'` echo $L1BLOCKNUM_IMPLEMENTATION ``` ```sh theme={null} cast send --private-key $PRIVKEY $PROXY_ADMIN "upgrade(address,address)" $L1BLOCKNUM $ZERO_ADDR ``` ```sh theme={null} cast call $L1BLOCKNUM 'implementation()' cast call $L1BLOCKNUM 'number()' ``` ```sh theme={null} cast send --private-key $PRIVKEY $PROXY_ADMIN "upgrade(address,address)" $L1BLOCKNUM $L1BLOCKNUM_IMPLEMENTATION cast call $L1BLOCKNUM 'number()' | cast --to-dec ``` # How to rewind op-geth Source: https://docs.optimism.io/chain-operators/tutorials/rewind-op-geth Learn how to rewind an op-geth node to a previous chain head. ## Overview This tutorial teaches you how to rewind a single op-geth instance to a previous chain head. This can be helpful to fix a divergent node, recreate archival state, or the safedb from an earlier chain state. ## Rewind op-geth Follow these steps to rewind your op-geth node. Whatever CL clients are driving the op-geth instance need to be stopped to prevent them from interfering with the rewind later. This would typically be a locally running `op-node` or `kona-node` application, a Docker container or a pod in a Kubernetes cluster. Make sure you don't have something like ArgoCD syncing the app in question which would just scale the pod back up again. If you already know the block number/hash you want to rewind to, you can proceed to the next step. If you only know the *timestamp* you want to rewind to, you can find the corresponding block with ```bash theme={null} cast find-block 1741890000 -r ``` Where `` points to your op-geth node’s RPC endpoint, e.g. `http://localhost:8545` if it was a local instance with the default port and `1741890000` is an example unix timestamp. You can use e.g. [https://www.epochconverter.com/](https://www.epochconverter.com/) to convert from human times to unix timestamps. You need the JWT secret and *open* & *admin* port (default `8545` & `8551`). Then you can use the `op-wheel` command from the [monorepo](https://github.com/ethereum-optimism/optimism/tree/develop/op-wheel) to issue the rewind. ```bash theme={null} # save JWT secret to env var export JWT="YourJWTSecret123" # assuming default ports 8545 and 8551 and local endpoint go run ./op-wheel/cmd engine rewind \ --engine.open http://localhost:8545 \ --engine http://localhost:8551 \ --engine.jwt-secret $JWT \ --log.level DEBUG \ --set-head --to 8460000 ``` This would rewind the op-geth node to the block with number `8460000`. You should have determined the right block number in step 2. You can now start your CL client again. It will sync from the rewound block head. # Upgrading a Chain From Output Roots to Super Roots Source: https://docs.optimism.io/chain-operators/tutorials/upgrade-chain-to-super-roots Upgrade an OP Stack chain from output-root dispute games to super-root dispute games with a single opcm.upgrade call, then cut op-proposer, op-challenger, and op-dispute-mon over to super roots. # Upgrading a Chain From Output Roots to Super Roots This guide depends on the interop feature, which is still in development. Do not follow it on production chains. This runbook walks you through upgrading a single OP Stack chain from output-root dispute games (`PERMISSIONED_CANNON`, `CANNON` or `CANNON_KONA`) to super-root dispute games (`SUPER_PERMISSIONED` or `SUPER_CANNON_KONA`). It runs as a single `opcm.upgrade` call against the chain's existing per-chain `AnchorStateRegistry` and `DisputeGameFactory`. The chain's permission model is preserved: a permissioned chain stays permissioned with `SUPER_PERMISSIONED` only; a permissionless chain runs both super game types with `SUPER_CANNON_KONA` as the respected one. Differences between the two are called out inline. By the end you will have a chain proposing super-root claims via `op-proposer` using a single-chain super-root RPC endpoint and monitoring them with `op-dispute-mon`. On permissionless chains, `op-challenger` defends `SUPER_CANNON_KONA` claims. On permissioned chains, `op-dispute-mon` detects invalid `SUPER_PERMISSIONED` claims, `op-challenger` updates the `AnchorStateRegistry` as games finalize. Every pre-migration dispute game already in flight continues to resolve, and proven withdrawals are not invalidated. This is `opcm.upgrade`, not `opcm.migrate` — the chain keeps its own per-chain `AnchorStateRegistry` and `DisputeGameFactory`. Looking to switch from permissioned to permissionless fault proofs? See [Migrating to permissionless fault proofs](/chain-operators/tutorials/migrating-permissionless). This runbook is for chains already running fault proofs that need to move from output-root games to super-root games. ## Before You Begin ### Required tooling The versions below are the ones the optimism repo's `mise.toml` pins; older versions of `cast` in particular may not parse the function-selector syntax used in this runbook. | Tool | Minimum version | | --------------------------- | --------------- | | `foundry` (`cast`, `forge`) | `1.2.3` | | `just` | `1.46.0` | | `jq` | `1.7.1` | | `go` | `1.26.5` | | `curl` | any | You also need a checkout of the [optimism monorepo](https://github.com/ethereum-optimism/optimism) to run [`op-fetcher`](https://github.com/ethereum-optimism/optimism/tree/develop/op-fetcher) (used in the next step). ### Gather the Required Inputs Collect everything below before you start. **Chain identity.** The chain's per-chain addresses live in the `superchain-registry` repository under `superchain/configs//.toml`. Open that file and read `chain_id`, `addresses.SystemConfigProxy`, and `addresses.L1StandardBridgeProxy`. **Chain addresses and roles.** Use `op-fetcher` to derive the rest of the on-chain configuration in a single call. It runs an embedded forge script against `$L1_RPC` and resolves every per-chain proxy, role, and the current fault-proof status from `SystemConfig` and `L1StandardBridge`: ```bash theme={null} cd /op-fetcher just build-all go run ./cmd fetch \ --l1-rpc-url "$L1_RPC" \ --system-config "" \ --l1-standard-bridge "" \ --output-file chain.json ``` Read the values you need from `chain.json`: | Item | Source | | ---------------------------------------------------------- | ---------------------------------------------------------- | | L2 chain ID | `chain_id` in the chain's registry TOML | | `SystemConfig` proxy | `addresses.SystemConfigProxy` in the chain's registry TOML | | `OptimismPortal2` proxy | `.addresses.OptimismPortalProxy` | | `AnchorStateRegistry` proxy (referred to below as ``) | `.addresses.AnchorStateRegistryProxy` | | `DisputeGameFactory` proxy (referred to below as ``) | `.addresses.DisputeGameFactoryProxy` | | `SuperchainConfig` proxy | `.addresses.SuperchainConfigProxy` | **Chain type.** The upgrade preserves the chain's existing permission model. `chain.json` reports the current respected game type at `.faultProofs.respectedGameType`: * `1` (`PERMISSIONED_CANNON`) — chain is **permissioned**. The new respected game type is `5` (`SUPER_PERMISSIONED`). * `0` (`CANNON`) or `8` (`CANNON_KONA`) — chain is **permissionless**. The new respected game type is `9` (`SUPER_CANNON_KONA`). **Init bonds.** `SUPER_PERMISSIONED` (game type `5`) is bondless and must use an `initBond` of `0`. `SUPER_CANNON_KONA` (game type `9`) uses `0.08 ether` (`80000000000000000` wei), the standard value used on existing chains. **Release artifacts and infrastructure.** | Item | Source | | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `OPCM` address for the target network | `validation/standard/standard-versions-.toml` in the [superchain-registry](https://github.com/ethereum-optimism/superchain-registry). Look up the `op-contracts/v8.x.y` release pinned by the `OPCMUpgradeV800` template and read `op_contracts_manager.address`. | | Kona-interop prestate hash | OPCM release manifest. Use the `-interop` kona variant, even if interop is not scheduled for the chain. | | Prestate artifact URL | The chain's existing `cannon-kona-prestates-url` server, with the kona-interop prestate uploaded ahead of the upgrade | | Single-chain super-root RPC endpoint (`$SUPER_ROOT_RPC`) | Your infrastructure team. Use the chain's op-node RPC endpoint or an op-supernode `//` endpoint. An op-node must run with `--safedb.path` enabled and populated. The namespaced endpoint returns a super root containing only this chain, even if the op-supernode tracks other chains. | ### Verify the Preconditions Before you change any configuration: * **Confirm the template's extra instructions.** Open `superchain-ops/src/template/OPCMUpgradeV800.sol` and check `_buildExtraInstructions`. As of writing it injects `overrides.cfg.startingRespectedGameType` and `PermittedProxyDeployment`. Both need attention before continuing. `PermittedProxyDeployment` must be dropped: OPCM `8.0.0` permits no proxy deployments during an upgrade, because the unified `DelayedWETH` shipped with the 7.x OPCM, so the instruction now reverts with `OPContractsManagerV2_InvalidUpgradeInstruction`. An `overrides.cfg.startingAnchorRoot` override must be added: without it, OPCM falls back to the existing on-chain `startingAnchorRoot`, which on a pre-upgrade chain is an output-root-shaped value with a block-number `l2SequenceNumber` — not a valid super-root anchor. The template must be extended to read a starting super-root anchor from TOML and add it as an extra instruction. Fix the template before continuing. * **Confirm the RPC endpoint returns a single-chain super root.** Either the chain's op-node RPC endpoint or an op-supernode `//` endpoint can be used. Do not use a multi-chain op-supernode root endpoint; it computes roots across its full dependency set. * **Verify the single-chain RPC endpoint is healthy.** For an op-node or namespaced op-supernode endpoint, confirm it reports a recent finalized L2 head and can produce the corresponding super root: ```bash theme={null} TS=$(cast rpc optimism_syncStatus --rpc-url $SUPER_ROOT_RPC | jq -r '.finalized_l2.timestamp') cast rpc superroot_atTimestamp "$(cast 2h $TS)" \ --rpc-url $SUPER_ROOT_RPC | jq -r '.data.super_root' ``` If an op-node returns a SafeDB error, configure `--safedb.path`, let the node populate records through derivation, and retry. `optimism_syncStatus` can succeed while SafeDB is disabled, but `superroot_atTimestamp` cannot serve a non-genesis timestamp without SafeDB. * **Verify the prestate server serves the new hash.** ```bash theme={null} curl -fI "$PRESTATE_URL/$SUPER_PRESTATE_HASH.bin.gz" ``` ## Stage the Off-Chain Configuration Apply these changes before you submit the on-chain upgrade. After the changes ship, the components keep operating against existing pre-migration games and pick up super-root games automatically once the upgrade lands. ### Update op-challenger Update the running `op-challenger` for the chain. Keep `--rollup-rpc` and the existing `--game-types` so existing games continue to be defended. Add the super-root trace type only on permissionless chains, where `SUPER_CANNON_KONA` is enabled. | Action | Flag (env var) | Value | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | | Add | `--superroot-rpc` (`OP_CHALLENGER_SUPERROOT_RPC`) | `$SUPER_ROOT_RPC` | | Append to | `--game-types` (`OP_CHALLENGER_GAME_TYPES`) | `super-cannon-kona`. Do not add `super-permissioned`; the simplified `SUPER_PERMISSIONED` game does not require claims to be posted. | | Confirm set | `--cannon-kona-prestates-url` (`OP_CHALLENGER_CANNON_KONA_PRESTATES_URL`) | The prestate-server URL you validated in the preconditions | | Confirm set | `--cannon-kona-network` (`OP_CHALLENGER_CANNON_KONA_NETWORK`) or `--cannon-kona-depset-config` (`OP_CHALLENGER_CANNON_KONA_DEPSET_CONFIG`) | One must be set so kona can resolve the dependency set for `SUPER_CANNON_KONA`. | On a permissionless chain, confirm the startup log lists `super-cannon-kona` as registered and shows no connection errors against the single-chain super-root RPC endpoint. On a permissioned chain, confirm the existing trace types remain registered; do not configure a `SUPER_PERMISSIONED` trace type. `op-challenger` is still required on permissioned chains to update the `AnchorStateRegistry` as `SUPER_PERMISSIONED` games finalize. ### Update op-dispute-mon Update the running `op-dispute-mon` for the chain. | Action | Flag (env var) | Value | | ------ | -------------------------------------------------- | ----------------- | | Add | `--superroot-rpc` (`OP_DISPUTE_MON_SUPERROOT_RPC`) | `$SUPER_ROOT_RPC` | Keep `--rollup-rpc`. `op-dispute-mon` discovers games from the existing `DisputeGameFactory` and does not need a game-type filter change. After the restart, confirm the existing-games metrics keep populating. ### Leave op-proposer Unchanged for Now Skip `op-proposer` until cutover. Its configuration changes in [Switch op-proposer to Super Roots](#switch-op-proposer-to-super-roots). ## Generate the Starting Anchor Super Root The upgrade must re-initialise `` with a super-root-shaped starting anchor. The existing on-chain `startingAnchorRoot` is in output-root form (its `l2SequenceNumber` is an L2 block number), so the template must inject a fresh super-root value via `overrides.cfg.startingAnchorRoot` in `extraInstructions`. Confirm in the precondition above that the template has been extended to read this from TOML and pass it through. Compute the value using `superroot_atTimestamp`. Pick the current finalized timestamp (or any recent finalized timestamp), then ask the single-chain RPC endpoint for the super root at that timestamp. ```bash theme={null} # .finalized_l2.timestamp is a JSON number (decimal Unix seconds). TS=$(cast rpc optimism_syncStatus --rpc-url $SUPER_ROOT_RPC | jq -r '.finalized_l2.timestamp') # superroot_atTimestamp expects a hex-encoded JSON string (hexutil.Uint64); cast 2h handles the conversion. cast rpc superroot_atTimestamp "$(cast 2h $TS)" --rpc-url $SUPER_ROOT_RPC | jq -r '.data.super_root' echo "timestamp=$TS" ``` Capture two values: * `super_root` (a `bytes32` hash from `.data.super_root`) — passed as `Proposal.root` in `overrides.cfg.startingAnchorRoot`. * `timestamp` (the uint64 you passed in) — passed as `Proposal.l2SequenceNumber`. This field is the timestamp itself, not a block number or sequence index. ## Build the superchain-ops Task Author a new task directory under `superchain-ops/src/tasks///` using the `OPCMUpgradeV800` template. The schema below assumes the template has been extended (per the precondition above) to also read a starting super-root anchor and inject it as `overrides.cfg.startingAnchorRoot`. ### Configure config.toml ```toml theme={null} l2chains = [ {name = "", chainId = }, ] templateName = "OPCMUpgradeV800" [[opcmUpgrades]] chainId = # Kona-interop super prestate, used by SUPER_CANNON_KONA. The `-interop` variant # supports super roots and works whether # or not interop is enabled or scheduled on the chain. cannonKonaPrestate = "0x" expectedValidationErrors = "" # fill in after the dry run initBond = 80000000000000000 # 0.8 ether, applied to `SUPER_CANNON_KONA` games; the template always forces SUPER_PERMISSIONED to 0 startingRespectedGameType = <9 or 5> # 9 permissionless, 5 permissioned # Pending template extension — see the "Generate the Starting Anchor Super Root" section. startingAnchorRoot = { root = "0x", l2SequenceNumber = } [addresses] OPCM = "0x" ``` The template derives everything else (per-game-type config, `SuperchainConfig`, validator, etc.) automatically — no further TOML required. ### Capture expectedValidationErrors Run the task in simulation mode against an L1 fork from inside the task directory: ```bash theme={null} cd superchain-ops/src/tasks// just simulate ``` If the validator's output does not match `expectedValidationErrors` in TOML, the simulation reverts with a message of the form `Unexpected errors: ; expected: `. Read the actual codes from that revert message. The default expectation is **no errors** — `expectedValidationErrors = ""` and a clean simulation. Any non-empty error string must be reviewed code by code, not copy-pasted. For each code: * **Resolve it** if it points at a fixable input — a wrong address, a wrong prestate, a template release mismatch, a missing override, or a registry entry that needs updating. * **Add it to `expectedValidationErrors` only after justifying it** with an inline comment in the TOML explaining why it is structurally expected for this chain. The simulation passes once every printed code has been either resolved or knowingly added with justification. Treat any code you cannot explain as a hard stop. ## Execute the Upgrade 1. **Stop `op-proposer` for the chain.** Existing games continue to resolve; only new proposals halt. 2. **Leave `op-challenger` and `op-dispute-mon` running.** Both were configured earlier and pick up super-root games automatically. 3. **Sign and broadcast the task** using your team's standard `superchain-ops` signing workflow. 4. **Wait for the L1 transaction to confirm.** The on-chain effect: * `` is re-initialised with the supplied anchor and respected game type. The retirement timestamp is not bumped, so existing in-flight games stay valid. * The super dispute game implementation or implementations are installed on ``. * Implementation pointers for the game types passed with `enabled = false` are cleared, blocking creation of new games of those types. ## Verify the Upgrade On-Chain Run the checks below before you cut `op-proposer` over. If any check fails, stop, do not start the new proposer, and escalate via your standard incident-response channel. Recovery from a half-cut state with a misbehaving proposer is materially harder than recovery from a paused proposer. ### Common Checks ```bash theme={null} # Respected game type cast call 'respectedGameType()(uint32)' --rpc-url $L1_RPC # Expect: 9 (permissionless) or 5 (permissioned) # Anchor root and timestamp cast call 'getAnchorRoot()(bytes32,uint256)' --rpc-url $L1_RPC # Expect: (, ) from the previous step # Retirement timestamp unchanged cast call 'retirementTimestamp()(uint64)' --rpc-url $L1_RPC # Expect: same value as before the upgrade # Pre-migration impls cleared cast call 'gameImpls(uint32)(address)' 0 --rpc-url $L1_RPC # CANNON cast call 'gameImpls(uint32)(address)' 1 --rpc-url $L1_RPC # PERMISSIONED_CANNON cast call 'gameImpls(uint32)(address)' 8 --rpc-url $L1_RPC # CANNON_KONA # Expect each: 0x0000000000000000000000000000000000000000 ``` ### Permissionless Chain Checks ```bash theme={null} cast call 'gameImpls(uint32)(address)' 5 --rpc-url $L1_RPC # SUPER_PERMISSIONED cast call 'gameImpls(uint32)(address)' 9 --rpc-url $L1_RPC # SUPER_CANNON_KONA # Expect both: non-zero cast call 'initBonds(uint32)(uint256)' 5 --rpc-url $L1_RPC # Expect: 0 cast call 'initBonds(uint32)(uint256)' 9 --rpc-url $L1_RPC # Expect: 80000000000000000, or the configured SUPER_CANNON_KONA bond ``` ### Permissioned Chain Checks ```bash theme={null} cast call 'gameImpls(uint32)(address)' 5 --rpc-url $L1_RPC # SUPER_PERMISSIONED # Expect: non-zero cast call 'initBonds(uint32)(uint256)' 5 --rpc-url $L1_RPC # Expect: 0 cast call 'gameImpls(uint32)(address)' 9 --rpc-url $L1_RPC # SUPER_CANNON_KONA # Expect: 0x0000000000000000000000000000000000000000 ``` ## Switch op-proposer to Super Roots Start `op-proposer` with the new configuration. | Flag (env var) | Old | New | | ------------------------------------------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------- | | `--rollup-rpc` (`OP_PROPOSER_ROLLUP_RPC`) | set | **remove** | | `--superroot-rpcs` (`OP_PROPOSER_SUPERROOT_RPCS`) | unset | `$SUPER_ROOT_RPC`, or a list of high-availability endpoints that each return a super root containing only this chain | | `--game-type` (`OP_PROPOSER_GAME_TYPE`) | `0` or `1` | numeric: `9` for permissionless, `5` for permissioned | | `--game-factory-address` (`OP_PROPOSER_GAME_FACTORY_ADDRESS`) | unchanged | unchanged (same ``) | Other flags such as `--proposal-interval` and `--poll-interval` stay the same. After start-up, verify: * The logs show the proposer polling the configured single-chain super-root RPC endpoint and contain no references to `--rollup-rpc`. * Within one `--proposal-interval`, the proposer submits a new game. Inspect it: ```bash theme={null} COUNT=$(cast call 'gameCount()(uint256)' --rpc-url $L1_RPC) # Expect: increased by 1 since the upgrade echo "gameCount=$COUNT" read -r GAME_TYPE CREATED_AT GAME_PROXY < <(cast call 'gameAtIndex(uint256)(uint32,uint64,address)' $((COUNT-1)) --rpc-url $L1_RPC) # Expect: gameType matches the configured super type (5 or 9) and gameProxy is non-zero. echo "gameType=$GAME_TYPE createdAt=$CREATED_AT gameProxy=$GAME_PROXY" cast call $GAME_PROXY 'rootClaim()(bytes32)' --rpc-url $L1_RPC cast call $GAME_PROXY 'l2SequenceNumber()(uint256)' --rpc-url $L1_RPC ``` * Recompute the super root for the proposed timestamp and confirm it matches the proposal: ```bash theme={null} cast rpc superroot_atTimestamp "$(cast 2h )" \ --rpc-url $SUPER_ROOT_RPC | jq -r '.data.super_root' # Expect: equals rootClaim from above ``` This confirms `op-proposer` is correctly configured and passing valid super roots. ## Verify After the Upgrade Run these checks once the proposer is stable. * **Pre-migration game still resolves.** Pick a still-in-flight pre-migration game (use `op-dispute-mon` dashboards or `gameAtIndex` to find one) and watch its status until it resolves: ```bash theme={null} cast call 'status()(uint8)' --rpc-url $L1_RPC # 0 = IN_PROGRESS, 1 = CHALLENGER_WINS, 2 = DEFENDER_WINS ``` * **`op-challenger` traces `SUPER_CANNON_KONA` when enabled.** On a permissionless chain, verify the startup log lists `super-cannon-kona` and ongoing logs contain no scheduler or game-poll errors as type-9 games appear. On a permissioned chain, `op-challenger` continues to update the `AnchorStateRegistry` when `SUPER_PERMISSIONED` games finalize but does not need to post claims. * **`op-dispute-mon` reports super-root games.** Confirm `op_dispute_mon_games` reports the enabled super game types and `op_dispute_mon_failed_games` remains zero. On a permissioned chain, alert on `op_dispute_mon_games_agreement{status="disagree_defender_wins"}` and `Unexpected game result` logs for `SUPER_PERMISSIONED`. * **No new pre-migration games can be created.** Optionally call `DisputeGameFactory.create` with one of the disabled game types and confirm it reverts. * **Anchor advances on first super-game finalisation.** The first anchor update typically lands \~7 days after the first super-root game is created (game duration plus `DISPUTE_GAME_FINALITY_DELAY_SECONDS`). Do not block the rollout on this — schedule a follow-up to re-run `getAnchorRoot()` after that window and confirm it returns the new game's claim instead of the starting root. Track via `op-dispute-mon` rather than waiting in-line. # EAS contracts and attestation schemas Source: https://docs.optimism.io/governance/attestation-schemas Contract addresses for the Ethereum Attestation Service and the attestation schemas used across the Optimism Collective. This page catalogues the [Ethereum Attestation Service ("EAS")](https://attest.sh/) contract addresses on OP Mainnet and OP Sepolia, the ways to read and write attestations, and the attestation schemas used across the Optimism Collective. For how attestations underpin identity in the Collective, see [How identity works in the Optimism Collective](/governance/eas-attestations). For details on the EAS predeploys themselves, see the [smart contracts overview](/op-stack/protocol/smart-contracts#eas-ethereum-attestation-service). ## EAS contract addresses The [Ethereum Attestation Service](https://docs.attest.sh/docs/welcome) is deployed on these addresses: | **Network** | **Attestation Contract** | **Schema Registry Contract** | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | OP Sepolia | [0x4200000000000000000000000000000000000021](https://sepolia-optimism.etherscan.io/address/0x4200000000000000000000000000000000000021) | [0x4200000000000000000000000000000000000020](https://sepolia-optimism.etherscan.io/address/0x4200000000000000000000000000000000000020) | | OP Mainnet | [0x4200000000000000000000000000000000000021](https://optimistic.etherscan.io/address/0x4200000000000000000000000000000000000021) | [0x4200000000000000000000000000000000000020](https://optimistic.etherscan.io/address/0x4200000000000000000000000000000000000020) | ## How to read and write attestations You can read and write attestations in several ways: * [EAS scan user interface (OP Mainnet)](https://optimism.easscan.org/) * [EAS scan user interface (OP Sepolia)](https://optimism-sepolia.easscan.org/) * [JavaScript SDK](https://docs.attest.sh/docs/developer-tools/eas-sdk) * [Access directly onchain](https://github.com/ethereum-attestation-service/eas-contracts/blob/master/contracts/EAS.sol) (if you need to attest from a smart contract) ## Indexing Indexing is available via: * [GraphQL endpoint](https://docs.attest.sh/docs/developer-tools/api) * [Ponder graph](https://github.com/ethereum-attestation-service/eas-ponder-graph) * [Open source indexer](https://github.com/ethereum-attestation-service/eas-indexing-service) ## Schemas Schemas define the structure and type of data that can be included in an attestation. Below you will find a list of relevant schemas that are being used on OP Mainnet. Schemas are built using the [Ethereum Attestation Service](https://docs.attest.sh/docs/welcome). ### General schemas * [**Gitcoin Passport V1 scores schema UID**](https://optimism.easscan.org/schema/view/0x6ab5d34260fca0cfcf0e76e96d439cace6aa7c3c019d7c4580ed52c6845e9c89): `0x6ab5d34260fca0cfcf0e76e96d439cace6aa7c3c019d7c4580ed52c6845e9c89` * [**Superchain Faucet schema UID**](https://optimism.easscan.org/schema/view/0x98ef220cd2f94de79fbc343ef982bfa8f5b315dec6a08f413680ecb7085624d7): `0x98ef220cd2f94de79fbc343ef982bfa8f5b315dec6a08f413680ecb7085624d7` ### Schemas related to project creation and Retro Funding application [**Project and organization identifier**](https://optimism.easscan.org/schema/view/0xff0b916851c1c5507406cfcaa60e5d549c91b7f642eb74e33b88143cae4b47d0) Used as the unique identifier for projects and organizations created on or after 23 August 2024. For projects created earlier, please see the [archived schemas](#archived-schemas) at the bottom of this page. | **Schema UID** | **`0xff0b916851c1c5507406cfcaa60e5d549c91b7f642eb74e33b88143cae4b47d0`** | | -------------- | --------------------------------------------------------------------------------------------------------------- | | Issuer | Attestations issued as part of Retro Funding sign up are issued by `0xF6872D315CC2E1AfF6abae5dd814fd54755fE97C` | | farcasterID | The Farcaster id of the individual who created the project or organization | | type | "Project" or "Organization" | [**Organization metadata**](https://optimism.easscan.org/schema/view/0xc2b376d1a140287b1fa1519747baae1317cf37e0d27289b86f85aa7cebfd649f) Used to associate metadata to an organization. Re-issued each time there is a change to metadata | **Schema UID** | **`0xc2b376d1a140287b1fa1519747baae1317cf37e0d27289b86f85aa7cebfd649f`** | | -------------- | --------------------------------------------------------------------------------------------------------------- | | Issuer | Attestations issued as part of Retro Funding sign up are issued by `0xF6872D315CC2E1AfF6abae5dd814fd54755fE97C` | | Recipient | Null | | RefUID | The attestation UID of the organization this metadata relates to | | farcasterID | The Farcaster id of the individual who published the organization metadata | | name | The name of the organization | | projects | The array of projects that belong to this organization | | parentOrgUID | The attestation UID of this organization's parent, in case it has one | | metadataType | How the metadata can be accessed. 1 for ipfs, 2 for http | | metadataUrl | The storage location where the metadata can be retrieved | [**Project metadata**](https://optimism.easscan.org/schema/view/0xe035e3fe27a64c8d7291ae54c6e85676addcbc2d179224fe7fc1f7f05a8c6eac) Used to associate metadata to a project. Re-issued each time there is a change to metadata. | **Schema UID** | **`0xe035e3fe27a64c8d7291ae54c6e85676addcbc2d179224fe7fc1f7f05a8c6eac`** | | -------------------- | --------------------------------------------------------------------------------------------------------------- | | Issuer | Attestations issued as part of Retro Funding sign up are issued by `0xF6872D315CC2E1AfF6abae5dd814fd54755fE97C` | | Recipient | Null | | projectRefUID | The attestation UID of the project this metadata relates to | | farcasterID | The Farcaster id of the individual who published the project metadata | | name | The name of the project | | category | The category of the project | | parentProject RefUID | The attestation UID of this project's parent project, in case it has a parent | | metadataType | How the metadata can be accessed. 1 for ipfs, 2 for http | | metadataUrl | The storage location where the metadata can be retrieved | [**Retro funding application**](https://optimism.easscan.org/schema/view/0x2169b74bfcb5d10a6616bbc8931dc1c56f8d1c305319a9eeca77623a991d4b80) Used to identify a project's application to a specific Retro Funding Round. This attestation is used for Retro Funding Round 6 and beyond. | **Schema UID** | **`0x2169b74bfcb5d10a6616bbc8931dc1c56f8d1c305319a9eeca77623a991d4b80`** | | ----------------------- | ---------------------------------------------------------------------------------------------------------------- | | Issuer | Attestations issued as part of Retro Funding sign up are issued by: `0xF6872D315CC2E1AfF6abae5dd814fd54755fE97C` | | Recipient | Null | | round | The round number for which this application was submitted | | metadataType | How the metadata can be accessed. 1 for ipfs, 2 for http | | metadataUrl | The storage location where the metadata can be retrieved | | farcasterID | The individual that submitted this application on behalf of the project. | | metadataSnapshot RefUID | The project metadata at the time the application was submitted. | [**Retro funding application approval/rejection**](https://optimism.easscan.org/schema/view/0x683b1b399d47aabed79c9aa8f2674729021174b6e5cce1e20675eab404fc82d6) Used to identify which Retro Funding applications have been approved or rejected. | **Schema UID** | **`0x683b1b399d47aabed79c9aa8f2674729021174b6e5cce1e20675eab404fc82d6`** | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Issuer | Currently, the Optimism Foundation issues these from the following address: `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F` | | Recipient | Null | | projectApplicationUID | The unique identifier of the projects Retro Funding application. | | Status | The status of the Retro Funding application. | | Reason | Identifier for the reason an application was rejected. 1 = "Duplicate Application", 2 = "Deceiving Badgeholders", 3 = "Spam", 4 = "Not meeting eligibility criteria" | [**Retro funding rewards**](https://optimism.easscan.org/schema/view/0x670ad6e6ffb842d37e050ea6d3a5ab308195c6f584cf2121076067e0d8adde18) Used to identify the reward amount each approved project received in a Retro Funding round | **Schema UID** | **`0x670ad6e6ffb842d37e050ea6d3a5ab308195c6f584cf2121076067e0d8adde18`** | | -------------- | ------------------------------------------------------------------------------------------------------------------------ | | Issuer | Currently, the Optimism Foundation issues these from the following address: `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F` | | Recipient | Null | | refUID | The UID of the Retro Funding application | | projectRefUID | The unique identifier of the project | | round | The retro round for which the project was rewarded | | OPamount | The amount of OP awarded to the project | ### Schemas related to token house grants [**Token house grant approved**](https://optimism.easscan.org/schema/view/0x8aef6b9adab6252367588ad337f304da1c060cc3190f01d7b72c7e512b9bfb38) Issued by the Grants Council when a project is approved for a grant. Does not indicate that the grant has been completed. | **Schema UID** | **`0x8aef6b9adab6252367588ad337f304da1c060cc3190f01d7b72c7e512b9bfb38`** | | ---------------- | --------------------------------------------------------------------------------- | | Issuer | Currently issued by the Grants Council lead. | | Recipient | The address where the tokens will be delivered once the grant has been completed. | | refUID | Currently null | | projectRefUID | The unique identifier of the project that was approved for the grant. | | UserIncentivesOP | The OP amount approved for user incentives. | | BuildersOP | The OP amount approved for the builder. | | Season | The season (number) in which the grant was approved | | Intent | The intent (number) to which the mission belongs | | Mission | The name of the mission (in words) under which this grant was made. | | Approval date | The date the grant was approved, in the following format MM/DD/YYYY | | MetadataUrl | Currently null | ### Schemas related to roles and contributions [**Citizens**](https://optimism.easscan.org/schema/view/0xc35634c4ca8a54dce0a2af61a9a9a5a3067398cb3916b133238c4f6ba721bc8a) Citizen attestations were first issued in Season 6 and are used to represent Citizenship separately from the ability to vote in a specific Retro Round. The resolver contract checks that the issuer is the Foundation with following address `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F` | **Schema UID** | **`0xc35634c4ca8a54dce0a2af61a9a9a5a3067398cb3916b133238c4f6ba721bc8a`** | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | RefUID | In case the Citizen is a chain or an app, the refUID field will reference the organization/project id of the chain or app. If null, the Citizen is an end-user | | FarcasterID | The Citizen's unique identifier | | SelectionMethod | A Code representing the method through which the Citizen was selected. Codes beginning with the number 1 refer to various flavours of Web of Trust selection. | [**Retro funding voters**](https://optimism.easscan.org/schema/view/0x41513aa7b99bfea09d389c74aacedaeb13c28fb748569e9e2400109cbe284ee5) These attestations are voting Badges issued for Retro Round 5 and beyond. They are different from the [previous schema](https://optimism.easscan.org/schema/view/0xfdcfdad2dbe7489e0ce56b260348b7f14e8365a8a325aef9834818c00d46b31b) to include new fields like votingGroup, used to assign voters to sub-categories in the round. | **Schema UID** | **`0x41513aa7b99bfea09d389c74aacedaeb13c28fb748569e9e2400109cbe284ee5`** | | --------------- | -------------------------------------------------------------------------- | | FarcasterID | The voter's unique identifier | | Round | The round number for which this voting Badge was valid | | voterType | Guest or Citizen | | votingGroup | Used to assign voters to subcategories in case the Round has subcategories | | selectionMethod | The method in which this voter was selected | [**MetaGov contribution**](https://optimism.easscan.org/schema/view/0x84260b9102b41041692558a4e0cba6b7e5f9b813be56402c3db820c06dd4a5f1) | **Schema UID** | **`0x84260b9102b41041692558a4e0cba6b7e5f9b813be56402c3db820c06dd4a5f1`** | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Issuer | Currently, the Optimism Foundation issues these from one of the following addresses: `0x621477dBA416E12df7FF0d48E14c4D20DC85D7D9` or `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F`. | | Recipient | The address of the individual who made the contribution | | refUID | The UID of the project, in case this contribution is represented as a project | | FarcasterID | The id of the individual who made the contribution, if known | | Impact | This field is not currently being used | | Season | The season in which the contribution was made | | Decision Module | The decision module to which the contribution relates | | Contribution Type | The type of contribution | | MetadataUrl | This field is not currently being used | [**Foundation mission request completed**](https://optimism.easscan.org/schema/view/0x649cc6df5af7561b66384405a62682c44e2428584d2f17a202ac3ef4506e2457) | **Schema UID** | **`0x649cc6df5af7561b66384405a62682c44e2428584d2f17a202ac3ef4506e2457`** | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Issuer | Currently, the Optimism Foundation issues these from one of the following addresses: `0x621477dBA416E12df7FF0d48E14c4D20DC85D7D9` or `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F`. | | projectRefUID | The UID of the project that represents the work completed as part of the Foundation Mission Request | | OP Amount | The OP Amount that was awarded for the completion of this Mission Request | | Season | The season in which this Mission Request was completed | [**Retro funding governance contribution**](https://optimism.easscan.org/schema/view/0x3743be2afa818ee40304516c153427be55931f238d961af5d98653a93192cdb3) | **Schema UID** | **`0x3743be2afa818ee40304516c153427be55931f238d961af5d98653a93192cdb3`** | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Issuer | Currently, the Optimism Foundation issues these from one of the following addresses: `0x621477dBA416E12df7FF0d48E14c4D20DC85D7D9` or `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F`. | | Recipient | The address of the individual who made the contribution | | Rpgf\_round | The round number for which this contribution was made | | RetroPGF\_Contribution | The type of contribution made | [**Governance contribution**](https://optimism.easscan.org/schema/view/0xef874554718a2afc254b064e5ce9c58c9082fb9f770250499bf406fc112bd315) Issued to those who held governance roles in the Collective, such as Grants Council members. | **Schema UID** | **`0xef874554718a2afc254b064e5ce9c58c9082fb9f770250499bf406fc112bd315`** | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Issuer | Currently, the Optimism Foundation issues these from one of the following addresses: `0x621477dBA416E12df7FF0d48E14c4D20DC85D7D9` or `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F`. | | Recipient | The address of the individual who made the contribution | | govSeason | The season the individual held the role | | govRole | The role held by the individual | ### Archived schemas These schemas are no longer being actively issued, but capture valuable historical data. [**Retro funding application**](https://optimism.easscan.org/schema/view/0x88b62595c76fbcd261710d0930b5f1cc2e56758e155dea537f82bf0baadd9a32) Used to identify a project's application to a specific Retro Funding Round. This attestation was used for Retro Funding Rounds 4 and 5. | **Schema UID** | **`0x88b62595c76fbcd261710d0930b5f1cc2e56758e155dea537f82bf0baadd9a32`** | | ----------------------- | ---------------------------------------------------------------------------------------------------------------- | | Issuer | Attestations issued as part of Retro Funding sign up are issued by: `0xF6872D315CC2E1AfF6abae5dd814fd54755fE97C` | | Recipient | Null | | round | The round number for which this application was submitted | | projectRefUID | The unique identifier of the project that submitted this application | | farcasterID | The individual that submitted this application on behalf of the project. | | metadataSnapshot RefUID | The project metadata at the time the application was submitted. | [**Retro funding badgeholders**](https://optimism.easscan.org/schema/view/0xfdcfdad2dbe7489e0ce56b260348b7f14e8365a8a325aef9834818c00d46b31b) These attestations are considered "voting Badges" and allow an individual to vote in any given iteration of Retro Funding. They were used up to and including Retro Round 4. | **Schema UID** | **`0xfdcfdad2dbe7489e0ce56b260348b7f14e8365a8a325aef9834818c00d46b31b`** | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Issuer | Currently, the Optimism Foundation issues these from one of the following addresses: `0x621477dBA416E12df7FF0d48E14c4D20DC85D7D9` or `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F` | | Recipient | The Badgeholder's address | | rpgfRound | The round number for which this voting Badge was valid | | referredBy | In early rounds, new Badges were issued by referral. This field captures the address of the referrer, if there was one | | referredMethod | If this voting Badge was issued by referral, this field captures the referral method | [**Project identifier**](https://optimism.easscan.org/schema/view/0x7ae9f4adabd9214049df72f58eceffc48c4a69e920882f5b06a6c69a3157e5bd) Used as the unique identifier for projects created in the Collective before 23 August 2024. Attestations issued from this schema prior to 23 August 2024 are still used as the unique identifier for projects. New projects created after 23 August 2024 use the new entity identifier (see above). | **Schema UID** | **`0x7ae9f4adabd9214049df72f58eceffc48c4a69e920882f5b06a6c69a3157e5bd`** | | -------------- | --------------------------------------------------------------------------------------------------------------- | | Issuer | Attestations issued as part of Retro Funding sign up are issued by `0xF6872D315CC2E1AfF6abae5dd814fd54755fE97C` | | Recipient | Null | | farcasterID | The Farcaster id of the individual who created the project | * [**RetroPGF 3 Approved Application schema UID**](https://optimism.easscan.org/schema/view/0xebbf697d5d3ca4b53579917ffc3597fb8d1a85b8c6ca10ec10039709903b9277): `0xebbf697d5d3ca4b53579917ffc3597fb8d1a85b8c6ca10ec10039709903b9277`. Important: Remember to verify the attester address is `0x621477dBA416E12df7FF0d48E14c4D20DC85D7D9` * [**RetroPGF 3 Application schema UID**](https://optimism.easscan.org/schema/view/0x76e98cce95f3ba992c2ee25cef25f756495147608a3da3aa2e5ca43109fe77cc): `0x76e98cce95f3ba992c2ee25cef25f756495147608a3da3aa2e5ca43109fe77cc` * [**RetroPGF 3 Lists schema UID**](https://optimism.easscan.org/schema/view/0x3e3e2172aebb902cf7aa6e1820809c5b469af139e7a4265442b1c22b97c6b2a5): `0x3e3e2172aebb902cf7aa6e1820809c5b469af139e7a4265442b1c22b97c6b2a5` * [**Season 4 Co-grant participant schema UID**](https://optimism.easscan.org/schema/view/0x401a80196f3805c57b00482ae2b575a9f270562b6b6de7711af9837f08fa0faf): `0x401a80196f3805c57b00482ae2b575a9f270562b6b6de7711af9837f08fa0faf`. Important: Remember to verify the attester address is `0x3C7820f2874b665AC7471f84f5cbd6E12871F4cC` or `0x2a0eB7cAE52B68e94FF6ab0bFcf0dF8EeEB624be` * [**Optimist Profile schema UID**](https://optimism.easscan.org/schema/view/0xac4c92fc5c7babed88f78a917cdbcdc1c496a8f4ab2d5b2ec29402736b2cf929): `0xac4c92fc5c7babed88f78a917cdbcdc1c496a8f4ab2d5b2ec29402736b2cf929` # Capital Allocation Source: https://docs.optimism.io/governance/capital-allocation Learn how Optimism allocates capital for long-term success. ## How does Optimism ensure long-term success? Optimism strives to create a sustainable ecosystem flywheel. In this flywheel, revenue contributed by OP Chains to the Optimism Collective funds open-source development and drives ecosystem growth, which strengthens the OP Stack and attracts more end-users, apps, integration partners, and chains. In implementing this flywheel, Optimism uses a public decision making process designed to prevent short-term profit seeking at the expense of the platform, while ensuring organizations contributing the OP Stack remain accountable to tokenholders and customers. This process includes a capital allocation model, designed to avoid many of the common failure modes of corporate governance, aiming to ensure the product always remains at the cutting edge. For more details, please see the [Operating Manual.](https://github.com/ethereum-optimism/OPerating-manual/blob/main/manual.md) capital alloction ## How does Optimism generate revenue? OP Chains in the Superchain earn transaction fees whenever users send transactions onchain, including for payments, trading, identity, and other applications. Each chain also pays costs to publish its activity to Ethereum for security. OP Chains contribute a portion of their revenue to Optimism. This treasury is used to drive growth, provide shared infrastructure, and fund open source contributions that benefit the Superchain. Superchain member chains contribute the greater of: * 15% of net transaction fee profit (transaction fees earned on L2 - costs paid to Ethereum L1), or * 2.5% of gross transaction fees OP Mainnet contributes 100% of its revenue to this shared treasury. You can find more information about revenue in the [Superchain Revenue Explainer documentation](/superchain/superchain-information/superchain-revenue-explainer). The wallets across L1 and OP Mainnet where this revenue sits, along with the Optimism Foundation treasury and grants wallet addresses, are listed under [relevant addresses](/governance/resources#relevant-addresses) on the dashboards, trackers, and addresses page. ## How is the treasury managed? The treasury is currently stewarded by the Foundation, but is subject to oversight by key stakeholder groups, via Optimism's public decision making process. Specifically, tokenholders, chains, apps, and users are asked to oversee annual budgets, which enable the Foundation to deploy the treasury into initiatives aimed at generated the sustainable flywheel described above. Foundation Budget Reports can be found [here](https://gov.optimism.io/c/updates-and-announcements/foundation-budgets/) on the governance forum. The OP Token Unlock (Estimated) tracker is listed under [OP trackers](/governance/resources#op-trackers) on the dashboards, trackers, and addresses page. You can find more information via the Operating Manual [here](https://github.com/ethereum-optimism/OPerating-manual/blob/main/manual.md). ## What is Optimism's commitment to Open Source Software? Optimism has always been committed to funding open-source software. OP Labs, a core contributor to the OP Stack, is registered as a public benefit corporation with a mission to enhance and enshrine access to public goods. The OP Stack is MIT licensed and Optimism dedicates a significant portion of its treasury to funding public goods and open-source software. Optimism operates various grant programs to incentivize and reward open-source contributions. Grant programs can be found via [atlas.optimism.io](http://atlas.optimism.io). ## What can I do with the OP Token? The OP token was created in May of 2022, with an initial supply of 4,294,967,296 OP tokens. The token was launched as a governance token to enable tokenholders to weigh in on technical and economic decisions that impact Optimism, such as protocol upgrades and capital allocation. The Optimism Foundation estimates the total supply of circulating OP tokens to increase as detailed in the [OP Token Unlock (Estimated) tracker](/governance/resources#op-trackers). Tokenholders can use OP to vote on: * Protocol Upgrades * Token Allocations * Adjusting Inflation * Removing the Director of the Optimism Foundation * Dissolutions * Elections (and representative removal) * Protecting the rights of tokenholders by consenting to any changes to the founding documents of the Optimism Foundation, if those changes would materially reduce their rights. * Ratification of Governing Documents You can find full details of what Tokenholders can vote with the Operating Manual [here](https://github.com/ethereum-optimism/OPerating-manual/blob/main/manual.md). You can sign up to vote with your tokens [here](https://vote.optimism.io/delegates). # How identity works in the Optimism Collective Source: https://docs.optimism.io/governance/eas-attestations Learn how the Optimism Collective uses onchain attestations to represent Citizenship, project identity, and governance roles. Optimism governance gives a voice to several distinct stakeholder groups: tokenholders, chains, apps, and end-users. Token House voting power is straightforward to establish — it follows OP token holdings. The rest of the system is harder: the Citizens' House uses a "1 member, 1 vote" model, Retro Funding rewards specific projects for their impact, and elected roles carry responsibilities across Seasons. All of that requires a shared, verifiable answer to the question "who is this participant?" — without handing the answer to a private membership database. The Collective's answer is **attestations**: signed onchain statements, published where anyone can read and verify them. This page explains what attestations are, how the Collective uses them, and why the model works the way it does. ## Attestations and the Ethereum Attestation Service An attestation is an onchain record in which one account (the issuer) makes a structured claim — for example, "this address is a Citizen" or "this project applied to Retro Funding Round 6." Attestations in the Collective are built on the [Ethereum Attestation Service ("EAS")](https://attest.sh/), an open-source public good that is included as a predeploy in the OP Stack. Every OP Stack chain ships with two EAS contracts at fixed addresses: * The **EAS contract** (`0x4200000000000000000000000000000000000021`), where attestations are created and stored. * The **SchemaRegistry contract** (`0x4200000000000000000000000000000000000020`), which holds the schemas that attestations are checked against. Because these are predeploys, the same identity infrastructure is available on OP Mainnet, OP Sepolia, and any other OP Stack chain, with no extra deployment. For predeploy details, see the [smart contracts overview](/op-stack/protocol/smart-contracts#eas-ethereum-attestation-service). ### Schemas give attestations structure A schema defines the structure and type of data that an attestation can carry, and each schema has a unique identifier (UID). This is what makes attestations machine-readable rather than free-form claims: an application that wants to check Citizenship looks for attestations issued against the specific Citizen schema UID, and knows exactly which fields (such as the member's Farcaster ID and selection method) it will find there. The full catalogue of schemas the Collective uses — with their UIDs, issuers, and field-by-field descriptions — is maintained in the [EAS contracts and attestation schemas reference](/governance/attestation-schemas). ### Trust comes from the issuer, not the statement Anyone can issue an attestation, so an attestation on its own proves only that *someone* made a claim. What makes an attestation meaningful is *who issued it*. Citizen attestations, for example, are only valid when issued by the Optimism Foundation, and the schema's resolver contract enforces that check onchain. Other schemas document their expected issuer addresses so that consumers can verify them — several archived schemas explicitly remind readers to verify the attester address before trusting the record. This is the core design trade-off: rather than a closed registry that must be queried and trusted wholesale, the Collective publishes individually signed claims and lets every consumer verify the issuer for themselves. ## How the Collective uses attestations ### Citizenship Membership in the Citizens' House is represented by Citizen attestations, first issued in Season 6. A Citizen attestation identifies the member (by Farcaster ID), records how they were selected, and — for chain and app Citizens — references the organization or project they represent. Citizenship is recorded separately from the ability to vote in any specific Retro Funding round. To learn who is eligible and how to register, see the [governance FAQ](/governance/gov-faq). ### Projects and organizations Projects and organizations in the Collective (as registered in [OP Atlas](https://atlas.optimism.io)) are identified by attestations: an identifier attestation acts as the project's unique ID, and metadata attestations — re-issued each time something changes — associate names, categories, and metadata locations with it. This is how Retro Funding knows which project an application, approval, or reward belongs to. ### Retro Funding and grants The Retro Funding lifecycle is recorded as a chain of attestations: applications to a round, approval or rejection decisions, voting badges for the round's voters, and finally the reward amount each approved project received. Token House grant approvals and governance contributions (such as serving on the Grants Council) are attested in the same way. ### Proof of personhood For end-user Citizens, the Collective relies on external proof-of-personhood systems — [World ID](https://world.org/world-id) and [Passport](https://app.passport.xyz/) — alongside attestations such as Gitcoin Passport scores. Until Sybil-resistance mechanisms are more mature, the Optimism Foundation may suspend Citizens flagged as possible Sybils and request further verification of unique personhood. ## Next steps * Look up contract addresses, schema UIDs, and field definitions in the [EAS contracts and attestation schemas reference](/governance/attestation-schemas). * Read or issue attestations via [EAS scan for OP Mainnet](https://optimism.easscan.org/) or the [EAS SDK](https://docs.attest.sh/docs/developer-tools/eas-sdk). * Learn how the Token House and Citizens' House use these identities in the [governance FAQ](/governance/gov-faq). # Evolution & Experimentation Source: https://docs.optimism.io/governance/evolution-and-experimentation Learn about Optimism's commitment to iterative improvement and experimentation. ## Evolution In our pursuit to design a new type of organization, Optimism's public decision making process has undergone significant evolution since its inception, reflecting Optimism's commitment to iterative improvement and experimentation. Below is a summary of some of the key things we learned along the way. ### Key Stakeholders * We've run multiple experiments to understand who our most engaged stakeholders are and how they participate in our public decision making process. * **Tokenholders:** Anyone who holds OP can vote * We've also run multiple delegation experiments aimed at getting if specific types of tokenholders (protocols, chains, and individual community members) more involved. Our main learning has been that tokenholders need strong incentive alignment to invest time in decision making processes and they want to be involved in low effort, high impact ways. * While our system allows for delegation - whereby tokenholders can assign their votes to someone else to cast on their behalf - over time we've come to believe that delegation disrupts the incentives of token-weighted voting and that voting directly should be heavily encouraged. * Tokenholders are asked to make decisions that would benefit from investor protections * **Users, Apps, and Chains:** You must qualify to be a Citizen * Citizenship started with a small initial group and expanded via a Web of Trust model. This model suffered from in-group dynamics (which were replicated here), resulting in many Citizens that were impacted by the decisions being made. * We later ran targeted experiments to evaluate how community members, chains, and past grant recipients voted, ultimately resulting in our key stakeholder model. Our stakeholder models ensures chains, apps, and end-users are able to influence the decisions that impact them. * Citizens are asked to make decisions that would benefit from consumer protections * We've realized that input from different stakeholders is needed depending on the type of decision being made: * **Preferences**: There is no absolute "right" answer and all stakeholders should have a say * **Prediction**: There is a correct answer, which is only revealed in the future. Experts are best suited to make these decisions. * When “experts” are needed, these decisions are made by Councils and Boards - such as the Developer Advisory Board and Security Council. These Councils and Boards are still ultimately accountable to key stakeholders. * **Measurement**: This is best done objectively, by a computer, when possible, or by experts. ### High Impact Inputs * Different decisions impact each stakeholder group in unique ways. Our approach has evolved from “everyone decides everything” to one that only asks stakeholders to make decisions that directly impact them. * In many cases, a stakeholder doesn't need to make a decision directly, but should still have the ability to veto - or reject - a decision that disadvantages their stakeholder group. * Stakeholders will also be able to express preferences and influence strategy via non-voting processes. * We've outlined the different decisions here: Figma ### The Core Set of Decisions * Governance minimization is a foundational principle of Optimism's collective decision making process. Our evolution has been one of continuously simplifying process, reducing structure, and further refining scope. * We've learned over time that several decisions that used to be made publicly, actually benefit from more centralized decision making (CoCC, CFC, BB.) * We believe the set of decisions that should be made collectively are those that: * Reduce platform risk for customers and users of the protocol * Prevent short-term profit seeking at the long-term expense of the platform * Optimism has always been committed to supporting public goods, but the way we support public goods has evolved greatly over time. We started with a fully public grant making process, which gradually evolved to be more metrics-driven and programmatic approach, requiring less human input. We expect this to be a continued area of evolution and innovation. * Our Decentralization Milestones outlines the remaining steps we hope to take to refine and further decentralize our public decision making process. ## Experimentation Underpinning the learnings outlined above is a culture of experimentation. In our early days, our [iterative approach](https://gov.optimism.io/t/the-path-to-open-metagovernance/7728) sometimes involved a less-scientific, trial-and-error approach. Over time, we've realized a more rigorous, data-driven approach - leveraging controlled trials where possible - allows us to truly understand what works and what doesn't. A sample of our Research & Experiments findings are summarized in the table below. We often collaborate with academics, industry experts, and independent researchers. | **Topic** | **Research question** | **Methods** | **Key Takeaways** | **Write-up** | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Airdrops** | Do airdrops drive prosocial behaviors like delegation? Do they increase retention among new users? | Regression discontinuity design (RDD) | Increased delegation esp among small wallets; Baseline reward increases retention but high activity bonuses decrease retention | - [Did OP Airdrop 2 Increase Governance Engagement?](https://gov.optimism.io/t/did-op-airdrop-2-increase-governance-engagement/7270)
- [Did OP Airdrop 5 Increase User Retention Rates? A Regression Discontinuity Analysis](https://gov.optimism.io/t/did-op-airdrop-5-increase-user-retention-rates-a-regression-discontinuity-analysis/9610) | | **Citizenship** | How do we identify key stakeholders (eg, end users, app devs, or partner chains) and give them decision-making rights? | Voting data analysis, surveys, qualitative interviews | Experts no “better” at values questions but better at assessing impact; Guest voters don’t vote differently to existing set; 3 clear personas | - [Citizenship Learnings 2024](https://gov.optimism.io/t/citizenship-learnings-2024/9563) | | **Deliberation** | How does participating in a deliberative process with direct policy implications change individual attitudes and behaviors? | Randomized experiment, instrumental variable regression | Deliberation increases knowledge and trust; No reduction in polarization when outcome is binding | - [When Is Deliberation Useful for Optimism Governance?](https://gov.optimism.io/t/when-is-deliberation-useful-for-optimism-governance/9142) | | **Futarchy** | Do projects selected via Futarchy see greater increase in TVL than projects selected by existing Grants Council? | Time-series analysis, RDD, analysis of telegram, survey, and trading data | Futarchy grants produced more Superchain TVL after 3 months than Grants Council picks; Predictions notably overpriced; 400+ forecasters participated | - [Futarchy v1 Preliminary Findings](https://gov.optimism.io/t/futarchy-v1-preliminary-findings/10062) | | **Public Goods Funding** | What voting designs lead to impactful grant allocation decisions? Does algorithmic/ metrics-based voting improve outcomes? | Voting data analysis, synthetic control method, surveys, qualitative feedback | Humans are bad at quantification and bias toward even distributions rather than reflecting value; Experts with context make better decisions for OSS; Individual bias about impact vs need is inevitable | - [Retro Funding 4: Learnings and Reflections](https://gov.optimism.io/t/retro-funding-4-learnings-and-reflections/9271)
- [Season 7 Retro Funding - Early Evidence on Developer Tooling Impact](https://gov.optimism.io/t/season-7-retro-funding-early-evidence-on-developer-tooling-impact/10162) | | **Voter mobilization** | Do appeals to civic duty, economic self-interest, collective security, or decision authority increase tokenholder turnout? | Randomized multi-wave experiment | Economic and security (tangible stakes) were most effective in driving turnout; Repeated reminders are necessary to sustain increase in participation; catchy visuals and follow-ups important | - “What Drives Turnout in Digital Governance? Evidence from a Multi-stage Voter Mobilization Experiment among 34,328 Tokenholders” (Draft available upon request: [eliza@optimism.io](mailto:eliza@optimism.io)) | # FAQs Source: https://docs.optimism.io/governance/gov-faq Frequently Asked Questions about how Optimism evolves. All OP tokenholders, a key stakeholder group, are represented in governance via the Token House. The Token House uses token-weighted voting, giving influence proportional to OP token holdings. Tokenholders may vote themselves or assign their voting power to a “delegate.” The primary role of tokenholders is to express their financial interest in the evolution of the Superchain and to hold proposers accountable. Tokenholders may vote on: **Protocol Upgrades** Delegates have the power to veto decisions about protocol upgrades made by the Developer Advisory Board (DAB). This veto power serves as a critical check on technical changes, with the aim of ensuring they align with the interests of those who rely on the protocol. **Capital Allocation** Delegates participate in resource allocation decisions, including: * Approving the Collective Intent, missions, and budget * Approving Governance Fund proposals **Representative Elections** Delegates elect members to the Councils and Boards and/or approve any alternative selection mechanisms **Ratification** Delegates may ratify core governing documents. For a full description of the voting mechanics for each of these proposal types, please refer to the [Operating Manual](https://github.com/ethereum-optimism/OPerating-manual/blob/main/manual.md). In future phases, the Token House may gain additional governance powers. **Unlock Your Voting Power** OP token holders are able to vote on some of the most important decisions for the Collective. This empowers one of the Collective's key stakeholders to have a say in the development of the system. You can either vote yourself with your OP tokens, or you can delegate the voting power of your OP tokens to someone else to make decisions on your behalf. Get started at [vote.optimism.io/delegates](http://vote.optimism.io/delegates) Users, Apps, and Chains, key stakeholder groups, are represented in governance via the Citizens’ House. The Citizens' House uses a ‘1 member, 1 vote’ model, so all members have the same level of influence. The primary role of Citizens is to express their preferences in the evolution of the Superchain and to hold proposers accountable. Citizens may vote on: ### **Protocol Upgrades** Citizens have the power to veto decisions about protocol upgrades made by the Developer Advisory Board (DAB). This veto power serves as a critical check on technical changes, ensuring they align with the interests of those who rely on the protocol. ### **Resource Allocation** Citizens participate in resource allocation decisions, including: * Approving the Collective Intent, missions, and budget ### **Representative Elections** Citizens elect representatives to the Developer Advisory Board, ensuring it remains accountable to their interests. ### **Ratification** Citizens may ratify core governing documents. For a full description of the voting mechanics for each of these proposal types, please refer to the [Operating Manual](https://github.com/ethereum-optimism/OPerating-manual/blob/main/manual.md). In future phases, the Citizens’ House may gain additional governance powers. ## **Eligibility Framework and Principles** The Citizens' House relies on a carefully designed eligibility framework aimed at achieving representation from key stakeholders in the Superchain ecosystem. This framework is built on the following principles: 1.Those who are most impacted by Protocol Upgrades should have governance power over them 2.Those who contribute most to shared resources should have a voice in the governance of those shared resources Eligibility criteria include three distinct stakeholder groups within the Citizens' House: 1.Chains 2.Onchain Applications 3.Superchain End-Users ## **Citizenship Eligibility Criteria** Eligibility is recalculated at the beginning of every Season, and criteria are subject to change. ## **Chain Citizens** ### **Eligibility Criteria in Season 9** Chains are eligible to vote in the Citizens' House if they meet either of these criteria: * Account for at least 2% of the total revenue share contributed by all chains in the past Season * Are among the top 15 chains by revenue contribution in the past Season Eligibility for Season 9 is calculated based on activity from 01 August 2025 - 31 December 2025. This approach aims to give chains with significant economic stake in the ecosystem a voice in governance, while the minimum number of seats (15) should mean broad representation even if revenue becomes concentrated. ## **App Citizens** ### **Eligibility Criteria** Onchain applications are eligible to join the Citizens' House if they meet either of these criteria: * Are responsible for at least 0.5% of the total gas used across the Superchain over the past Season * Are among the top 100 apps by gas usage in the past Season Eligibility for Season 9 is calculated based on activity from 01 August 2025 - 31 December 2025 based on contract data registered by projects in OP Atlas. Projects/contracts not registered in OP Atlas cannot be considered at this time. This approach aims to give applications driving significant activity on the Superchain a voice in governance, while the minimum number of seats (100) should mean broad representation from the application ecosystem. ## **End-user Citizens** ### **Eligibility Criteria** Individual end-users are eligible to join the Citizens' House if they meet all of these criteria: * Had their first Superchain transaction before June 1, 2024 * Have at least 2 Superchain transactions each month in at least 3 distinct months from 01 August 2025 - 31 December 2025 * Can provide proof of personhood through [World ID](https://world.org/world-id) or [Passport](https://app.passport.xyz/) To check the eligibility of your address, navigate to [atlas.optimism.io/citizenship](http://atlas.optimism.io/citizenship) and link the address to your Atlas profile. These criteria are designed so that Citizens will be genuine, active users of the Superchain with sustained engagement over time, rather than one-time or sporadic users. ### **Selection Process** To register as an end-user Citizen, please visit [https://atlas.optimism.io/citizenship](https://atlas.optimism.io/citizenship) Until Sybil-resistance mechanisms are more mature, the Optimism Foundation may suspend Citizens flagged as possible Sybils and request further verification of unique personhood. The Token House and the Citizens' House together represent all key stakeholders of the Superchain: tokenholders, chains, apps, and end-users. Both houses vote on proposals when the interests of all stakeholders should be represented in a particular decision. Each house has a distinct voting mechanism which, when combined together, creates a system of checks and balances aimed at balancing competing interests. Voting happens on a regular schedule via three-week voting cycles. Regular voting Cycles begin on Thursday at 19:00p GMT (12p PST) and end on Wednesday at 19:00 GMT (12p PST). Protocol Upgrades may go through an accelerated process. You can view full details [here](https://github.com/ethereum-optimism/OPerating-manual/blob/main/manual.md). You can track cycles on [the governance calendar](https://calendar.google.com/calendar/u/0/r?cid=Y180aHVpNzBpdG0wODllN3Q4cTUwaGVoMWtub0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t). Key stakeholders of the Superchain can protect their interests by participating in Optimism's public decision making process (governance). This process allows stakeholders to influence the future of the Superchain with limited day-to-day involvement. Key stakeholders will be asked to: * **Vote:** 1-2 times per year * **Provide input:** 3-4 times per year * **Veto:** only as needed Email notifications will be sent to all stakeholders whenever any of the above actions is possible. Stakeholders can also monitor activity directly at [vote.optimism.io](http://vote.optimism.io) or [atlas.optimism.io](http://atlas.optimism.io) **Token House Voters** 1. **Activity:** The social standard for being an active delegate is participating in 70% of all votes. 2. **No self-dealing:** Voters are prohibited from approving and voting on their own proposals. Voters may not vote solely for their own candidacy in an election. In the case of approval/ranked choice elections, optimists may vote for themselves, so long as they also cast votes for the remaining elected positions. 3. **Conflicts of Interest:** Any actual or reasonably anticipated conflicts of interest must be disclosed in writing and prominently displayed ahead of any voting (i.e. when approving proposal drafts, when running for an elected position, when making public recommendations). These guidelines help ensure that the Token House remains active and resistant to capture or manipulation. **Citizens House Voters** To maintain the integrity of the Citizens' House, several important rules govern participation: 1. **No Double Representation**: If you are an admin of a Citizen project or organization, you may not also join the Citizens' House as a Superchain user. 2. **Organization Priority**: An organization and a project under that organization can never both get votes in the Citizens' House. If both are eligible, membership defaults to the organization. 3. **No Multiple Accounts**: It is forbidden to create multiple accounts to attempt to get multiple votes in the Citizens' House as a Superchain user. In Season 8, Citizens will be manually reviewed for possible Sybil activity by the Optimism Foundation. 4. **Seasonal Recalculation**: The eligibility criteria for being a member of the Citizens' House will be recalculated every Season and may change—being a Citizen now doesn't guarantee future Citizens' House membership. These rules help ensure that the Citizens' House remains balanced, representative, and resistant to capture or manipulation. You can view the Code of Conduct [here](https://gov.optimism.io/t/code-of-conduct/5751). Funding public goods is core to Optimism's values and vision for a healthy ecosystem. Retroactive Public Goods Funding (Retro Funding) is an experimental grant program to reward public goods that have created impact in the Optimism ecosystem. Learn more at atlas.optimism.io Identity in the Optimism Collective is built on onchain attestations, created with the [Ethereum Attestation Service ("EAS")](https://attest.sh/) — an open-source public good that is included as a predeploy in the OP Stack. Attestations represent Citizenship, project and organization identity, Retro Funding participation, and governance roles. * For how attestations work and why the Collective uses them, see [How identity works in the Optimism Collective](/governance/eas-attestations). * For EAS contract addresses, how to read and write attestations, and the full schema catalogue, see the [EAS contracts and attestation schemas reference](/governance/attestation-schemas). Relevant governing documents, OP trackers, Foundation budget reports, Retro Funding round results, and Optimism Foundation wallet addresses are collected on the [dashboards, trackers, and addresses](/governance/resources) page, alongside the [Superchain Health Dashboard](https://docs.google.com/spreadsheets/d/1f-uIW_PzlGQ_XFAmsf9FYiUf0N9l_nePwDVrw0D5MXY/edit?gid=584971628#gid=584971628). The Optimism Foundation is a Cayman Islands foundation company. It operates to support the establishment of the Optimism Collective, the development of the Optimism ecosystem, and the technology that powers it. Consistent with the Collective's Working Constitution, the Foundation strives to: * Support the Collective with a formal legal entity, allowing the Foundation to: * Enter into contracts with third parties, such as service providers. * Administer intellectual property rights. * Make required governmental reports and filings. **How does the Foundation work?** The Optimism Foundation is governed by a Board of Directors and a Supervisor. The Board of Directors currently consists of: Abbey Titcomb, Mark Tyneway, Brian Avello, and Jing Wang. The Board's role is to manage the business and affairs of the Foundation. The Supervisor is the Cayman Islands firm, DS Limited. Its role is to oversee the Foundation's directors and ensure the observance of their legal obligations. The Foundation also employs officers, contractors and service providers to execute on its operational and administrative aims. **How is the Foundation held accountable?** As a Cayman Islands foundation company, the Foundation is legally accountable to its governing documentation, which sets up the Foundation to defer to the will of the Optimism Collective and its governance. There are two governance proposal types specifically targeted towards ensuring that the Foundation and its personnel are accountable to the will of the Collective: * **Director removal** - the ability of governance to have a member of the Foundation's Board of Directors removed from service. * **Rights protections** - a blocking vote, which enables governance to veto any proposed change to the Foundation's governing documents that would materially reduce the rights of OP token holders. More information on each of the above proposal types is contained in the [Operating Manual](https://github.com/ethereum-optimism/OPerating-manual). # Protocol Upgrades Source: https://docs.optimism.io/governance/protocol-upgrades Learn how the OP Stack stay up to date with the latest innovations. ## How does the OP Stack stay up to date with the latest innovation? The OP Stack is Optimism's open-source software for deploying next-generation onchain products. The software is licensed under the MIT license, meaning it can be freely used and forked by all parties. The OP Stack has a vibrant core developer community who contribute to the stack, ensuring it reflects the features and values protocol users care about. The Superchain is an ecosystem of chains running on Optimism's OP Stack, featuring some of the world's largest enterprises. Superchain networks benefit from shared security, upgrades and services provided by Optimism. Each chain maintains peak performance with access to innovative new features developed anywhere on the stack, continually strengthening the entire Superchain ecosystem. Chains may also configure components of the OP Stack to fit their regulatory and business needs while still benefiting from shared infrastructure and innovation. Learn more about the best way to build on the OP Stack for your business [here](https://www.optimism.io/compare). ## How are new features added to the OP Stack? OP Labs and external contributors determine the feature roadmap. Based on discussions, protocol upgrades are drafted, which go through the protocol upgrade process. ## What is the protocol upgrade process? The protocol upgrade process is designed to make sure the OP Stack does not change against the interests of the businesses building on the platform. This is a key benefit of crypto systems compared to their centralized alternatives. Platform risk is a common risk of [Web 2 platforms](https://a16zcrypto.com/posts/article/when-is-decentralizing-on-a-blockchain-valuable/) and is a key consideration for the largest partners building on the OP Stack. protocol-upgrade-process Protocol upgrades are drafted by OP Labs or other core contributors to the OP Stack. Before they are implemented, they are reviewed by an independent group of developers (the Developer Advisory Board) to ensure the upgrade is well justified. After a proposal has been reviewed by the Developer Advisory Board, it enters a 7 day veto period. This allows all impacted stakeholders, namely tokenholders, chains, apps, and end-users to override the DAB's decision if they believe an upgrade disadvantages their interests. This is how platform risk is reduced for key stakeholders of the OP Stack. If a proposal is veto'd, it enters an appeals and discussion phase and can be resubmitted. For full details about the protocol upgrade process, please see the [Operating Manual](https://github.com/ethereum-optimism/OPerating-manual/blob/main/manual.md). Overall - contributors, tokenholders, chains, apps, and end-users all have a voice. Checks and balances exist so that no single entity (including OP Labs or the Foundation) can unilaterally dictate the future of the OP Stack. Platform risk is reduced by distributing veto power across stakeholder groups while maintaining an efficient core developer process. This ensures upgrades happen quickly but can be vetoed if they harm key stakeholders. ## How can my chain specifically influence the feature roadmap? Superchain members who contribute revenue back to the Collective are consulted by OP Labs and core developers about the feature roadmap to ensure their voices are heard. All development happens in the open and chains are encouraged to participate and share their perspectives within various research and development repositories. ## How does Optimism help my chain achieve decentralization? Permissionless Fault Proof OP Chains that have their upgrade keys managed by the Optimism Security Council are classified as Stage 1 in [L2Beat's framework](https://l2beat.com/stages). This distributed group delivers the benefit of security scrutinized upgrades that are managed by Optimism. # Dashboards, trackers, and addresses Source: https://docs.optimism.io/governance/resources Key governing documents, trackers, budget reports, and Optimism Foundation wallet addresses in one place. This page collects the governing documents, dashboards, trackers, reports, and addresses referenced throughout Optimism governance. Start with the [Superchain Health Dashboard](https://docs.google.com/spreadsheets/d/1f-uIW_PzlGQ_XFAmsf9FYiUf0N9l_nePwDVrw0D5MXY/edit?gid=584971628#gid=584971628) for an overview of the state of the Superchain. ## Governing documentation * [Operating Manual](https://github.com/ethereum-optimism/OPerating-manual/blob/main/manual.md) * [Working Constitution of the Optimism Collective](https://gov.optimism.io/t/working-constitution-of-the-optimism-collective/55) * [Standard Rollup Charter](https://github.com/ethereum-optimism/OPerating-manual/blob/main/Standard%20Rollup%20Charter.md) * [Law of Chains](https://gov.optimism.io/t/final-law-of-chains-v0-1/) * [Decentralization Milestone Working Model](https://docs.google.com/spreadsheets/d/1IpL0oTd3AgNBu_eWdjP9EjbQfZjq-_Nd3yU1H2ke3vY/edit?gid=0#gid=0) * [Decision Diagram Working Model](https://www.figma.com/board/iXqyKmLJeBeplKpJBHDI7G/PUBLIC%3A-Optimism-Decision-Diagram-Working-Model?node-id=0-1\&node-type=canvas\&t=QLiz1uM1DepwYyHy-0) * [Optimist Expectations](https://gov.optimism.io/t/optimist-expectations/) ## OP trackers * [Optimism GovFund Grants: Public Delivery Tracking](https://docs.google.com/spreadsheets/d/1Ul8iMTsOFUKUmqz6MK0zpgt8Ki8tFtoWKGlwXj-Op34/edit?gid=1179446718#gid=1179446718) * [OP Token Unlock (Estimated)](https://docs.google.com/spreadsheets/d/1qVMhLmmch3s6XSbiBe8hgD4ntMkPIOhc1WrhsYsQc7M/edit?gid=470961921#gid=470961921) ## Foundation budget reports * These can be found [here](https://gov.optimism.io/c/updates-and-announcements/foundation-budgets/) on the governance forum. ## Retroactive Public Goods Funding round results * These can be found [here](https://retrofunding.optimism.io/round/results) on retrofunding.optimism.io. ## Relevant addresses You can find the list of wallets across L1 and OP Mainnet where the Optimism Collective Revenue earned sits [here](https://docs.google.com/spreadsheets/d/1f-uIW_PzlGQ_XFAmsf9FYiUf0N9l_nePwDVrw0D5MXY/edit?gid=155717474#gid=155717474), on the right-hand side of the Collective Contribution page. * OP Treasury Address for Foundation Allocated Budget: `0x2A82Ae142b2e62Cb7D10b55E323ACB1Cab663a26` * This address holds the remaining OP tokens allocated to the Foundation, which the Foundation requires governance approval to access (via annual FND budget proposals). * OP Treasury Address for Foundation Approved Budget: `0x2501c477D0A35545a387Aa4A3EEe4292A9a8B3F0` * This is the Foundation's OP Treasury which is available for the Foundation to utilize as the Foundation's budget granted through the initial token allocation. Transactions from this wallet are typically internal operational movements per the Foundation's needs. * Additional tokens may be moved from `0x2…3a26` to `0x2…B3F0` based on governance approval of budgets. * OP Foundation Grants Wallet: `0x19793c7824Be70ec58BB673CA42D2779d12581BE` * This Foundation wallet is used to make private OP grants. This is topped up from the OP Treasury Foundation Approved Budget wallet `0x2…B3F0` as needed. * OP Foundation Locked Grants Wallet: `0xE4553b743E74dA3424Ac51f8C1E586fd43aE226F` * This Foundation wallet is used to hold OP for one year lockups. This is topped up from the OP Foundation Grants Wallet `0x1…81BE` as needed. ## Optimism governance calendar * You can find a link to the Governance Calendar [here](https://calendar.google.com/calendar/embed?src=c_fnmtguh6noo6qgbni2gperid4k%40group.calendar.google.com\&ctz=Europe%2FBerlin). # OP Stack documentation Source: https://docs.optimism.io/index Build apps on the OP Stack, deploy your own OP Stack chain, run a node, or learn how the protocol works. ## Find your path Build and deploy apps on OP Mainnet and other OP Stack chains. Deploy your first contract, bridge ETH to a testnet, and explore interop. Launch and operate your own OP Stack chain. Deploy the L1 contracts, spin up a sequencer, and run the full stack of services. Run a node on OP Mainnet or any OP Stack chain. Docker-based setups, source builds, monitoring, and troubleshooting. Understand how the OP Stack works - from transaction flow to fault proofs, interop, and more. ## Jump straight to a goal * **Deploy your first smart contract** — [Deploy a contract to OP Sepolia](/app-developers/tutorials/deploy-a-contract) * **Bridge ETH or tokens between L1 and L2** — [Bridging basics](/app-developers/guides/bridging/basics) * **Launch an L2 rollup testnet end to end** — [Create your own L2 rollup](/chain-operators/tutorials/create-l2-rollup) * **Run an OP Mainnet node with Docker** — [Running a node with Docker](/node-operators/tutorials/node-from-docker) * **Understand fault proofs** — [Fault proofs explainer](/op-stack/fault-proofs/explainer) * **Build cross-chain apps with interop** — [Interoperability explainer](/op-stack/interop/explainer) ## Ready to go further? Compare running the stack yourself with OP Enterprise's managed and supported options. Either way, these docs are the reference for what your chain runs. # Consensus client configuration Source: https://docs.optimism.io/node-operators/guides/configuration/consensus-clients Learn how to configure consensus clients (op-node, kona-node) for your OP Stack node. The consensus client (also called the rollup node) builds, relays, and verifies the canonical chain of blocks. This guide covers configuration for the most popular consensus client implementations. Always run your consensus client and execution client in a one-to-one configuration. Don't run multiple execution client instances behind one consensus client, or vice versa. ## Consensus clients Choose the consensus client that best fits your needs: ## op-node configuration [op-node](https://github.com/ethereum-optimism/optimism/tree/develop/op-node) is the reference implementation of the OP Stack consensus client, written in Go. ### Minimal configuration The minimum required flags for running op-node: ```bash theme={null} op-node \ --l1=https://ethereum-rpc-endpoint.example.com \ --l1.beacon=https://ethereum-beacon-endpoint.example.com \ --l2=http://localhost:8551 \ --l2.jwt-secret=/path/to/jwt-secret.txt \ --network=op-mainnet \ --rpc.addr=0.0.0.0 \ --rpc.port=9545 ``` ### Sequencer configuration If you're running a sequencer node, use these additional flags: ```bash theme={null} --rpc.enable-admin \ --sequencer.enabled \ --sequencer.l1-confs=4 \ --p2p.sequencer.key= ``` Keep your sequencer private key secure and never commit it to version control. Use environment variables or secure key management systems in production. ### l2.enginekind Controls op-node's engine-API behavior to match the connected execution client. Supported values: * `reth` — default; for op-reth. * `geth` — for op-geth (*deprecated*, see the [op-geth deprecation notice](/notices/archive/op-geth-deprecation)). The default is `reth`, so op-reth operators do not need to set this flag. Set `--l2.enginekind=geth` only if you are running op-geth. ### Complete reference For all available configuration options, see the [op-node configuration reference](/node-operators/reference/op-node-config). ## kona-node configuration [kona-node](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/bin/node) is an experimental Rust-based implementation of the OP Stack consensus client. kona-node is experimental and may not be production-ready. Use with caution. ### Basic configuration kona-node follows a similar configuration pattern to op-node: ```bash theme={null} kona-node \ --l1-rpc-url=https://ethereum-rpc-endpoint.example.com \ --l2-rpc-url=http://localhost:8551 \ --jwt-secret=/path/to/jwt-secret.txt \ --network=op-mainnet ``` ### Additional resources For more details on kona-node configuration, see: * [kona-node component hub](/op-stack/components/kona-node) * [kona-node CLI reference](/node-operators/kona-node/configuration) * [Run a node with kona-node](/node-operators/kona-node/run/overview) ## JWT secret To communicate with execution client and enable the Engine API, you'll also need to generate a JWT secret file and enable the consensus client's authenticated RPC endpoint. To generate the JWT secret file: ```bash theme={null} openssl rand -hex 32 > jwt-secret.txt ``` # Execution client configuration Source: https://docs.optimism.io/node-operators/guides/configuration/execution-clients Configure op-reth as your OP Stack execution client and migrate off end-of-support op-geth. The execution client provides the EVM runtime and transaction processing for your OP Stack node. **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. Always run your execution client and consensus client in a 1:1 configuration. Don't run multiple execution clients behind one consensus client, or vice versa. ## What a running node needs The execution client is one of three pieces. Before configuring it, make sure you have: 1. **L1 endpoints** for the settlement layer of the chain you are syncing: an L1 execution RPC endpoint and an L1 Beacon API endpoint. Your consensus client reads batch data and blobs from them. 2. **A consensus client**, also called the rollup node: op-node or kona-node. It derives the canonical chain from L1 and drives the execution client over the Engine API. See [Consensus client configuration](/node-operators/guides/configuration/consensus-clients). 3. **An execution client**, configured below. ## Execution clients [op-reth](https://github.com/paradigmxyz/reth) is a Rust-based execution client and the primary supported path for OP Stack nodes going forward. The [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry) chain configurations are compiled into the binary, so registry chains work by name through `--chain` (for example `--chain unichain` or `--chain unichain-sepolia`). ### Install Two supported install paths: * **Docker image**, wired up end to end in [Running a Node With Docker](/node-operators/tutorials/node-from-docker). * **From source.** op-reth lives at `rust/op-reth/` inside the Optimism monorepo and builds with Cargo. Follow [Building and running an OP Stack node from source](/node-operators/tutorials/run-node-from-source), which pins op-node and op-reth to the same coordinated release tag. ### Minimal configuration ```bash theme={null} op-reth node \ --chain optimism \ --rollup.sequencer https://mainnet-sequencer.optimism.io \ --http \ --ws \ --authrpc.port 9551 \ --authrpc.jwtsecret /path/to/jwt.hex ``` ### OP Stack specific flags op-reth's `Rollup` flag group holds the behavior that exists only on OP Stack chains. Two matter to most operators: * `--rollup.sequencer ` (shown above) is the sequencer endpoint that transactions submitted to this node are forwarded to, since the sequencer is what builds blocks. Aliases: `--rollup.sequencer-http`, `--rollup.sequencer-ws`. * `--rollup.disable-tx-pool-gossip` stops the node from gossiping its transaction pool to peers. Omit it on a personal node; set it on a replica you operate as a provider. The rest of the group covers the interop filter, subblocks, and historical RPC. For the full list with the binary's own descriptions, see the [`op-reth node` flag listing](/node-operators/op-reth/cli/op-reth/node), and [Understanding the op-reth CLI](/node-operators/op-reth/cli/overview) for how the flag groups fit together. ### Subblocks To serve pre-confirmed state from a chain that streams [Subblocks](/op-stack/features/subblocks), point op-reth at the chain's WebSocket stream: ```bash theme={null} op-reth node \ --chain optimism \ --rollup.sequencer https://mainnet-sequencer.optimism.io \ --flashblocks-url wss://op-mainnet-fb-ws-pub.optimism.io/ws \ --http \ --ws \ --authrpc.port 9551 \ --authrpc.jwtsecret /path/to/jwt.hex ``` The node then answers requests carrying the `pending` block tag from subblock state, executing each subblock's transactions against its own view of the chain. It does not need the stream's `state_root`, which subblocks leave zeroed. The flag keeps its `flashblocks` spelling; `--websocket-url` is an accepted alias. `--flashblocks-url` on its own is what an ordinary node wants. Leave `--flashblock-consensus` unset: it drives the chain forward from the stream by submitting completed sequences through `engine_newPayload`, which is a specialized topology, not an addition to a normal node following op-node. Enabling it also turns on local state-root computation for the last subblock in each sequence, which an ordinary node has no use for. ### Historical proofs Permissionless chains need \~28 days of historical state for withdrawal proving. Follow the [Running op-reth with Historical Proofs](/node-operators/tutorials/reth-historical-proofs) tutorial to set up the `--proofs-history` (v2) store on op-reth v2.2.3 or later. ### Pruning op-reth defaults to an archive node. To reclaim disk, prune the state and receipt segments and keep block bodies. Body pruning (`--minimal` or `--prune.bodies.distance`) is unsupported and advised against. See [Pruning op-reth](/node-operators/guides/management/archive-node#pruning-op-reth). ### Complete reference * [op-reth configuration reference](/node-operators/reference/op-reth-config) * [op-reth historical proof configuration](/node-operators/reference/op-reth-historical-proof-config) * [reth.rs documentation](https://reth.rs/run/opstack) [Nethermind](https://github.com/NethermindEth/nethermind) is a .NET-based alternative execution client. ### Minimal configuration ```bash theme={null} nethermind \ -c op-mainnet \ --data-dir path/to/data/dir \ --jsonrpc-jwtsecretfile path/to/jwt.hex ``` ### Additional resources * [Nethermind OP Stack documentation](https://docs.nethermind.io/get-started/running-node/l2-networks) * [Nethermind configuration reference](https://docs.nethermind.io/fundamentals/configuration) ## JWT secret The execution client and consensus client communicate over the Engine API using a shared JWT secret: ```bash theme={null} openssl rand -hex 32 > jwt-secret.txt ``` This file must be identical for both your execution client and your consensus client. ## op-geth (legacy, end of support 2026-05-31) **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. [op-geth](https://github.com/ethereum-optimism/op-geth) is a minimal fork of go-ethereum optimized for the OP Stack. Although the Docker image is called `op-geth`, the actual binary is still named `geth` to minimize differences from go-ethereum. See the [op-geth diff viewer](https://op-geth.optimism.io/?utm_source=op-docs\&utm_medium=docs) for details. ### Minimal configuration ```bash theme={null} geth \ --datadir=/data/optimism \ --http \ --http.addr=0.0.0.0 \ --http.port=8545 \ --http.api=eth,net,web3 \ --authrpc.jwtsecret=/path/to/jwt-secret.txt \ --op-network=op-mainnet \ --rollup.sequencerhttp=https://mainnet-sequencer.optimism.io/ \ --rollup.disabletxpoolgossip ``` Defaults: snap sync mode, no WebSocket server, no metrics. ### OP Stack specific flags * `--rollup.sequencerhttp`: HTTP endpoint of the sequencer for transaction submission * `--rollup.disabletxpoolgossip`: Disables transaction pool gossip (for replica nodes) * `--rollup.historicalrpc`: Enables historical RPC endpoint for upgraded networks (OP Mainnet pre-bedrock archive nodes) ### Complete reference The op-geth configuration reference has been retired; see the [op-reth configuration reference](/node-operators/reference/op-reth-config) for the equivalent op-reth flags. # Legacy Geth configuration Source: https://docs.optimism.io/node-operators/guides/configuration/legacy-geth Learn how to configure Legacy Geth for serving historical execution traces on upgraded OP Stack networks. Legacy Geth (`l2geth`) is the old pre-Bedrock OVM client running against a preconfigured data directory. It is required only for upgraded networks like OP Mainnet to serve execution traces and chain data from before the Bedrock upgrade. If you're running a node that had a chain genesis after the Bedrock upgrade, you do not need Legacy Geth. Legacy Geth (`l2geth`) is the pre-Bedrock OVM client and is unrelated to op-geth's deprecation. l2geth is required on OP Mainnet archive nodes regardless of which post-Bedrock execution client you run (op-reth or op-geth). If you need state proofs for post-Bedrock blocks (for example, for withdrawal proving), see the [historical proofs config](/node-operators/reference/op-reth-historical-proof-config) — that's a different feature. ## Do you need Legacy Geth? op-reth routes RPC requests that target pre-Bedrock blocks to Legacy Geth. This includes *historical execution* — methods that need to execute pre-Bedrock transactions, such as `eth_call` and the `debug_trace*` methods — as well as reads of pre-Bedrock block and transaction data, such as `eth_getBlockByNumber` and `eth_getTransactionReceipt`. op-reth serves everything post-Bedrock directly. If you do not need any RPC access to pre-Bedrock blocks, then you do not need to run Legacy Geth at all. For the exact list of RPC methods routed to Legacy Geth, see the [Legacy Geth configuration reference](/node-operators/reference/legacy-geth-config#rpc-methods-routed-to-legacy-geth). ## Setup ### 1. Download the preconfigured data directory Download and extract the Legacy Geth data directory, which is available at [datadirs.optimism.io](https://datadirs.optimism.io). ```bash theme={null} # Download the data directory curl -o legacy-geth-datadir.tar -sL # Extract it tar -xvf legacy-geth-datadir.tar -C /data/legacy-geth ``` ### 2. Configure Legacy Geth Run Legacy Geth with the minimum required configuration: ```bash theme={null} USING_OVM=true \ ETH1_SYNC_SERVICE_ENABLE=false \ RPC_API=eth,rollup,net,web3,debug \ RPC_ADDR=0.0.0.0 \ RPC_CORS_DOMAIN=* \ RPC_ENABLE=true \ RPC_PORT=8545 \ RPC_VHOSTS=* \ geth --datadir /data/legacy-geth ``` It is imperative that you specify the `USING_OVM=true` environment variable. Failing to specify this will cause `l2geth` to return invalid execution traces or panic at startup. The full set of environment variables Legacy Geth accepts, with defaults, is catalogued in the [Legacy Geth configuration reference](/node-operators/reference/legacy-geth-config#environment-variables). ### 3. Configure your execution client to route to Legacy Geth Point your execution client at Legacy Geth with the `--rollup.historicalrpc` flag; op-reth and op-geth accept the same flag (see the [routing-flag reference](/node-operators/reference/legacy-geth-config#execution-client-routing-flag)). ```bash theme={null} op-reth node \ --datadir=/data/optimism \ --rollup.historicalrpc=http://localhost:8545 \ # ... other flags ``` **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. ```bash theme={null} geth \ --datadir=/data/optimism \ --rollup.historicalrpc=http://localhost:8545 \ # ... other flags ``` ## Troubleshooting `l2geth` is based on an old version of geth where trace functionality is unstable. It is no longer maintained and will not be updated. ### Legacy Geth won't start **Problem**: `l2geth` panics or returns errors on startup **Solution**: Ensure `USING_OVM=true` is set in your environment variables ### Invalid execution traces **Problem**: Legacy Geth returns invalid or incorrect trace data **Solution**: Verify that `USING_OVM=true` is set and the data directory is complete and uncorrupted ### Execution client not routing to Legacy Geth **Problem**: Historical execution requests are not being routed to Legacy Geth **Solution**: Check that `--rollup.historicalrpc` is set on your execution client (op-reth or op-geth) with the correct URL to Legacy Geth # Supernode configuration Source: https://docs.optimism.io/node-operators/guides/configuration/supernode Learn how to configure op-supernode to run every chain in an interop dependency set in one process. op-supernode is in active development. This page tracks the [op-supernode/v0.2.2-rc.8](https://github.com/ethereum-optimism/optimism/releases/tag/op-supernode%2Fv0.2.2-rc.8) release candidate and the recommendations may evolve before the stable release. For background on what op-supernode is and why it exists, see the [supernode explainer](/op-stack/interop/supernode). This guide covers the recommended settings and a starter configuration for op-supernode. op-supernode runs every chain in an interop dependency set together as virtual nodes inside one process, sharing the L1 client and beacon-chain plumbing across them. For the end-to-end procedure to stand up a supernode from scratch (build, engine-API wiring, start, verify), see the [supernode setup guide](/node-operators/guides/configuration/supernode-setup). For the complete per-flag catalogue, see the [op-supernode configuration reference](/node-operators/reference/op-supernode-config). ## Recommendations ### Share the JWT secret across virtual nodes with `--vn.all.l2.jwt-secret` Each chain's virtual node needs the JWT secret to authenticate with its execution client over the Engine API. When every chain in the dependency set uses the same secret, set it once at the supernode level and let every virtual node inherit it. To share a single JWT secret across every virtual node, set `--vn.all.l2.jwt-secret=` (or `OP_SUPERNODE_VN_ALL_L2_ENGINE_AUTH`) at the supernode level. This avoids repeating the per-chain `--vn..l2.jwt-secret` line for every chain in `--chains`. Reserve the per-chain form for the case where one chain's execution client needs a different secret; the [configuration reference](/node-operators/reference/op-supernode-config) documents both forms. ### Configure a beacon archiver fallback with `--l1.beacon-fallbacks` Ethereum beacon nodes prune blob sidecars after roughly 18 days. Without an archive fallback configured, a supernode that has been offline past the prune window cannot fetch the blobs it needs to derive missed L1 blocks, and chain containers will stall at the gap. Configure `--l1.beacon-fallbacks` (or `OP_SUPERNODE_L1_BEACON_FALLBACKS`) with one or more beacon-API-compatible archive endpoints. Set them up from the start — once a primary beacon prunes a blob the supernode needs, only an archiver can recover it. The shared beacon client uses the fallbacks transparently when the primary beacon node returns 404 for an expired blob. For options on what to point `--l1.beacon-fallbacks` at — running your own non-pruning beacon, running `blob-archiver`, or using a third-party service — see the [blob archiver guide](/node-operators/guides/management/blobs#configure-a-blob-archiver). ### Configure EL retention for supernode backfill The supernode reads historical block and receipt data from each chain's execution client to backfill initiating-message logs after restarts or extended downtime. ELs that aggressively prune receipts will break the backfill path. Configure each EL to retain at least 7 days of block and receipt history. A full archive is not required — see the [op-reth configuration reference](/node-operators/reference/op-reth-config) for the granular `--prune.*` flags that let you keep block and receipt history without enabling transaction indexing or world-state history. If you also run op-challenger for permissionless fault proofs, the same ELs additionally need historical proofs enabled — see [Running op-reth with Historical Proofs](/node-operators/tutorials/reth-historical-proofs). ### Pair op-supernode with a Light CL fleet For operators running more than a handful of nodes, the deployable pattern is to concentrate the expensive multi-chain derivation work on supernodes and run the rest of the fleet as op-node or kona-node instances in Light CL mode. Each supernode (or HA pool of supernodes) acts as the safe source for a fleet of Light CLs. The fleet points at the supernode's `optimism_syncStatus` RPC over the `--l2.follow.source` flag and inherits its safe and finalized view, while keeping its own unsafe-head progression over P2P. Larger operators often run several such supernode-plus-fleet groups for blast-radius isolation, regional placement, or staged rollouts. See the [specialized op-node topology notice](/notices/specialized-node-topology) for the fleet side of this pattern, and the [supernode explainer](/op-stack/interop/supernode#op-supernode-and-light-cl) for the architecture overview. Set `--disable-p2p=true` on the supernode when the fleet handles unsafe-head P2P gossip on its own. Leave P2P enabled (the default) when the supernode is the only node in the topology. ### Run an HA pool of supernodes behind a consensus-aware proxyd For production reliability, OP Labs recommends running an **HA pool of at least three op-supernode instances** and fronting them with a [consensus-aware `proxyd`](/chain-operators/tools/proxyd#consensus-awareness) configured with the `consensus_aware_consensus_layer` routing strategy. Point the Light CL fleet's `--l2.follow.source` at the proxyd endpoint rather than at a single supernode. This hides individual supernode failures or reorgs from the Light CL fleet and lets the supernode tier roll between releases without downtime. An individual supernode going down inside the HA pool is masked by `proxyd` — Light CLs continue following the surviving instances. If the entire supernode tier becomes unreachable, Light CLs keep advancing the unsafe chain over P2P gossip and resume safe-head tracking automatically once the tier is restored. A single op-supernode is acceptable for evaluation, but treat it as a single point of failure for safe-head progression on every chain it hosts. ## Example configuration This is a minimum viable configuration for an op-supernode acting as a verifier across OP Sepolia and Unichain Sepolia. The example uses environment variables; pass the equivalent `--flag` arguments instead if that fits your deployment better. Fill in the placeholders before starting the binary. The example below assumes a two-chain dependency set of OP Sepolia (chain ID `11155420`) and Unichain Sepolia (chain ID `1301`). For a different dependency set, replace the chain IDs in `OP_SUPERNODE_CHAINS` and add or remove the matching `OP_SUPERNODE_VN__NETWORK` and `OP_SUPERNODE_VN__L2_ENGINE_RPC` pairs for each chain. ```yaml theme={null} # Dependency set and storage OP_SUPERNODE_CHAINS: "11155420,1301" # OP Sepolia + Unichain Sepolia OP_SUPERNODE_DATA_DIR: /var/lib/op-supernode # default is ./datadir # Shared L1 access OP_SUPERNODE_L1_ETH_RPC: OP_SUPERNODE_L1_BEACON: OP_SUPERNODE_L1_BEACON_FALLBACKS: # Shared JWT secret for every virtual node's engine connection OP_SUPERNODE_VN_ALL_L2_ENGINE_AUTH: /etc/op/jwt-secret.txt # Per-chain: chain identity, engine RPC, and engine kind (reth when the chain's EL is op-reth) OP_SUPERNODE_VN_11155420_NETWORK: op-sepolia OP_SUPERNODE_VN_11155420_L2_ENGINE_RPC: OP_SUPERNODE_VN_11155420_L2_ENGINE_KIND: reth OP_SUPERNODE_VN_1301_NETWORK: unichain-sepolia OP_SUPERNODE_VN_1301_L2_ENGINE_RPC: OP_SUPERNODE_VN_1301_L2_ENGINE_KIND: reth # Top-level JSON-RPC server (per-chain namespaces under //) OP_SUPERNODE_RPC_ADDR: 0.0.0.0 OP_SUPERNODE_RPC_PORT: "8545" # Observability OP_SUPERNODE_LOG_LEVEL: info OP_SUPERNODE_METRICS_ENABLED: "true" OP_SUPERNODE_METRICS_ADDR: 0.0.0.0 OP_SUPERNODE_METRICS_PORT: "7300" ``` For chains that are not in op-node's built-in network registry, replace `--vn..network` with `--vn..rollup.config=`. Every flag in the example — and everything else the binary accepts, including P2P, interop verification, JSON-RPC, logging, and metrics options — is catalogued with syntax, examples, and environment-variable names in the [op-supernode configuration reference](/node-operators/reference/op-supernode-config). ## Where to go next * Follow the [supernode setup guide](/node-operators/guides/configuration/supernode-setup) to stand up a supernode from scratch. * Read the [op-supernode configuration reference](/node-operators/reference/op-supernode-config) for the complete flag and environment-variable catalogue. * Read the [interop prep notice](/notices/interop-prep) for the node-operator action checklist for the OP Sepolia and Unichain Sepolia activation. * Read the [supernode explainer](/op-stack/interop/supernode) for what op-supernode is and why it exists. * Read the [specialized op-node topology notice](/notices/specialized-node-topology) for the operator-facing pattern of running Light CL fleets that follow a supernode safe source. * Read the [interop explainer](/op-stack/interop/explainer) for how cross-chain messaging works at the protocol level. * Read the [op-node configuration reference](/node-operators/reference/op-node-config) for the full set of flags available under the `--vn.*` namespace. * See the [op-supernode source](https://github.com/ethereum-optimism/optimism/tree/develop/op-supernode) in the monorepo for implementation detail. # Supernode setup Source: https://docs.optimism.io/node-operators/guides/configuration/supernode-setup Stand up op-supernode end to end - build the binary, wire each chain's engine API, start the process, and verify every chain is syncing. op-supernode is in active development. This page tracks the [op-supernode/v0.2.2-rc.8](https://github.com/ethereum-optimism/optimism/releases/tag/op-supernode%2Fv0.2.2-rc.8) release candidate and the procedure may evolve before the stable release. For background on what op-supernode is and why it exists, see the [supernode explainer](/op-stack/interop/supernode). This guide stands up a single op-supernode process from scratch: build the binary, wire each chain's execution client over the engine API, start the process, and verify that every chain in the dependency set is syncing. At the end, one op-supernode acts as the consensus layer for every chain it hosts, replacing a separate op-node per chain. This page covers getting to a running, verified process. For recommended production settings (beacon archiver fallbacks, execution-client retention, Light CL fleets, and HA pools), continue with the [supernode configuration guide](/node-operators/guides/configuration/supernode). Every flag used below is catalogued in the [op-supernode configuration reference](/node-operators/reference/op-supernode-config). ## Before you start You need: * **One execution client per chain.** Each chain in the dependency set needs its own execution client with the engine API (authrpc) enabled; one execution client cannot back two chains. See the [execution client configuration guide](/node-operators/guides/configuration/execution-clients) for client options, and the [run a node from source tutorial](/node-operators/tutorials/run-node-from-source) for a full execution-client walkthrough. * **L1 endpoints.** An L1 JSON-RPC endpoint with the `eth` namespace enabled and an L1 beacon-node HTTP endpoint, shared by every chain. A beacon archiver fallback is strongly recommended; see [configuring a blob archiver](/node-operators/guides/management/blobs#configuring-a-blob-archiver). * **The chain IDs of every chain the supernode will host.** For chains in op-node's built-in network registry (for example `op-sepolia`, `unichain-sepolia`), the network name is enough. For any other chain, you need a rollup configuration JSON file per chain. ## Build op-supernode The binary is built from the Optimism Monorepo. The build environment is managed through [mise](https://mise.jdx.dev/), which installs the toolchains needed to build the monorepo; see [`mise.toml`](https://github.com/ethereum-optimism/optimism/blob/develop/mise.toml) at the monorepo root. ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git cd optimism git checkout op-supernode/v0.2.2-rc.8 ``` ```bash theme={null} cd op-supernode just op-supernode ``` The binary is written to `op-supernode/bin/op-supernode`. ```bash theme={null} ./bin/op-supernode --version ``` The flag set is generated dynamically from the `--chains` list, so to inspect the full help output for your chains, run `./bin/op-supernode --chains= --help`. ## Create the JWT secret and wire the engine API Each chain's virtual node authenticates to that chain's execution client over the engine API using a shared JWT secret. ```bash theme={null} openssl rand -hex 32 > jwt-secret.txt ``` Start every chain's execution client with its authrpc listening and pointed at the same secret file; for op-reth, `--authrpc.jwtsecret=`. Start the execution clients before the supernode; they simply won't receive blocks until the supernode connects. You will pass each chain's engine-API endpoint (port `8551` by convention) to the supernode as `--vn..l2` in the next section. The supernode side of the secret is a single `--vn.all.l2.jwt-secret=` flag when every execution client shares one secret; use the per-chain `--vn..l2.jwt-secret` form only when a client needs its own. ## Start op-supernode Start the supernode with the list of chain IDs, the shared L1 endpoints, and each chain's network identity and engine-API endpoint. The example below hosts OP Sepolia (chain ID `11155420`) and Unichain Sepolia (chain ID `1301`) with op-reth execution clients. Fill in the placeholders, and add or remove the per-chain `--vn..*` groups to match your dependency set. ```bash theme={null} ./bin/op-supernode \ --chains=11155420,1301 \ --data-dir=/var/lib/op-supernode \ --l1= \ --l1.beacon= \ --l1.beacon-fallbacks= \ --vn.all.l2.jwt-secret=./jwt-secret.txt \ --vn.11155420.network=op-sepolia \ --vn.11155420.l2=http://op-sepolia-el:8551 \ --vn.11155420.l2.enginekind=reth \ --vn.1301.network=unichain-sepolia \ --vn.1301.l2=http://unichain-sepolia-el:8551 \ --vn.1301.l2.enginekind=reth \ --metrics.enabled=true ``` A few notes on the flags: * For a chain that is not in op-node's built-in network registry, replace `--vn..network` with `--vn..rollup.config=`. * The `--vn..l2.enginekind=reth` lines tell the supernode the execution client is op-reth; the default is `geth`, so drop them if you run op-geth. * P2P is enabled by default, with each virtual node's listen port chosen dynamically to avoid collisions. Set `--disable-p2p=true` when other nodes in your topology handle unsafe-head gossip; see [pair op-supernode with a Light CL fleet](/node-operators/guides/configuration/supernode#pair-op-supernode-with-a-light-cl-fleet). * The JSON-RPC server listens on `0.0.0.0:8545` by default (`--rpc.addr` / `--rpc.port`). Like the op-node RPC, it is not meant to be exposed to the public internet. * Every flag has an environment-variable equivalent (`OP_SUPERNODE_*`). The [configuration guide's example configuration](/node-operators/guides/configuration/supernode#example-configuration) shows the same kind of setup in environment-variable form, and the [configuration reference](/node-operators/reference/op-supernode-config) lists the exact name for every flag. ## Verify the supernode is working The heartbeat activity logs a `heartbeat` message every 10 seconds as a basic sign that the process is alive and its activities are running. The `heartbeat_check` method at the RPC root returns a random hex value as a sign of life: ```bash theme={null} curl -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"heartbeat_check","params":[],"id":1}' \ http://localhost:8545/ ``` The `supernode_syncStatus` method at the RPC root returns the per-chain op-node sync status for every hosted chain, plus dependency-set-wide fields: the chain IDs, the highest fully derived and verified L1 block, and the safe, local-safe, and finalized L2 timestamps across the set. ```bash theme={null} curl -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"supernode_syncStatus","params":[],"id":1}' \ http://localhost:8545/ ``` Confirm that every chain ID you configured appears in the response and that the reported heads advance between calls. Each chain's full op-node RPC surface is mounted under a `//` path prefix on the same server, so any [op-node JSON-RPC method](/node-operators/reference/op-node-json-rpc#optimism_syncstatus) works per chain: ```bash theme={null} curl -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"optimism_syncStatus","params":[],"id":1}' \ http://localhost:8545/11155420/ ``` A chain's endpoint becomes available once its chain container has started; requests to a chain ID that is not configured return `404 Not Found`. With `--metrics.enabled=true`, every chain's metrics are fanned into a single Prometheus endpoint at `/metrics` on the metrics port (default `7300`), labeled per chain: ```bash theme={null} curl http://localhost:7300/metrics ``` ## Next steps * Harden the deployment with the [supernode configuration guide](/node-operators/guides/configuration/supernode): beacon archiver fallbacks, execution-client retention for backfill, Light CL fleets, and HA pools behind a consensus-aware proxyd. * Look up any flag in the [op-supernode configuration reference](/node-operators/reference/op-supernode-config). * Read the [supernode explainer](/op-stack/interop/supernode) for what op-supernode is and why it exists. * Read the [interop prep notice](/notices/interop-prep) for the node-operator action checklist for the OP Sepolia and Unichain Sepolia activation. # Running an archive node Source: https://docs.optimism.io/node-operators/guides/management/archive-node Learn how to configure and run an archive node. This guide shows you how to configure your node to run as an archive node. Archive nodes store the complete history of the blockchain, including all historical states. ## Overview Archive nodes maintain the entire state history of the blockchain, allowing you to query any historical state at any block height. This is useful for: * Block explorers that need to provide historical data * Analytics and data analysis applications * Services that need to query historical state * Debugging and auditing purposes Archive nodes use execution-layer sync but configure the execution client to retain all historical state data instead of pruning it. Historical proofs are a lighter-weight alternative to a full archive node when you only need cryptographic state proofs (`eth_getProof`) at historical blocks — the typical case is withdrawal proving and fault proof workloads. If you need historical execution (`eth_call`, `debug_trace*`) or arbitrary historical state queries, you still need a full archive node. See the [historical proofs config](/node-operators/reference/op-reth-historical-proof-config). ## Requirements * **OP Mainnet**: Requires the [bedrock datadir](/node-operators/guides/management/snapshots) * **Other OP Stack networks**: No datadir required * **Storage**: Archive nodes require significantly more disk space than regular nodes (several terabytes for OP Mainnet) * **Sync time**: Archive sync with execution-layer mode is faster than full block-by-block execution ## Configuration Each section below shows the full set of flags needed on both `op-node` and your chosen execution client to run as an archive node. The `op-node` flag `--syncmode=execution-layer` is required in all cases and is not the default — it must be explicitly configured. ### op-reth op-reth retains complete state when run without pruning flags, so the standard op-node + op-reth configuration already produces an archive node. Set on `op-node`: ```shell theme={null} --syncmode=execution-layer ``` Do not pass any `--prune.*` flags to op-reth for a complete archive node. If you don't need complete history and want to reclaim disk, see [Pruning op-reth](#pruning-op-reth) below. ### Nethermind Set on `op-node`: ```shell theme={null} --syncmode=execution-layer ``` Enable archive mode on Nethermind using the archive network configuration: ```shell theme={null} --config op-mainnet_archive ``` Replace `op-mainnet_archive` with the appropriate archive configuration for your network (e.g., `op-sepolia_archive` for OP Sepolia). ### op-geth **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. Set on `op-node`: ```shell theme={null} --syncmode=execution-layer ``` Set on `op-geth`: ```shell theme={null} --syncmode=full --gcmode=archive ``` Both flags are not the default settings and must be explicitly configured. The `--syncmode=full` flag ensures every block is executed, and `--gcmode=archive` disables state pruning. ## Pruning op-reth If you don't need a complete archive node, you can prune op-reth to reclaim disk. The recommended approach prunes state and receipts while keeping every block body. ### Recommended: prune state and receipts, keep block bodies Prune the state and receipt segments and leave block bodies fully intact. Set the same depth on each: ```shell theme={null} --prune.minimum-distance= --prune.receipts.distance= --prune.account-history.distance= --prune.storage-history.distance= ``` Recommended `` (in blocks), matching production: * **`22000`** for sequencer-side nodes — covers the 12h sequencing window (≈ 21,600 blocks at a 2s block time). * **`1296000`** (\~30 days at 2s) for nodes that need more history. ### Pruning block bodies (unsupported) op-node's safe derivation reads the L1-info deposit transaction — the first transaction of every block — from the block body at the head placed [`--syncmode.offset-el-safe`](/node-operators/reference/op-node-config#syncmode-offset-el-safe) behind the tip, and possibly further if restoring a safedb. If that body has been pruned, EL sync fails with `l2 block is missing L1 info deposit tx`. Body pruning is therefore **not supported, and we advise against it** — you run it at your own risk, with no guarantees. It can be made to work if you know what you're doing, subject to one hard requirement: the retained body window must always cover the `--syncmode.offset-el-safe` range. Concretely, set [`--prune.bodies.distance`](/node-operators/op-reth/cli/op-reth/node) (in blocks) comfortably **greater than** the offset converted to blocks (the default `12h` ≈ 21,600 at a 2s block time), with margin for the block-time and offset you actually run. And if you restore a safedb, you also have to take the maximum distance to its head into account. Do not use `--minimal`: it prunes bodies to a fixed 10,064-block window, which is smaller than the default offset and cannot be widened independently. Body pruning is unsupported. If you enable it anyway, `--prune.bodies.distance` must always exceed `--syncmode.offset-el-safe` (in blocks), and additionally the distance to a restoring safedb's head, or execution-layer sync fails with `l2 block is missing L1 info deposit tx`. Prefer pruning only the state and receipt segments above. ## How archive sync works With execution-layer sync mode enabled: 1. **Initial sync**: The node downloads block headers and data through the P2P network 2. **Block execution**: The node executes every block in the chain to build the complete state history 3. **State retention**: Unlike regular nodes, archive nodes never prune historical state data 4. **Faster than legacy**: While still executing all blocks, this is faster than the legacy consensus-layer sync because block data is retrieved via P2P instead of being derived from L1 ## Storage considerations Archive nodes require substantial storage: * **OP Mainnet**: Several terabytes and growing * **Other networks**: Varies by network age and activity * **Growth rate**: Storage requirements increase continuously as new blocks are added * **Recommendation**: Use fast SSD storage for optimal performance ## Next steps * See the [sync modes reference](/node-operators/reference/consensus-layer-sync) for non-archive node sync configuration * See the [Consensus Client Configuration](/node-operators/guides/configuration/consensus-clients) and [Execution Client Configuration](/node-operators/guides/configuration/execution-clients) guides for additional explanation or customization * See the [Snapshots guide](/node-operators/guides/management/snapshots) for information about downloading the bedrock datadir * If you experience difficulty at any stage of this process, please reach out to [developer support](https://github.com/ethereum-optimism/developers/discussions) # Fetch blob data for your node Source: https://docs.optimism.io/node-operators/guides/management/blobs Configure op-node to fetch L1 batcher blob data, including blobs older than the beacon retention window. OP Stack rollups post batch data to L1 as [EIP-4844 blobs](https://eips.ethereum.org/EIPS/eip-4844). To retrieve this data, `op-node` requires access to an L1 beacon endpoint. Run your own beacon node ([Lighthouse](https://lighthouse-book.sigmaprime.io/run_a_node.html), Lodestar, Nimbus, Prysm, or Teku) or use a third-party service like [QuickNode](https://www.quicknode.com/docs/ethereum/eth-v1-beacon-genesis). Pass the beacon endpoint to op-node: ```shell theme={null} --l1.beacon value ($OP_NODE_L1_BEACON) HTTP endpoint Address of L1 Beacon-node. ``` ## Configuring a blob archiver Standard beacon nodes prune blobs after 18 days. If your node is synced within the last 18 days and stays online, the default beacon endpoint is sufficient. You need a blob archiver if either of these is true: * You're syncing a new node from a snapshot or genesis older than 18 days * Your node has been offline for more than 18 days Pass one or more fallback endpoints to op-node: ```shell theme={null} --l1.beacon-fallbacks value ($OP_NODE_L1_BEACON_FALLBACKS) Addresses of L1 Beacon-API compatible HTTP fallback endpoints. Used to fetch blob sidecars not available at the l1.beacon (e.g. expired blobs). ``` `--l1.beacon-fallbacks` was previously called `--l1.beacon-archiver`. The old name still works as an alias, and so does the legacy env var `$OP_NODE_L1_BEACON_ARCHIVER`. Choose one of these options for the archiver endpoint: * **Option 1 — Run a beacon node with blob pruning disabled.** For Lighthouse, set `--prune-blobs=false` and point `--l1.beacon-fallbacks` at it. * **Option 2 — Run a dedicated blob archiver service** such as [base-org/blob-archiver](https://github.com/base-org/blob-archiver), and point `--l1.beacon-fallbacks` at its API endpoint. Lighter weight than running a full no-prune beacon node. * **Option 3 — Use a third-party blob-archiver service.** Useful if you don't want to operate any beacon infrastructure. # Restore a Node From a Snapshot Source: https://docs.optimism.io/node-operators/guides/management/restore-from-snapshot Download, verify, and extract a snapshot into your node's data directory to skip the initial sync. This guide walks you through bootstrapping an OP Stack execution client from a pre-synced snapshot: download it, verify the checksum, extract it into your data directory, and start the node from the snapshot's tip instead of replaying the chain from genesis. For **what** snapshots are available for OP Mainnet and their download links, see the [Snapshots reference page](/op-mainnet/network-information/snapshots). ## When to use a snapshot **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. This guide assumes an `op-reth` node. You don't always need one. With [execution-layer sync](/node-operators/reference/consensus-layer-sync) — `--syncmode=execution-layer` and `--l2.enginekind=reth` on `op-node` — `op-reth` retrieves blocks over the P2P network instead of deriving each one, which makes the initial sync much faster and, on most OP Stack chains, needs no snapshot at all. [Nethermind](https://docs.nethermind.io/get-started/running-node/l2-networks#op-stack) downloads what it needs automatically. Use a snapshot when: * You are running an **archive node**, or otherwise need to trace the entire chain. * You simply want to skip the initial sync entirely: a mature chain's data directory can run to hundreds of gigabytes (OP Mainnet is roughly 700 GB for a full node), and even execution-layer sync takes days from scratch. On **OP Mainnet**, syncing `op-reth` on a fresh data directory is another reason to use a snapshot: it satisfies the [pre-Bedrock state import requirement](/node-operators/op-reth/run/faq/sync-op-mainnet) in one step, even when execution-layer sync is enabled. ## Before you begin * **Disk space**: you temporarily need room for both the compressed archive and the extracted data directory, so plan for roughly twice the snapshot size during the restore, on fast (NVMe-class) storage. * **Tools**: `curl` (or [aria2](https://aria2.github.io/), which can significantly speed up large downloads), `zstd`, and `tar`. * **A stopped client**: never extract into a data directory an execution client is actively using. ## Restore the snapshot Pick a recent snapshot matching your network and client from your chain's snapshot provider. For OP Mainnet, browse the OP Labs managed [Data Directories website](https://datadirs.optimism.io/); the [Snapshots reference page](/op-mainnet/network-information/snapshots) lists the available sources, including third-party providers. Download the archive and check its SHA256 against the value published on the index page: ```bash theme={null} curl -fLO /.tar.zst sha256sum .tar.zst # Linux shasum -a 256 .tar.zst # macOS ``` Don't skip verification — a truncated multi-hundred-gigabyte download is easy to miss and produces a corrupt database. If the node has run before and you want to start clean from the snapshot, stop the execution client and remove (or move aside) the contents of its data directory. Inspect the archive layout first, then extract it into your client's data directory: ```bash theme={null} tar -tf .tar.zst | head -3 mkdir -p tar -I zstd -xvf .tar.zst -C --strip-components=1 ``` `--strip-components=1` removes the top-level wrapping directory inside the tarball. If the inspection shows files already at the archive root, omit it. Use the same path your client is configured with (the `--datadir` flag for `op-reth`). Start the execution client pointed at the restored data directory, then confirm the node reports the snapshot's block height — not `0` — as its latest block: ```bash theme={null} curl -s -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ http://localhost:8545 ``` The node then syncs from the snapshot's tip to the current head, which takes minutes to hours depending on the snapshot's age. Once caught up, you can delete the downloaded `.tar.zst` archive to reclaim disk space. ## Next steps * Running with Docker? The [node-from-docker tutorial](/node-operators/tutorials/node-from-docker#bootstrap-from-a-snapshot) shows this flow with a bind-mounted `op-reth` data directory. * See the [Snapshots reference page](/op-mainnet/network-information/snapshots) for all OP Mainnet download links, including the legacy (pre-Bedrock) data directory for archive nodes. * If you run into problems, check the [node troubleshooting guide](/node-operators/guides/troubleshooting) or reach out to [developer support](https://github.com/ethereum-optimism/developers/discussions). # Node Metrics and Monitoring Source: https://docs.optimism.io/node-operators/guides/monitoring/metrics Learn about the different metrics you can use to monitor the health of your node. The Optimism `op-node` exposes a variety of metrics to help observe the health of the system and debug issues. Metrics are formatted for use with Prometheus and exposed via a metrics endpoint. The default metrics endpoint is `http://localhost:7300/metrics`. To enable metrics, pass the `--metrics.enabled` flag to the `op-node`. You can customize the metrics port and address via the `--metrics.port` and `--metrics.addr` flags, respectively. ## Important metrics To monitor the health of your node, you should monitor the following metrics: * `op_node_default_refs_number`: This metric represents the `op-node`'s current L1/L2 reference block number for different sync types. If it stops increasing, it means that the node is not syncing. If it goes backwards, it means your node is reorging. * `op_node_default_peer_count`: This metric represents how many peers the `op-node` is connected to. Without peers, the `op-node` cannot sync unsafe blocks and your node will lag behind the sequencer as it will fall back to syncing purely from L1. * `op_node_default_rpc_client_request_duration_seconds`: This metric measures the latency of RPC requests initiated by the `op-node`. This metric is important when debugging sync performance, as it will reveal which specific RPC calls are slowing down sync. This metric exposes one timeseries per RPC method. The most important RPC methods to monitor are: * `engine_forkChoiceUpdatedV1`, `engine_getPayloadV1`, and `engine_newPayloadV1`: These methods are used to execute blocks on `op-geth`. If these methods are slow, it means that sync time is bottlenecked by either `op-geth` itself or your connection to it. * `eth_getBlockByHash`, `eth_getTransactionReceipt`, and `eth_getBlockByNumber`: These methods are used by the `op-node` to fetch transaction data from L1. If these methods are slow, it means that sync time is bottlenecked by your L1 RPC. ## Available metrics A complete list of available metrics is below: | METRIC | DESCRIPTION | LABELS | TYPE | | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------ | --------- | | op\_node\_default\_info | Pseudo-metric tracking version and config info | version | gauge | | op\_node\_default\_up | 1 if the op node has finished starting up | | gauge | | op\_node\_default\_rpc\_server\_requests\_total | Total requests to the RPC server | method | counter | | op\_node\_default\_rpc\_server\_request\_duration\_seconds | Histogram of RPC server request durations | method | histogram | | op\_node\_default\_rpc\_client\_requests\_total | Total RPC requests initiated by the opnode's RPC client | method | counter | | op\_node\_default\_rpc\_client\_request\_duration\_seconds | Histogram of RPC client request durations | method | histogram | | op\_node\_default\_rpc\_client\_responses\_total | Total RPC request responses received by the opnode's RPC client | method,error | counter | | op\_node\_default\_l1\_source\_cache\_size | L1 Source cache size | type | gauge | | op\_node\_default\_l1\_source\_cache\_get | L1 Source cache lookups, hitting or not | type,hit | counter | | op\_node\_default\_l1\_source\_cache\_add | L1 Source cache additions, evicting previous values or not | type,evicted | counter | | op\_node\_default\_l2\_source\_cache\_size | L2 Source cache size | type | gauge | | op\_node\_default\_l2\_source\_cache\_get | L2 Source cache lookups, hitting or not | type,hit | counter | | op\_node\_default\_l2\_source\_cache\_add | L2 Source cache additions, evicting previous values or not | type,evicted | counter | | op\_node\_default\_derivation\_idle | 1 if the derivation pipeline is idle | | gauge | | op\_node\_default\_pipeline\_resets\_total | Count of derivation pipeline resets events | | counter | | op\_node\_default\_last\_pipeline\_resets\_unix | Timestamp of last derivation pipeline resets event | | gauge | | op\_node\_default\_unsafe\_payloads\_total | Count of unsafe payloads events | | counter | | op\_node\_default\_last\_unsafe\_payloads\_unix | Timestamp of last unsafe payloads event | | gauge | | op\_node\_default\_derivation\_errors\_total | Count of derivation errors events | | counter | | op\_node\_default\_last\_derivation\_errors\_unix | Timestamp of last derivation errors event | | gauge | | op\_node\_default\_sequencing\_errors\_total | Count of sequencing errors events | | counter | | op\_node\_default\_last\_sequencing\_errors\_unix | Timestamp of last sequencing errors event | | gauge | | op\_node\_default\_publishing\_errors\_total | Count of p2p publishing errors events | | counter | | op\_node\_default\_last\_publishing\_errors\_unix | Timestamp of last p2p publishing errors event | | gauge | | op\_node\_default\_unsafe\_payloads\_buffer\_len | Number of buffered L2 unsafe payloads | | gauge | | op\_node\_default\_unsafe\_payloads\_buffer\_mem\_size | Total estimated memory size of buffered L2 unsafe payloads | | gauge | | op\_node\_default\_refs\_number | Gauge representing the different L1/L2 reference block numbers | layer,type | gauge | | op\_node\_default\_refs\_time | Gauge representing the different L1/L2 reference block timestamps | layer,type | gauge | | op\_node\_default\_refs\_hash | Gauge representing the different L1/L2 reference block hashes truncated to float values | layer,type | gauge | | op\_node\_default\_refs\_seqnr | Gauge representing the different L2 reference sequence numbers | type | gauge | | op\_node\_default\_refs\_latency | Gauge representing the different L1/L2 reference block timestamps minus current time, in seconds | layer,type | gauge | | op\_node\_default\_l1\_reorg\_depth | Histogram of L1 Reorg Depths | | histogram | | op\_node\_default\_transactions\_sequenced\_total | Count of total transactions sequenced | | gauge | | op\_node\_default\_p2p\_peer\_count | Count of currently connected p2p peers | | gauge | | op\_node\_default\_p2p\_stream\_count | Count of currently connected p2p streams | | gauge | | op\_node\_default\_p2p\_gossip\_events\_total | Count of gossip events by type | type | counter | | op\_node\_default\_p2p\_bandwidth\_bytes\_total | P2P bandwidth by direction | direction | gauge | | op\_node\_default\_sequencer\_building\_diff\_seconds | Histogram of Sequencer building time, minus block time | | histogram | | op\_node\_default\_sequencer\_building\_diff\_total | Number of sequencer block building jobs | | counter | | op\_node\_default\_sequencer\_sealing\_seconds | Histogram of Sequencer block sealing time | | histogram | | op\_node\_default\_sequencer\_sealing\_total | Number of sequencer block sealing jobs | | counter | # Node Troubleshooting Source: https://docs.optimism.io/node-operators/guides/troubleshooting Learn solutions to common problems to troubleshoot your node. This page lists common troubleshooting scenarios and solutions for node operators. ## 401 Unauthorized: Signature Invalid If you see a log that looks like this in `op-node`: ``` WARN [12-13|15:53:20.263] Derivation process temporary error attempts=80 err="stage 0 failed resetting: temp: failed to find the L2 Heads to start from: failed to fetch current L2 forkchoice state: failed to find the finalized L2 block: failed to determine L2BlockRef of finalized, could not get payload: 401 Unauthorized: signature is invalid ``` It means that the `op-node` is unable to authenticate with `execution client`'s authenticated RPC using the JWT secret. ### Solution 1. Check that the JWT secret is correct in both services. 2. Check that `execution client`'s authenticated RPC is enabled, and that the URL is correct. ## Failed to Load P2P Config If you see a log that looks like this in `op-node`: ``` CRIT [12-13|13:46:21.386] Application failed message="failed to load p2p config: failed to load p2p discovery options: failed to open discovery db: mkdir /p2p: permission denied" ``` It means that the `op-node` lacks write access to the P2P discovery or peerstore directories. ### Solution 1. Make sure that the `op-node` has write access to the P2P directory. By default, this is `/p2p`. 2. Set the P2P directory to somewhere the `op-node` can access via the `--p2p.discovery.path` and `--p2p.peerstore.path` parameters. 3. Set the discovery path to `memory` to disable persistence via the `--p2p.discovery.path` and `--p2p.peerstore.path` parameters. ## Wrong Chain If you see a log that looks like this in `op-node`: ``` {"attempts":183,"err":"stage 0 failed resetting: temp: failed to find the L2 Heads to start from: wrong chain L1: genesis: 0x4104895a540d87127ff11eef0d51d8f63ce00a6fc211db751a45a4b3a61a9c83:8106656, got 0x12e2c18a3ac50f74d3dd3c0ed7cb751cc924c2985de3dfed44080e683954f1dd:8106656","lvl":"warn","msg":"Derivation process temporary error","t":"2022-12-13T23:31:37.855253213Z"} ``` It means that the `op-node` is pointing to the wrong chain. ### Solution 1. Verify that the `op-node`'s L1 URL is pointing to the correct L1 for the given network. 2. Verify that the `op-node`'s rollup config/`--network` parameter is set to the correct network. 3. Verify that the `op-node`'s L2 URL is pointing to the correct instance of `execution client`, and that `execution client` is properly initialized for the given network. ## Error: `eth_sendRawTransaction` Does Not Exist If an RPC call to your execution client (`op-reth`, Nethermind, etc.) returns a response like: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "error": { "code": -32601, "message": "the method eth_sendRawTransaction does not exist/is not available" } } ``` This `-32601` JSON-RPC error means the sequencer endpoint you configured does not expose `eth_sendRawTransaction`. The request path looks like: ``` Client → eth_sendRawTransaction → execution client:8545 ↓ EL forwards to sequencer (--rollup.sequencer URL) ↓ eth_sendRawTransaction → op-node:8547 ↓ ❌ ERROR: "method does not exist/is not available" (op-node has no eth namespace!) ``` Because `op-node` only exposes rollup-specific RPC methods—there is no `eth_*` namespace—it cannot accept raw transaction submissions. When your execution client forwards the transaction to an `op-node` URL it immediately fails with `-32601`. This situation almost always happens when op-reth's `--rollup.sequencer` (aliases `--rollup.sequencer-http`, `--rollup.sequencer-ws`) is misconfigured to point at your own `op-node` rather than the chain's actual sequencer. ### Solution 1. Confirm op-reth exposes the `eth` namespace on its HTTP API (the standard set is `--http.api=eth,net,web3,debug`). If `eth` is disabled, raw transactions will be rejected before they reach the sequencer. 2. Inspect the CLI flags and environment variables of every component that talks to the sequencer (`op-node`, `op-reth`, `op-batcher`, `op-proposer`, scripts). The `--rollup.sequencer` flag must point to the chain's public sequencer endpoint (for example, `https://mainnet-sequencer.optimism.io`), **not** to your own `op-node`. 3. For user-deployed L2s where you run the sequencer yourself, leave `--rollup.sequencer` unset so op-reth forwards locally and never falls back to an `op-node` endpoint. 4. Restart the affected services after correcting the flag so they pick up the new endpoint. The error should disappear as soon as they can reach the proper sequencer RPC. ## Unclean Shutdowns An unclean shutdown occurs when the execution client stops without completing its normal shutdown procedure — for example, a `SIGKILL`, a power loss, or a container killed past its grace period. The impact depends on which database backend your EL uses. To minimize risk, always shut down gracefully: `Ctrl-C` for foreground processes, `docker stop -t 300 ` for Docker, or `systemctl stop` for systemd (override the default 90s timeout if your EL has a large in-memory write to flush). ### For op-reth op-reth uses MDBX, which is crash-safe by design. After an unclean shutdown the node typically restarts cleanly with no operator intervention required. If startup fails after an unclean shutdown, options include: * **Stage unwind** — roll back to the last consistent stage checkpoint: ```bash theme={null} op-reth stage unwind to-block --datadir= ``` * **Full resync** — as a last resort, delete the datadir and resync from genesis or a [snapshot](https://datadirs.optimism.io/). ### For Nethermind Unclean shutdowns in `Nethermind` can lead to database corruption. This typically happens when: * The node experiences hardware failures (disk failures, memory errors, overheating) * Power cuts cause abrupt shutdowns * The process is terminated without proper cleanup **Solutions** 1. **Lock File Issues** If `Nethermind` complains about lock files after an unclean shutdown, run: ```bash theme={null} find /path/to/nethermind_db -type f -name 'LOCK' -delete ``` 2. **Block Checksum Mismatch** If you encounter block checksum mismatch errors, you can enable direct I/O: ```bash theme={null} --Db.UseDirectIoForFlushAndCompactions true ``` Note: This may impact performance. 3. **Complete Resync** In cases of severe corruption, a full resync is recommended: ```bash theme={null} sudo systemctl stop nethermind sudo rm -rf /path/to/nethermind_db/mainnet sudo systemctl start nethermind ``` # Kona Node CLI Reference Source: https://docs.optimism.io/node-operators/kona-node/configuration Reference for all kona-node CLI flags and environment variables, grouped by category, plus default ports and default runtime behavior. This document lists all CLI flags for the `kona-node node` subcommand, grouped by category. All flags can be provided as command-line arguments or via environment variables. For more details on each flag, see the inline help (`kona-node node --help`) or the source code. ## Default Ports | Service | Default Port | Flag/Env | | ------------- | ------------ | ---------------------------------------------------- | | RPC HTTP | 9545 | `--port` / `KONA_NODE_RPC_PORT` | | RPC WebSocket | 9545 | (same as HTTP, enabled with `--rpc.ws-enabled`) | | P2P TCP | 9222 | `--p2p.listen.tcp` / `KONA_NODE_P2P_LISTEN_TCP_PORT` | | P2P UDP | 9223 | `--p2p.listen.udp` / `KONA_NODE_P2P_LISTEN_UDP_PORT` | `kona-node` does not run a supervisor RPC server: the binary has no `--supervisor.*` flag group. Its only interop flag, `--interop.dependency-set` (`KONA_NODE_INTEROP_DEPENDENCY_SET`), takes a path to a dependency-set JSON file rather than a port. `--conductor.rpc` (`KONA_NODE_CONDUCTOR_RPC`) is not a listening port either. It is the RPC endpoint URL of an external conductor service that the node dials out to, and it has no default value. Supplying it enables the conductor integration when the node runs in sequencer mode (`--mode sequencer`); in validator mode it has no effect. ## Core Node Arguments | Flag | Env | Description | Required | Default | | ----------------------------------------------- | --------------------------------------------- | --------------------------------------------------------------------------- | -------- | ----------- | | `--mode ` | `KONA_NODE_MODE` | Mode of operation for the node | No | `validator` | | `--l1-eth-rpc ` | `KONA_NODE_L1_ETH_RPC` | URL of the L1 execution client RPC API | Yes | - | | `--l1-trust-rpc ` | `KONA_NODE_L1_TRUST_RPC` | Whether to trust the L1 RPC without verification | No | `true` | | `--l1-beacon ` | `KONA_NODE_L1_BEACON` | URL of the L1 beacon API | Yes | - | | `--l2-engine-rpc ` | `KONA_NODE_L2_ENGINE_RPC` | URL of the engine API endpoint of an L2 execution client | Yes | - | | `--l2-trust-rpc ` | `KONA_NODE_L2_TRUST_RPC` | Whether to trust the L2 RPC without verification | No | `true` | | `--l2-engine-jwt-secret ` | `KONA_NODE_L2_ENGINE_AUTH` | Path to file containing the hex-encoded JWT secret for the execution client | No | - | | `--l2-config-file ` | `KONA_NODE_ROLLUP_CONFIG` | Path to a custom L2 rollup configuration file | No | - | | `--l1-runtime-config-reload-interval ` | `KONA_NODE_L1_RUNTIME_CONFIG_RELOAD_INTERVAL` | Poll interval for reloading runtime config | No | `600` | ## Global Arguments | Flag | Env | Description | Required | Default | | ------------------------------------------- | ----------------------- | -------------------------------------------- | -------- | --------------- | | `--l2-chain-id ` or `-c ` | `KONA_NODE_L2_CHAIN_ID` | L2 chain ID (numeric) or chain name (string) | No | `10` (Optimism) | ### Chain ID Support The `--l2-chain-id` flag supports flexible chain identification using the `alloy_chains` crate: **Numeric Chain IDs:** ```bash theme={null} kona-node --l2-chain-id 10 node [args...] # Optimism mainnet kona-node --l2-chain-id 8453 node [args...] # Base mainnet kona-node --l2-chain-id 1 node [args...] # Ethereum mainnet ``` **String Chain Names:** ```bash theme={null} kona-node --l2-chain-id optimism node [args...] kona-node --l2-chain-id base node [args...] kona-node --l2-chain-id mainnet node [args...] ``` **Short Flag and Environment Variable:** ```bash theme={null} kona-node -c optimism node [args...] export KONA_NODE_L2_CHAIN_ID=optimism && kona-node node [args...] ``` Supported chain names include all those recognized by `alloy_chains` (e.g., `optimism`, `base`, `mainnet`). Unknown numeric chain IDs are accepted for custom networks. ## P2P Arguments | Flag | Env | Description | Default | | ------------------------------------- | ------------------------------------ | --------------------------------------------------- | --------- | | `--p2p.no-discovery` | `KONA_NODE_P2P_NO_DISCOVERY` | Disable Discv5 (node discovery) | `false` | | `--p2p.priv.path ` | `KONA_NODE_P2P_PRIV_PATH` | Path to hex-encoded 32-byte private key for peer ID | - | | `--p2p.priv.raw ` | `KONA_NODE_P2P_PRIV_RAW` | Hex-encoded 32-byte private key for peer ID | - | | `--p2p.advertise.ip ` | `KONA_NODE_P2P_ADVERTISE_IP` | IP to advertise to external peers | - | | `--p2p.advertise.tcp ` | `KONA_NODE_P2P_ADVERTISE_TCP_PORT` | TCP port to advertise | `0` | | `--p2p.advertise.udp ` | `KONA_NODE_P2P_ADVERTISE_UDP_PORT` | UDP port to advertise | `0` | | `--p2p.listen.ip ` | `KONA_NODE_P2P_LISTEN_IP` | IP to bind LibP2P/Discv5 to | `0.0.0.0` | | `--p2p.listen.tcp ` | `KONA_NODE_P2P_LISTEN_TCP_PORT` | TCP port to bind LibP2P to | `9222` | | `--p2p.listen.udp ` | `KONA_NODE_P2P_LISTEN_UDP_PORT` | UDP port to bind Discv5 to | `9223` | | `--p2p.peers.lo ` | `KONA_NODE_P2P_PEERS_LO` | Low-tide peer count | `20` | | `--p2p.peers.hi ` | `KONA_NODE_P2P_PEERS_HI` | High-tide peer count | `30` | | `--p2p.peers.grace ` | `KONA_NODE_P2P_PEERS_GRACE` | Grace period for new peers | `30` | | `--p2p.gossip.mesh.d ` | `KONA_NODE_P2P_GOSSIP_MESH_D` | GossipSub mesh target count | `8` | | `--p2p.gossip.mesh.lo ` | `KONA_NODE_P2P_GOSSIP_MESH_DLO` | GossipSub mesh low watermark | `6` | | `--p2p.gossip.mesh.dhi ` | `KONA_NODE_P2P_GOSSIP_MESH_DHI` | GossipSub mesh high watermark | `12` | | `--p2p.gossip.mesh.dlazy ` | `KONA_NODE_P2P_GOSSIP_MESH_DLAZY` | GossipSub gossip target | `6` | | `--p2p.gossip.mesh.floodpublish` | `KONA_NODE_P2P_GOSSIP_FLOOD_PUBLISH` | Publish to all known peers | `false` | | `--p2p.scoring ` | `KONA_NODE_P2P_SCORING` | Peer scoring strategy | `light` | | `--p2p.ban.peers` | `KONA_NODE_P2P_BAN_PEERS` | Enable peer banning | `false` | | `--p2p.ban.threshold ` | `KONA_NODE_P2P_BAN_THRESHOLD` | Ban threshold | `-100` | | `--p2p.ban.duration ` | `KONA_NODE_P2P_BAN_DURATION` | Ban duration | `60` | | `--p2p.discovery.interval ` | `KONA_NODE_P2P_DISCOVERY_INTERVAL` | Peer discovery interval | `5` | | `--p2p.bootstore ` | `KONA_NODE_P2P_BOOTSTORE` | Directory to store the bootstore | - | | `--p2p.redial ` | `KONA_NODE_P2P_REDIAL` | Peer redialing threshold | `500` | | `--p2p.redial.period ` | `KONA_NODE_P2P_REDIAL_PERIOD` | Peer dial period | `60` | | `--p2p.bootnodes ` | `KONA_NODE_P2P_BOOTNODES` | List of bootnode ENRs | - | | `--p2p.topic-scoring` | `KONA_NODE_P2P_TOPIC_SCORING` | Enable topic scoring | `false` | | `--p2p.discovery.randomize ` | `KONA_NODE_P2P_DISCOVERY_RANDOMIZE` | Remove random peers from discovery | - | ## RPC Arguments | Flag | Env | Description | Default | | -------------------------- | ---------------------------- | ------------------------------------- | --------- | | `--rpc.disabled` | `KONA_NODE_RPC_DISABLED` | Disable the RPC server | `false` | | `--rpc.no-restart` | `KONA_NODE_RPC_NO_RESTART` | Prevent RPC server from restarting | `false` | | `--rpc.addr ` | `KONA_NODE_RPC_ADDR` | RPC listening address | `0.0.0.0` | | `--port ` | `KONA_NODE_RPC_PORT` | RPC listening port | `9545` | | `--rpc.enable-admin` | `KONA_NODE_RPC_ENABLE_ADMIN` | Enable the admin API | `false` | | `--rpc.admin-state ` | `KONA_NODE_RPC_ADMIN_STATE` | File path for admin state persistence | - | | `--rpc.ws-enabled` | `KONA_NODE_RPC_WS_ENABLED` | Enable websocket RPC server | `false` | ## Sequencer Arguments | Flag | Env | Description | Default | | ----------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | `--sequencer.stopped` | `KONA_NODE_SEQUENCER_STOPPED` | Start sequencer in stopped state | `false` | | `--sequencer.max-safe-lag ` | `KONA_NODE_SEQUENCER_MAX_SAFE_LAG` | Max L2 safe/unsafe lag | `0` | | `--sequencer.l1-confs ` | `KONA_NODE_SEQUENCER_L1_CONFS` | L1 block confirmations for sequencer | `4` | | `--sequencer.recover` | `KONA_NODE_SEQUENCER_RECOVER` | Strictly prepare next L1 origin and create empty L2 blocks | `false` | | `--conductor.rpc ` | `KONA_NODE_CONDUCTOR_RPC` | RPC endpoint URL of an external conductor service. Supplying it enables the conductor integration in sequencer mode; it has no effect in validator mode. | - | | `--conductor.rpc.timeout ` | `KONA_NODE_CONDUCTOR_RPC_TIMEOUT` | Conductor service RPC timeout | `1` | ## Interop Arguments | Flag | Env | Description | Default | | --------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------- | | `--interop.dependency-set ` | `KONA_NODE_INTEROP_DEPENDENCY_SET` | Path to the JSON file describing the interop dependency set for this chain. Required when the rollup config schedules the Lagoon hardfork. | - | `kona-node` does not run a supervisor RPC server, so there is no `--supervisor.*` flag group. `--interop.dependency-set` is the node's only interop flag. ## RPC Trust Flags The `--l1-trust-rpc` and `--l2-trust-rpc` flags control whether Kona verifies the block hashes of RPC responses. For guidance on when to disable trust and worked examples for trusted, untrusted, and mixed provider setups, see [configure RPC trust](/node-operators/kona-node/run/rpc-trust). ## Default Behavior Unless overridden by the flags above, a `kona-node node` run has the following defaults: * The P2P stack is spun up. The libp2p swarm listens on TCP `9222` to receive block gossip. The `discv5` discovery service runs on UDP port `9223`. Peer scoring is enabled. * An RPC server is exposed at `0.0.0.0:9545`. Websocket connections are disabled by default. * Prometheus metrics are disabled. Enable them with the `--metrics.enabled` flag; metrics are then served on `0.0.0.0:9090`, configurable via the `--metrics.port` and `--metrics.addr` flags. ## Rollup Configuration Loading If a file path to a rollup config is *not* specified via the `--l2-config-file` cli flag, the Rollup Config will be loaded via the [superchain registry][scr]. A custom rollup config can either be specified through the `--l2-config-file` flag, or specific values may be overridden using a set of override flags provided by the `kona-node`. Override flags (for example `--canyon-override`) can be viewed in the help menu by running `kona-node node --help`. The only overrides currently supported are hardfork timestamps in seconds. [scr]: https://github.com/ethereum-optimism/superchain-registry/tree/main # Derivation in Kona Node Source: https://docs.optimism.io/node-operators/kona-node/design/derivation The derivation system in kona-node is responsible for transforming L1 data into L2 payload attributes that can be executed to produce the canonical L2 blocks. This document covers how the [`kona-derive`][kd] crate is integrated and used within the kona-node architecture. ## Overview The derivation subsystem in kona-node is built around the **DerivationActor**, which manages the derivation pipeline lifecycle and coordinates with other node components. The actor uses the trait-abstracted [`kona-derive`][kd] pipeline to continuously process L1 data and produce L2 payload attributes. ### Key Components * **DerivationActor**: The main actor responsible for running the derivation pipeline * **OnlinePipeline**: A concrete implementation of the derivation pipeline using online providers * **DerivationStateMachine**: Manages when derivation is allowed to occur and tracks the confirmed safe head * **L2Finalizer**: Tracks derived L2 blocks awaiting finalization * **Signal System**: Handles pipeline resets, hardfork activations, and error conditions ## Architecture ### DerivationActor The `DerivationActor` is a [`NodeActor`][na] that runs as part of the node service. It receives requests from other actors over a single inbound channel and steps the derivation pipeline forward to produce new payload attributes. ```rust theme={null} pub struct DerivationActor where DerivationEngineClient_: DerivationEngineClient, PipelineSignalReceiver: Pipeline + SignalReceiver, { /// The channel on which all inbound requests are received by the actor. inbound_request_rx: mpsc::Receiver, /// The Engine client used to interact with the engine. engine_client: DerivationEngineClient_, /// The derivation pipeline. pipeline: PipelineSignalReceiver, /// The state machine controlling when derivation can occur. derivation_state_machine: DerivationStateMachine, /// The L2Finalizer tracks derived L2 blocks awaiting finalization. finalizer: L2Finalizer, } ``` Inbound requests are expressed as the `DerivationActorRequest` enum: L1 head updates, finalized L1 block updates, engine safe head updates, engine sync completion, and pipeline signals from the engine (for example flush or reset). The actor coordinates with several other node components: * **Engine Actor**: Receives payload attributes for execution and sends back safe head updates and pipeline signals * **L1 Watcher Actor**: Sends L1 head and finalized block updates from the L1 chain ### Pipeline Construction The derivation pipeline is constructed by the `RollupNode` service when it wires up the derivation actor. The node builds caching L1/L2 providers and then creates an `OnlinePipeline` in one of two modes, selected by `InteropMode`: 1. **Polled Mode**: Uses polling-based L1 block traversal 2. **Indexed Mode**: Uses indexed L1 block traversal for more efficient L1 block handling ```rust theme={null} match self.interop_mode { InteropMode::Polled => OnlinePipeline::new_polled( self.config.clone(), self.l1_config.chain_config.clone(), OnlineBlobProvider::init(self.l1_config.beacon_client.clone()).await, l1_derivation_provider, l2_derivation_provider, self.dependency_set.clone(), ), InteropMode::Indexed => OnlinePipeline::new_indexed( self.config.clone(), self.l1_config.chain_config.clone(), OnlineBlobProvider::init(self.l1_config.beacon_client.clone()).await, l1_derivation_provider, l2_derivation_provider, self.dependency_set.clone(), ), } ``` ### Provider Configuration The node uses caching providers to optimize performance: * **AlloyChainProvider**: Provides L1 blockchain data with configurable cache size * **AlloyL2ChainProvider**: Provides L2 blockchain data and system configuration * **OnlineBlobProvider**: Retrieves blob data from the beacon chain for post-4844 transactions The cache size is set to 1024 entries by default: ```rust theme={null} const DERIVATION_PROVIDER_CACHE_SIZE: usize = 1024; ``` ## Pipeline Operation ### Main Processing Loop The derivation actor runs a continuous loop that handles various events: 1. **Shutdown signals**: Graceful shutdown when cancellation token is triggered 2. **L1 head updates**: Triggers derivation when new L1 blocks are available 3. **Safe head updates**: Triggers derivation when the L2 safe head advances 4. **Pipeline signals**: Handles resets, hardfork activations, and channel flushes ### Stepping Logic The core derivation logic is implemented in `produce_next_attributes()`: ```rust theme={null} async fn produce_next_attributes( &mut self, ) -> Result ``` This method continuously steps the pipeline until payload attributes are produced: 1. **Step the pipeline** with the last confirmed L2 safe head from the derivation state machine 2. **Handle step results**: * `PreparedAttributes`: Attributes are ready to be consumed * `AdvancedOrigin`: Pipeline advanced to next L1 block * `OriginAdvanceErr`/`StepFailed`: Handle various error conditions 3. **Return attributes** when available ### Error Handling The derivation actor handles three categories of pipeline errors: #### Temporary Errors * `PipelineError::NotEnoughData`: Continue stepping, more data may become available * `PipelineError::Eof`: Yield and wait for more L1 data #### Reset Errors * `ResetError::HoloceneActivation`: Send `ActivationSignal` to handle hardfork * `ResetError::ReorgDetected`: Send reset request to engine (if not in interop mode) * Other reset errors: Wait for external signal before continuing #### Critical Errors * Unrecoverable errors that terminate the derivation process * Increment metrics counter and propagate error up ### Signal Handling The pipeline supports several signal types for coordination: * **ResetSignal**: Resets pipeline state with new L1 origin and system config * **ActivationSignal**: Handles hardfork activations (e.g., Holocene) * **FlushChannel**: Invalidates current channel data for deposit-only blocks Signals are sent from the engine actor when specific conditions are detected during payload execution. ## Configuration ### Rollup Configuration The derivation pipeline requires a [`RollupConfig`][rc] that defines: * Chain parameters (chain ID, block time, etc.) * Hardfork activation heights * System configuration addresses * Batch and channel parameters ### Runtime Configuration Runtime configuration includes: * Provider cache sizes * Polling intervals for L1 data * Interop mode selection * Metrics collection settings ## Integration Patterns ### With Engine Actor The derivation actor produces `OpAttributesWithParent` that are sent to the engine actor for execution through the `DerivationEngineClient` interface: ```rust theme={null} // Send payload attributes out for processing. self.engine_client .send_safe_l2_signal(payload_attributes.into()) .await ``` The engine actor executes these attributes and updates the L2 safe head, which triggers the next derivation cycle. ### With the L1 Watcher The derivation actor receives L1 head updates from the L1 watcher actor as `DerivationActorRequest::ProcessL1HeadUpdateRequest` messages on its inbound request channel, which indicate when new L1 data is available for processing. Finalized L1 blocks arrive the same way and drive the `L2Finalizer`. ### With RPC Layer The RPC layer can query derivation status and potentially trigger pipeline operations through the standard node RPC interface. ## Metrics and Observability The derivation actor exposes several metrics for monitoring: * `DERIVATION_L1_ORIGIN`: Current L1 origin block number * `DERIVATION_CRITICAL_ERROR`: Count of critical derivation errors * `L1_REORG_COUNT`: Count of detected L1 reorganizations These metrics help operators monitor the health and progress of the derivation process. ## Related Documentation For more details on the underlying derivation pipeline implementation, see: * The [`kona-derive` crate source](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/crates/protocol/derive) * The [`kona-derive` API documentation](https://docs.rs/kona-derive/latest/kona_derive/) on docs.rs * The [derivation pipeline specification](https://specs.optimism.io/protocol/derivation.html) [kd]: https://crates.io/crates/kona-derive [na]: /node-operators/kona-node/design/intro#actors [rc]: https://docs.rs/kona-genesis/latest/kona_genesis/struct.RollupConfig.html # Execution Engine Source: https://docs.optimism.io/node-operators/kona-node/design/engine The `kona-engine` crate provides a modular execution engine implementation for the OP Stack rollup node. It serves as the bridge between the rollup protocol and the execution layer (EL), managing Engine API interactions through a sophisticated task queue system. ## Architecture Overview The execution engine is built around several key components: * **Engine Task Queue**: A priority-ordered queue that manages Engine API operations * **Trait Abstractions**: Extensible interfaces for tasks, errors, and state management * **Engine Client**: HTTP client for communicating with the execution layer * **Actor Integration**: Service layer integration through the `EngineActor` ## Core Trait Abstractions ### EngineTaskExt The `EngineTaskExt` trait defines the interface for all engine tasks: ```rust theme={null} #[async_trait] pub trait EngineTaskExt { type Output; type Error: EngineTaskError; async fn execute(&self, state: &mut EngineState) -> Result; } ``` This trait enables: * **Atomic operations** over the `EngineState` * **Extensible task implementation** for custom operations * **Async execution** with proper error handling ### EngineTaskError The `EngineTaskError` trait provides sophisticated error handling with severity levels: ```rust theme={null} pub trait EngineTaskError { fn severity(&self) -> EngineTaskErrorSeverity; } pub enum EngineTaskErrorSeverity { Temporary, // Retry the task Critical, // Propagate to engine actor Reset, // Request derivation reset Flush, // Request derivation flush } ``` This allows tasks to signal different recovery strategies based on the error type. ## Task Queue System The engine uses a priority-based task queue (a binary heap ordered by the `EngineTask` `Ord` implementation) where tasks are ordered according to OP Stack synchronization requirements. Tasks are generic over an `EngineClient` implementation. ### Task Priority (Highest to Lowest) 1. **Seal** - Seals blocks that have finished building (sequencer mode) 2. **Build** - Builds new blocks (sequencer mode) 3. **Insert** - Inserts unsafe blocks from gossip 4. **Consolidate** - Advances safe chain via derivation 5. **Finalize** - Finalizes L2 blocks Forkchoice updates are not a standalone queue entry: the `SynchronizeTask` runs as part of the other tasks whenever the forkchoice state needs to move. ### Task Types #### SynchronizeTask Updates the execution layer's forkchoice state. It is invoked by the other tasks rather than queued directly: ```rust theme={null} pub struct SynchronizeTask { /// The engine client. pub client: Arc, /// The rollup config. pub rollup: Arc, /// The sync state update to apply to the engine state. pub state_update: EngineSyncStateUpdate, } ``` Handles: * Forkchoice synchronization via `engine_forkchoiceUpdated` * EL sync status management #### BuildTask Starts building a new block in sequencer mode, producing a payload ID: ```rust theme={null} pub struct BuildTask { /// The engine API client. pub engine: Arc, /// The RollupConfig. pub cfg: Arc, /// The OpAttributesWithParent to instruct the execution layer to build. pub attributes: OpAttributesWithParent, /// The optional sender through which the PayloadId will be sent /// after the block build has been started. pub payload_id_tx: Option>, } ``` Handles payload building initiation with `engine_forkchoiceUpdated`. #### SealTask Seals a block started by a `BuildTask`, retrieving the payload with version-specific `engine_getPayload` calls, inserting it, and canonicalizing it: ```rust theme={null} pub struct SealTask { /// The engine API client. pub engine: Arc, /// The RollupConfig. pub cfg: Arc, /// The PayloadId being sealed. pub payload_id: PayloadId, /// The OpAttributesWithParent to instruct the execution layer to build. pub attributes: OpAttributesWithParent, /// Whether or not the payload was derived, or created by the sequencer. pub is_attributes_derived: bool, /// An optional sender for the built OpExecutionPayloadEnvelope or the /// SealTaskError that occurred during processing. pub result_tx: Option>>, } ``` #### InsertTask Inserts payloads (for example unsafe blocks received from gossip) into the execution engine: ```rust theme={null} pub struct InsertTask { /// The engine client. client: Arc, /// The rollup config. rollup_config: Arc, /// The network payload envelope. envelope: OpExecutionPayloadEnvelope, /// If the payload is safe this is true. is_payload_safe: bool, } ``` #### ConsolidateTask Advances the safe chain through derivation: ```rust theme={null} pub struct ConsolidateTask { /// The engine client. pub client: Arc, /// The RollupConfig. pub cfg: Arc, /// The input for consolidation (either attributes or block info). pub input: ConsolidateInput, } ``` If consolidation fails, the task reverts to payload attribute processing via the `BuildTask`. #### FinalizeTask Finalizes L2 blocks: ```rust theme={null} pub struct FinalizeTask { /// The engine client. pub client: Arc, /// The rollup config. pub cfg: Arc, /// Identifier of the L2 block to finalize. pub block_id: FinalizeBlockId, } ``` ## Engine State Management The `EngineState` tracks the current state of the execution engine: ```rust theme={null} pub struct EngineState { /// The sync state of the engine. pub sync_state: EngineSyncState, /// Whether or not the EL has finished syncing. pub el_sync_finished: bool, /// Tracks when the rollup node changes the forkchoice to restore a /// previously known unsafe chain (e.g. an unsafe reorg caused by an /// invalid span batch). pub need_fcu_call_backup_unsafe_reorg: bool, } ``` The unsafe, safe, and finalized heads live in the nested `EngineSyncState`. State updates are communicated through watch channels, enabling reactive programming patterns across the system. ## Integration with kona-node The `kona-node` service layer integrates the engine through the `EngineActor`: ### Actor Pattern The `EngineActor` implements the `NodeActor` trait: ```rust theme={null} #[async_trait] pub trait NodeActor: Send + 'static { /// The error type for the actor. type Error: std::fmt::Debug; /// Handle the next inbound request, event, or scheduled tick. async fn step(&mut self) -> Result<(), Self::Error>; } ``` ### Communication Channels The `EngineActor` receives all state-mutating input through a single inbound request channel of `EngineActorRequest` messages: payload attributes from derivation, unsafe blocks from gossip, reset requests, finalization requests, and block building requests (sequencer mode only). A separate read-only `EngineRpcActor` runs as an independent peer and serves engine queries; it shares the engine client and a watch over the engine state and queue length, but is constrained to a read-only subset of the engine client so it cannot reach Engine API mutation methods. ### Engine Queries The engine supports queries for: ```rust theme={null} pub enum EngineQueries { /// Request the current rollup configuration. Config(Sender), /// Request the current EngineState snapshot. State(Sender), /// Request the L2 output root for a specific block. OutputAtBlock { block: BlockNumberOrTag, sender: Sender<(L2BlockInfo, OutputRoot, EngineState)> }, /// Subscribe to engine state updates via a watch channel receiver. StateReceiver(Sender>), /// Development API: Subscribe to task queue length updates. QueueLengthReceiver(Sender>), /// Development API: Get the current number of pending tasks in the queue. TaskQueueLength(Sender), } ``` ## Usage Patterns ### Basic Engine Setup ```rust theme={null} // Create an engine client. The `EngineClient` trait is implemented by // `OpEngineClient`, constructed through the `EngineClientBuilder`. let client = EngineClientBuilder { l2: l2_engine_url, l2_jwt: jwt_secret, l1_rpc: l1_rpc_url, cfg: rollup_config, } .build(); // Initialize engine state let state = EngineState::default(); let (state_sender, state_receiver) = watch::channel(state); let (queue_length_sender, queue_length_receiver) = watch::channel(0); // Create engine with task queue let engine = Engine::new(state, state_sender, queue_length_sender); ``` ### Adding Tasks ```rust theme={null} // Add a consolidate task let task = EngineTask::Consolidate(Box::new(ConsolidateTask::new( client.clone(), rollup_config.clone(), input, ))); engine.enqueue(task); ``` ### Draining the Queue ```rust theme={null} // Process all pending tasks match engine.drain().await { Ok(()) => info!("Tasks completed successfully"), Err(e) => match e.severity() { EngineTaskErrorSeverity::Reset => { // Request derivation reset }, EngineTaskErrorSeverity::Critical => { // Handle critical error }, _ => { // Handle other error types } } } ``` ## Error Handling and Recovery The engine provides robust error handling through: ### Severity-Based Recovery * **Temporary errors**: Automatically retried * **Critical errors**: Propagated to the actor * **Reset errors**: Trigger derivation pipeline reset * **Flush errors**: Trigger derivation pipeline flush ### State Consistency Tasks operate atomically on the `EngineState`, ensuring consistency even during error conditions. ## Version Support The engine automatically selects appropriate Engine API versions based on hardfork activation: * **Pre-Ecotone (Bedrock, Canyon, Delta)**: Uses `engine_newPayloadV2` and `engine_getPayloadV2` * **Post-Ecotone**: Uses `engine_newPayloadV3` and `engine_getPayloadV3` * **Post-Isthmus**: Uses `engine_newPayloadV4` and `engine_getPayloadV4` * **Post-Karst (Osaka)**: Uses `engine_getPayloadV5` (`engine_newPayload` and `engine_forkchoiceUpdated` stay at their V4/V3 versions) ## Metrics and Observability When the `metrics` feature is enabled, the engine provides comprehensive metrics for: * Task execution times * Error rates by task type * Engine state transitions * API call latencies ## Extensibility The trait-based architecture allows for: * **Custom task implementations** via `EngineTaskExt` * **Custom error handling** via `EngineTaskError` * **Custom state management** extensions * **Testing and mocking** support This modular design ensures the engine can adapt to future OP Stack protocol changes while maintaining backward compatibility. # Node Design Overview Source: https://docs.optimism.io/node-operators/kona-node/design/intro The entry-point for the `kona-node` is the [`RollupNode`][node] service, which encapsulates the core wiring for the node. A `RollupNode` is constructed through the [`RollupNodeBuilder`][builder], and its [`start` method][start] handles connecting all the different components of the node, running each in a spawned task. As such, each node component is considered an actor. The `RollupNode` abstracts individual actors through the [`NodeActor` trait][actor], a minimal interface with a single `step` method that the service drives in a loop until the actor reports a fatal error or the node shuts down. Kona provides implementations for all `NodeActor`s required to run a `RollupNode`. Actors are defined in the [actors][actors] module of the `kona-node-service` crate, and the `RollupNode` wiring lives in the [service][service] module. ### Actors The architecture of `kona-node` is a web of actors that share state through message passing, using channels, rather than using shared memory. The [`RollupNode`][node] builds and starts the following actors. * **Derivation Actor**: Orchestrates the derivation pipeline, deriving L2 payload attributes from L1 blocks. Payload attributes prepared this way are forwarded to the Engine Actor to be executed. The [derivation][derivation] docs dive deeper into how the derivation actor works. * **Engine Actor**: Brokers the connection to the execution layer client (or "execution engine"). The engine actor turns messages from other actors into engine "tasks" that are executed in priority order against the EL client. A companion engine RPC actor serves read-only engine queries. The [engine][engine] docs expand on this. * **L1 Watcher Actor**: Watches the L1 chain for new head and finalized blocks and relays them to the derivation actor. * **Network Actor**: Manages the P2P Network for the rollup node. The P2P stack consists of `discv5` peer discovery and block gossip through libp2p. Visit the [network][p2p] docs for more detail. * **Sequencer Actor**: The sequencer actor extends the `kona-node` to be run as a sequencer. Sequencing is periphery to the basic rollup node operation. See the [sequencer][sequencer] docs. * **RPC Actor**: The RPC actor spins up and serves an RPC server that exposes the rpc methods required by the [OP Stack Specs][specs]. [p2p]: ./p2p [engine]: ./engine [derivation]: ./derivation [sequencer]: ./sequencer [specs]: https://specs.optimism.io/protocol/rollup-node.html [service]: https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/crates/node/service/src/service [actors]: https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/crates/node/service/src/actors [actor]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/crates/node/service/src/actors/traits.rs [start]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/crates/node/service/src/service/node.rs [node]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/crates/node/service/src/service/node.rs [builder]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/crates/node/service/src/service/builder.rs # P2P Networking Source: https://docs.optimism.io/node-operators/kona-node/design/p2p Partly adapted from the [OP Stack P2P Specs][p2p-specs]. Please reference the specs for up-to-date OP Stack requirements. The OP Stack uses P2P networking on the consensus layer to share the sequencer's view of the L2 chain with other nodes on the network. L2 blocks shared via P2P are considered "unsafe", and will be reorganized to match the canonical chain, prioritizing L1. This means that behavior on the P2P layer does not affect the rollup security. As such, rules around banning and scoring peers based on their P2P gossip is policy - it is up to the user to ultimately choose a configuration best for them. To understand how the P2P is hooked up to the `kona-node`, jump to the [P2P Actor](#p2p-actor) section below. Otherwise, read on to learn more about the details of the P2P stack. ### Topography The P2P stack topography consists of the following. * Discovery of peers via [discv5][discv5]. * Gossip and peer connection management through [libp2p][libp2p]. * Publishing and validation of gossip by the node. In the `kona-node`, these layers are split up into modular components either as modules or distinct crates. #### Discovery Kona's discovery layer is encapsulated in a "driver" called the [`Discv5Driver`][driver]. When started, the driver spawns a new thread to handle [`discv5::Discv5`][discv5-service] events from its event stream as well as metrics requests from the `kona-node`. A "handler" is returned by the consumed [`Discv5Driver`][driver] which allows other components of the `kona-node` to communicate through channels to the spawned [`discv5::Discv5`][discv5-service] service. When peers are discovered by kona's discovery service, their "ENR"s need to be validated to ensure those peers are participating in the right network gossip. Ethereum Node Records (ENRs) and how they are validated is discussed in a [later section](#node-identification). After their ENRs are validated, they are forwarded to the consumer (in kona's case libp2p) which establishes and manages the connection to the node. There are also a few more notable functions of Kona's discovery driver. * Every X seconds it attempts to discover random ENRs. This is configurable using `Discv5Builder::with_interval` * Every Y seconds it evicts a random ENR from the discovery table to keep peer discovery fresh. This is configurable using `Discv5Builder::with_discovery_randomize`. * Every Z seconds it stores its ENR table at a configurable location so if the service is restarted, it doesn't need to rediscover peers, it can just use the stored peers. The interval is configurable using `Discv5Builder::with_store_interval`. #### Gossip L2 blocks on the OP Stack not otherwise derived from L1 are shared over TCP in the P2P network of nodes. Unsafe L2 blocks shared this way originate from the sequencer. In the `kona-node`, L2 block gossip is handled through the [libp2p Swarm][swarm]. The `GossipDriver` is the component in the `kona-node` that manages the libp2p swarm, including any interfacing with the swarm like dialing peers, publishing payloads (L2 blocks), handling events from the swarm, and more. The libp2p swarm must be polled via Swarm as Stream in order to make progress. Through kona's `GossipDriver`, this can be done by looping over and consuming events from `GossipDriver::next`. The `GossipDriver` provides the methods to handle events from the [libp2p Swarm][swarm]. Events should be consumed this way in order to use the connection gater as well as peer store and fields on the `GossipDriver`. The [libp2p Swarm][swarm] listens on a specified [`Multiaddr`][multiaddr]. #### L2 Block Publishing As mentioned in [the previous section](#gossip), L2 blocks are published as payloads through the [libp2p Swarm][swarm], which is done using the `GossipDriver`. The `GossipDriver` accepts an `OpExecutionPayloadEnvelope` and its signature, then privately encodes them in the wire format documented in the [OP Stack P2P Specs][p2p-specs]. L2 blocks published through the `GossipDriver` are published on a "topic". The topic is used by the gossipsub protocol to publish the message on that given topic, allowing peers to choose which topics they wish to subscribe to. #### L2 Block Validation L2 blocks are validated in kona through a trait-abstracted "block handler". Since messages in the libp2p mesh network are snappy compressed, they need to be decompressed and then decoded for the correct [block topic][block-topic] those messages are published on. After decompression, kona separates the signature from the exact encoded envelope bytes. It authenticates those bytes before decoding the envelope according to the corresponding block topic and validating the block contents. Block validity in kona follows the [OP Stack block validation specs][validation]. As of writing these docs, block validation follows a few rules. * The timestamp is between 60 seconds in the past and at most 5 seconds in the future. * The block signature authenticates the exact encoded envelope bytes. * The block hash is valid. This is checked by computing the transaction trie root directly from the encoded transaction bytes and hashing the reconstructed header. Transaction decoding and execution remain the execution layer's responsibility. * The contents of the payload envelope are correct for its version. Since different versions introduce new contents to the payload from hardforks, the forwards-compatible payload envelope cannot have fields with content that don't exist for previous versions. ### Node Identification TODO ### P2P Actor TODO [validation]: https://specs.optimism.io/protocol/rollup-node-p2p.html#block-validation [block-topic]: https://specs.optimism.io/protocol/rollup-node-p2p.html#gossip-topics [multiaddr]: https://docs.rs/libp2p/0.56.0/libp2p/struct.Multiaddr.html [swarm]: https://docs.rs/libp2p/latest/libp2p/struct.Swarm.html [discv5-service]: https://docs.rs/discv5/latest/discv5/struct.Discv5.html [driver]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/crates/node/disc/src/driver.rs [discv5]: https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md [libp2p]: https://libp2p.io/ [p2p-specs]: https://specs.optimism.io/protocol/rollup-node-p2p.html # Sequencer Mode Source: https://docs.optimism.io/node-operators/kona-node/design/sequencer Understand how the kona-node sequencer actor builds L2 blocks, and the trait abstractions and programmatic configuration behind sequencer mode. The Kona node can operate in **sequencer mode** to build and produce new L2 blocks. In this mode, the node acts as the sequencer for an OP Stack rollup, building L2 blocks on top of the current unsafe head and extending the L2 chain. This page explains the design of sequencer mode and how to configure it programmatically through the Node SDK. To run `kona-node` as a sequencer from the command line, follow the [run a sequencer node](/node-operators/kona-node/run/sequencer) guide. ## Overview When running in sequencer mode, the Kona node: * **Builds L2 blocks** by collecting transactions from the mempool and constructing new blocks * **Selects L1 origins** for new L2 blocks based on finalized L1 data * **Manages block production timing** and ensures proper sequencing constraints * **Integrates with conductor services** for leader election in multi-sequencer setups * **Handles recovery scenarios** when the sequencer needs to catch up with L1 The sequencer uses the same core derivation pipeline as validator nodes but operates in reverse - instead of deriving L2 blocks from L1 data, it produces L2 blocks that will later be derivable from L1. ## Core Components ### `NodeMode` The node's operational mode is expressed by the `NodeMode` enum, carried on the node's `EngineConfig`: ```rust theme={null} pub enum NodeMode { /// Validator mode. Validator, /// Sequencer mode. Sequencer, } ``` ### `SequencerActor` The core actor responsible for block production. Like every node component, it implements the `NodeActor` trait: * Builds L2 blocks using the attributes builder * Manages timing and L1 origin selection * Handles admin RPC commands for sequencer control * Coordinates with conductor services for leader election ### `SequencerConfig` Sequencer behavior is configured through the `SequencerConfig` struct: ```rust theme={null} pub struct SequencerConfig { /// Whether or not the sequencer is enabled at startup. pub sequencer_stopped: bool, /// Whether or not the sequencer is in recovery mode. pub sequencer_recovery_mode: bool, /// The Url for the conductor RPC endpoint. If Some, enables the conductor service. pub conductor_rpc_url: Option, /// The confirmation delay for the sequencer. pub l1_conf_delay: u64, } ``` ## Programmatic Configuration ### Using the RollupNodeBuilder To configure a Kona node programmatically for sequencer mode, set `NodeMode::Sequencer` on the `EngineConfig` and pass a `SequencerConfig` to the `RollupNodeBuilder`: ```rust theme={null} use kona_node_service::{NodeMode, RollupNodeBuilder, SequencerConfig}; // Configure sequencer settings let sequencer_config = SequencerConfig { sequencer_stopped: false, // Start sequencer immediately sequencer_recovery_mode: false, // Normal operation mode conductor_rpc_url: Some( // Optional conductor integration Url::parse("http://conductor:8080").unwrap() ), l1_conf_delay: 4, // L1 origin confirmation delay }; // engine_config carries `mode: NodeMode::Sequencer` along with the // L2 engine URL, JWT secret, and L1 RPC URL. RollupNodeBuilder::new( rollup_config, l1_config_builder, l2_trust_rpc, engine_config, p2p_config, rpc_config, ) .with_sequencer_config(sequencer_config) .build() .start() .await?; ``` ### Configuration Options | Field | Description | Default | | ------------------------- | ---------------------------------------------- | ------- | | `sequencer_stopped` | Start sequencer in stopped state | `false` | | `sequencer_recovery_mode` | Enable recovery mode for catch-up | `false` | | `conductor_rpc_url` | Conductor service endpoint for leader election | `None` | | `l1_conf_delay` | Confirmation delay for L1 origin selection | `0` | ## Next Steps * To run a sequencer from the command line, including the required flags and example configurations, see [run a sequencer node](/node-operators/kona-node/run/sequencer). * For the full CLI flag catalogue, see the [Kona node CLI reference](/node-operators/kona-node/configuration). # FAQ Source: https://docs.optimism.io/node-operators/kona-node/faq/overview 1. [Ports](/node-operators/kona-node/faq/ports) - Detailed account of ports used by the `kona-node` for P2P communication, JSON-RPC APIs, and the Engine API for execution layer communication. # Node Ports Source: https://docs.optimism.io/node-operators/kona-node/faq/ports | Service | Default Port | Flag/Env | | ------------- | ------------ | ---------------------------------------------------- | | RPC HTTP | 9545 | `--port` / `KONA_NODE_RPC_PORT` | | RPC WebSocket | 9545 | (same as HTTP, enabled with `--rpc.ws-enabled`) | | P2P TCP | 9222 | `--p2p.listen.tcp` / `KONA_NODE_P2P_LISTEN_TCP_PORT` | | P2P UDP | 9223 | `--p2p.listen.udp` / `KONA_NODE_P2P_LISTEN_UDP_PORT` | `kona-node` does not run a supervisor RPC server: the binary has no `--supervisor.*` flag group. Its only interop flag, `--interop.dependency-set` (`KONA_NODE_INTEROP_DEPENDENCY_SET`), takes a path to a dependency-set JSON file rather than a port. `--conductor.rpc` (`KONA_NODE_CONDUCTOR_RPC`) is not a listening port either. It is the RPC endpoint URL of an external conductor service that the node dials out to, and it has no default value. Supplying it enables the conductor integration when the node runs in sequencer mode (`--mode sequencer`); in validator mode it has no effect. Every port can be changed with the flag or environment variable listed alongside it. For the full flag catalog, see the [Kona Node CLI Reference](/node-operators/kona-node/configuration). # Install kona-node Source: https://docs.optimism.io/node-operators/kona-node/install/overview Prerequisites and the three ways to obtain kona-node: Docker images, pre-built binaries, or building from source. ## Prerequisites Before installing Kona, ensure you have the following prerequisites: * **Rust toolchain** (MSRV: 1.82) * **`just`** command runner * **Docker** (optional, for containerized builds) ### Installing Rust If you don't have Rust installed, you can install it using [rustup](https://rustup.rs/): ```bash theme={null} curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` Rustup is an easy way to update the Rust compiler, and works on all platforms. * During installation, when prompted, enter `1` for the default installation. * After Rust installation completes, try running `cargo version` . If it cannot be found, run `source $HOME/.cargo/env`. After that, running `cargo version` should return the version, for example `cargo 1.68.2`. * It's generally advisable to append `source $HOME/.cargo/env` to `~/.bashrc`. The Minimum Supported Rust Version (MSRV) of this project is 1.82.0. If you already have a version of Rust installed, you can check your version by running `rustc --version`. To update your version of Rust, run rustup update. ### Installing Just `just` is a command runner that Kona uses for build tasks. Install it with: ```bash theme={null} cargo install just ``` ## Installation Methods There are three ways to obtain Kona: * [Docker images](/node-operators/kona-node/run/docker#getting-the-kona-node-image): pull a published image or build one locally * [Pre-built binaries](https://github.com/ethereum-optimism/optimism/releases): download the latest release from GitHub, then follow the [binary guide](/node-operators/kona-node/run/binary) * [Building from source](/node-operators/kona-node/install/source) If you have Docker installed, we recommend using the [Docker recipe](/node-operators/kona-node/run/docker) configuration that will have kona-node, op-reth, Prometheus and Grafana running and syncing with just one command. # Building from Source Source: https://docs.optimism.io/node-operators/kona-node/install/source Building from source requires that the Rust toolchain is installed, as well as the `just` command runner. Visit the [Prerequisites](/node-operators/kona-node/install/overview) for details on installing Rust and `just`. First clone the repository: ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git cd rust/kona ``` Then, install the `kona-node` binary into your PATH directly via: ```bash theme={null} cargo install --locked --path bin/node --bin kona-node ``` The binary will now be accessible as `kona-node` via the command line, and exist under your default .cargo/bin folder. Alternatively, you can build yourself with: ```bash theme={null} cargo build --release --bin kona-node ``` This will place the reth binary under `./target/release/kona-node`, and you can copy it to your directory of preference after that. ## Update Kona You can update the `kona-node` to a specific version by running the commands below. `${VERSION}` is the version you wish to build in the format `vX.X.X`. ```bash theme={null} git fetch git checkout ${VERSION} cargo build --release --bin kona-node ``` ## Troubleshooting ### Command is not found Reth will be installed to `CARGO_HOME` or `$HOME/.cargo`. This directory needs to be on your `PATH` before you can run the `kona-node` binary. See ["Configuring the PATH environment variable"][path] for more information. [path]: https://www.rust-lang.org/tools/install ### Compilation error Make sure you are running the latest version of Rust. If you have installed Rust using rustup, simply run `rustup update`. If you can't install the latest version of Rust you can instead compile using the Minimum Supported Rust Version (MSRV) which is listed under the `rust-version` key in kona's [Cargo.toml](https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/Cargo.toml). If compilation fails with `(signal: 9, SIGKILL: kill)`, this could mean your machine ran out of memory during compilation. If you are on Docker, consider increasing the memory of the container, or use a [pre-built binary](https://github.com/ethereum-optimism/optimism/releases). If compilation fails with `error: linking with cc failed: exit code: 1`, try running `cargo clean`. ## Next Steps * Read the [design docs](/node-operators/kona-node/design/intro) to understand kona-node's architecture * Check out the [Binaries](/node-operators/kona-node/run/binary) documentation * Explore the [examples](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/examples) # Monitoring Source: https://docs.optimism.io/node-operators/kona-node/monitoring Set up logging, Prometheus metrics, and Grafana dashboards for kona-node. This guide covers observability for a running `kona-node`: adjusting log verbosity, filtering log targets, and collecting Prometheus metrics into Grafana dashboards. ## Logging `kona-node` provides a `-v` (or `--v`) flag as a way to set the "verbosity" level for logs. By default, the verbosity level is set to `3`, which is the INFO level. The level ranges from `0` being no logs to `5` which includes trace logs. Log levels are listed below, with each level including the one below it. * `5`: `TRACE` - very verbose logs that provide a detailed trace * `4`: `DEBUG` - logs meant to print debugging information * `3`: `INFO` - informational logs * `2`: `WARN` - includes warning and error logs * `1`: `ERROR` - only error logs are shown * `0`: No logs The default verbosity level is `-vvv` which is the `3` or `INFO` level. To set the `kona-node` to print `DEBUG` logs or level `4`, run the node like so: `kona-node node -vvvv`. ### Filtering Log Targets By default, the `kona-node` initializes its tracing (logging) using the default environment variable filter [provided by the tracing\_subscriber crate][tracing-env]. This uses the value in the `RUST_LOG` environment variable to set the tracing level for specific targets. Effectively, `RUST_LOG` allows you to bypass the default log level for the whole node or specific log targets. For example, by prepending `RUST_LOG=engine=debug` to the `kona-node` command (or setting that as an environment variable), only `INFO` logs will be displayed except for the `engine` log target which will also print `DEBUG` logs. This comes in handy say for when we would like to debug Kona's P2P stack, we could prepend `RUST_LOG=discv5=debug,libp2p=debug` to view debug logs from only `discv5` and `libp2p` targets. ## Metrics The `kona-node` can serve Prometheus metrics, which are disabled by default. To turn them on, pass the `--metrics.enabled` cli flag. Unless otherwise specified with the `--metrics.port` flag, metrics are exposed on port `9090`. To grab a snapshot of the metrics, you can visit `0.0.0.0:9090` or `curl` the url. ``` curl 0.0.0.0:9090 ``` The output should be raw text mapping metrics with their values. Remember, this is just a snapshot of the metrics at that point in time. To record and visualize the metrics, we'll use [Grafana and Prometheus](#grafana-and-prometheus). ## Grafana and Prometheus Prometheus is a simple service that scrapes metrics at a predefined interval. Grafana then uses Prometheus as a "Data Source" to visualize the collected metrics. The Reth book provides a great overview to setting up [Prometheus and Grafana][setup]. Visit the Reth docs to follow along. The `kona-node` comes shipped with a default Grafana dashboard for the `kona-node`. To import the dashboard to grafana, click the `+` icon > `Import Dashboard` > paste the contents of [kona's dashboard][dashboard] in the textbox > `Load`. [tracing-env]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#method.from_default_env [setup]: https://reth.rs/run/monitoring#prometheus--grafana [dashboard]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/docker/recipes/kona-node/grafana/dashboards/overview.json # System Requirements Source: https://docs.optimism.io/node-operators/kona-node/requirements `kona-node` is an L2 consensus client, so it stores almost nothing on disk! Anything stored on disk is configurable, and can be disabled. As a rollup node, it always sends L2 blocks over to the execution client (`op-reth` or `op-geth`) for execution. That way, chain state is entirely handled by the execution client. In this way, the `kona-node` is incredibly lightweight and can be run on a wide range of hardware. That said, a stable and dependable internet connection is critical for the peer-to-peer (P2P) part of the node. The `kona-node` relies on P2P communication to sync the unsafe chain. If the connection is unstable, the node may struggle to keep up, and could be banned by its peers for being too slow. # Admin RPC Methods Source: https://docs.optimism.io/node-operators/kona-node/rpc/admin The `admin` api provides methods for controlling and monitoring Kona's consensus node operations. ## `admin_postUnsafePayload` Posts an unsafe payload to the network. | Client | Method invocation | | ------ | ------------------------------------------------------------ | | RPC | `{"method": "admin_postUnsafePayload", "params": [payload]}` | ### Parameters * `payload` (`OpExecutionPayloadEnvelope`): The execution payload envelope to post ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"admin_postUnsafePayload","params":[{...payload...}]} {"jsonrpc":"2.0","id":1,"result":null} ``` ## `admin_sequencerActive` Returns whether the sequencer is currently active. | Client | Method invocation | | ------ | ------------------------------------- | | RPC | `{"method": "admin_sequencerActive"}` | ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"admin_sequencerActive","params":[]} {"jsonrpc":"2.0","id":1,"result":true} ``` **Note**: This method will return a "Method not found" error if the node is running in validator mode (sequencer not enabled). ## `admin_startSequencer` Starts the sequencer. | Client | Method invocation | | ------ | ------------------------------------ | | RPC | `{"method": "admin_startSequencer"}` | ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"admin_startSequencer","params":[]} {"jsonrpc":"2.0","id":1,"result":null} ``` **Note**: This method will return a "Method not found" error if the node is running in validator mode (sequencer not enabled). ## `admin_stopSequencer` Stops the sequencer and returns the hash of the last processed block. | Client | Method invocation | | ------ | ----------------------------------- | | RPC | `{"method": "admin_stopSequencer"}` | ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"admin_stopSequencer","params":[]} {"jsonrpc":"2.0","id":1,"result":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"} ``` **Note**: This method will return a "Method not found" error if the node is running in validator mode (sequencer not enabled). ## `admin_conductorEnabled` Returns whether the conductor is enabled. | Client | Method invocation | | ------ | -------------------------------------- | | RPC | `{"method": "admin_conductorEnabled"}` | ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"admin_conductorEnabled","params":[]} {"jsonrpc":"2.0","id":1,"result":false} ``` **Note**: This method will return a "Method not found" error if the node is running in validator mode (sequencer not enabled). ## `admin_setRecoverMode` Sets the recovery mode for the sequencer. | Client | Method invocation | | ------ | ------------------------------------------------------ | | RPC | `{"method": "admin_setRecoverMode", "params": [mode]}` | ### Parameters * `mode` (`bool`): Whether to enable recovery mode (true) or disable it (false) ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"admin_setRecoverMode","params":[true]} {"jsonrpc":"2.0","id":1,"result":null} ``` **Note**: This method will return a "Method not found" error if the node is running in validator mode (sequencer not enabled). ## `admin_overrideLeader` Overrides the leader in the conductor. | Client | Method invocation | | ------ | ------------------------------------ | | RPC | `{"method": "admin_overrideLeader"}` | ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"admin_overrideLeader","params":[]} {"jsonrpc":"2.0","id":1,"result":null} ``` **Note**: This method will return a "Method not found" error if the node is running in validator mode (sequencer not enabled). # JSON-RPC Source: https://docs.optimism.io/node-operators/kona-node/rpc/overview The `kona-node` supports JSON-RPC for interacting with the node. By default, `kona-node` exposes an HTTP JSON-RPC server. A WebSocket JSON-RPC endpoint is also available and can be enabled with the `--rpc.ws-enabled` flag or the `KONA_NODE_RPC_WS_ENABLED` environment variable. IPC transport is not supported. ### Namespaces JSON-RPC methods are grouped into namespaces, which are listed below: | Namespace | Description | Sensitive | | ------------------------------------------------ | -------------------------------------------------------- | --------- | | [`p2p`](/node-operators/kona-node/rpc/p2p) | The `p2p` API allows you to configure the p2p stack. | Maybe | | [`rollup`](/node-operators/kona-node/rpc/rollup) | The `rollup` API provides OP Stack specific rpc methods. | No | | [`admin`](/node-operators/kona-node/rpc/admin) | The `admin` API allows you to configure your node. | **Yes** | ### Interacting with the RPC Kona enables these RPC methods by default. You can interact with the RPC using any JSON-RPC client, such as `curl`, `httpie`, or a custom client in your preferred programming language. # P2P RPC Methods Source: https://docs.optimism.io/node-operators/kona-node/rpc/p2p The `p2p` api provides methods for interacting with Kona's P2P stack. ## Peer Information Methods ### `opp2p_self` Returns information about the local node in the form of `PeerInfo`. | Client | Method invocation | | ------ | -------------------------- | | RPC | `{"method": "opp2p_self"}` | #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_self","params":[]} {"jsonrpc":"2.0","id":1,"result":{"peerID":"16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x","nodeID":"0x311d8222ffc44e9c86f403d57f454bd823e7dc9d3c8e97171ddd862910352f31","userAgent":"kona","protocolVersion":"","ENR":"enr:-Jm4QBAdUpUqrpTj6yQor5mwif6RRmY11dlj-Um3TqKmJiYha4SUNqdJr2eM3pRsFVCwVikYcBk__5JVTwngUeimKxcCgmlkgnY0gmlwhC36_pOHb3BzdGFja4Xc76gFAIlzZWNwMjU2azGhA2WTa6OqvnWbRmoeuhRRu-BTPgP8y4_MY6snTsNW0gHBg3RjcIIj5oN1ZHCCn7U","addresses":["/ip4/127.0.0.1/tcp/9190/p2p/16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x","/ip4/172.18.0.9/tcp/9190/p2p/16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x"],"protocols":["/ipfs/id/push/1.0.0","/meshsub/1.1.0","/ipfs/ping/1.0.0","/meshsub/1.2.0","/ipfs/id/1.0.0","/opstack/req/payload_by_number/2151908/0/","/meshsub/1.0.0","/floodsub/1.0.0"],"connectedness":1,"direction":1,"protected":false,"chainID":11155420,"latency":0,"gossipBlocks":true,"scores":{"gossip":{"total":0.0,"blocks":{"timeInMesh":0.0,"firstMessageDeliveries":0.0,"meshMessageDeliveries":0.0,"invalidMessageDeliveries":0.0},"IPColocationFactor":0.0,"behavioralPenalty":0.0},"reqResp":{"validResponses":0.0,"errorResponses":0.0,"rejectedPayloads":0.0}}}} ``` ### `opp2p_peerCount` Returns the count of connected peers for both discovery and gossip networks. | Client | Method invocation | | ------ | ------------------------------- | | RPC | `{"method": "opp2p_peerCount"}` | #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_peerCount","params":[]} {"jsonrpc":"2.0","id":1,"result":{"connectedDiscovery":15,"connectedGossip":12}} ``` ### `opp2p_peers` Returns information about peers. If `connected` parameter is true, only returns connected peers. | Client | Method invocation | | ------ | -------------------------------------------------- | | RPC | `{"method": "opp2p_peers", "params": [connected]}` | #### Parameters * `connected` (boolean): If true, only returns connected peers #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_peers","params":[true]} {"jsonrpc":"2.0","id":1,"result":{"totalConnected":2,"peers":{"16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x":{"peerID":"16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x","nodeID":"0x311d8222ffc44e9c86f403d57f454bd823e7dc9d3c8e97171ddd862910352f31","userAgent":"kona","protocolVersion":"","addresses":["/ip4/127.0.0.1/tcp/9190"],"protocols":["/ipfs/ping/1.0.0","/meshsub/1.1.0"],"connectedness":1,"direction":2,"protected":false,"chainID":11155420,"latency":50000000,"gossipBlocks":true,"scores":{"gossip":{"total":1.5,"blocks":{"timeInMesh":100.0,"firstMessageDeliveries":10.0,"meshMessageDeliveries":5.0,"invalidMessageDeliveries":0.0},"IPColocationFactor":0.0,"behavioralPenalty":0.0},"reqResp":{"validResponses":25.0,"errorResponses":1.0,"rejectedPayloads":0.0}}}},"bannedPeers":[],"bannedIPS":[],"bannedSubnets":[]}} ``` ### `opp2p_peerStats` Returns statistical information about peers including connection counts and topic subscriptions. | Client | Method invocation | | ------ | ------------------------------- | | RPC | `{"method": "opp2p_peerStats"}` | #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_peerStats","params":[]} {"jsonrpc":"2.0","id":1,"result":{"connected":12,"table":50,"blocksTopic":8,"blocksTopicV2":10,"blocksTopicV3":5,"blocksTopicV4":2,"banned":3,"known":75}} ``` ### `opp2p_discoveryTable` Returns the discovery table entries as a list of ENR strings. | Client | Method invocation | | ------ | ------------------------------------ | | RPC | `{"method": "opp2p_discoveryTable"}` | #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_discoveryTable","params":[]} {"jsonrpc":"2.0","id":1,"result":["enr:-Jm4QBAdUpUqrpTj6yQor5mwif6RRmY11dlj-Um3TqKmJiYha4SUNqdJr2eM3pRsFVCwVikYcBk__5JVTwngUeimKxcCgmlkgnY0gmlwhC36_pOHb3BzdGFja4Xc76gFAIlzZWNwMjU2azGhA2WTa6OqvnWbRmoeuhRRu-BTPgP8y4_MY6snTsNW0gHBg3RjcIIj5oN1ZHCCn7U","enr:-Km4QBqBrKNq7F5L1dSrWW8Y1k8k4V2L2nTsNtGuKPpPwp3L_rBVMaQCQpnc2sBB-c2yV_n4qgM2_2yfcNjVXr4OFgCgmlkgnY0gmlwhH8AAAGHb3BzdGFja4OFAoAE"]} ``` ## Peer Blocking Methods ### `opp2p_blockPeer` Blocks a specific peer by peer ID, preventing any connections to or from that peer. | Client | Method invocation | | ------ | --------------------------------------------------- | | RPC | `{"method": "opp2p_blockPeer", "params": [peerID]}` | #### Parameters * `peerID` (string): The peer ID to block #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_blockPeer","params":["16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ### `opp2p_unblockPeer` Unblocks a previously blocked peer by peer ID. | Client | Method invocation | | ------ | ----------------------------------------------------- | | RPC | `{"method": "opp2p_unblockPeer", "params": [peerID]}` | #### Parameters * `peerID` (string): The peer ID to unblock #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_unblockPeer","params":["16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ### `opp2p_listBlockedPeers` Returns a list of all blocked peer IDs. | Client | Method invocation | | ------ | -------------------------------------- | | RPC | `{"method": "opp2p_listBlockedPeers"}` | #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_listBlockedPeers","params":[]} {"jsonrpc":"2.0","id":1,"result":["16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x","16Uiu2HAm7Th3s3C1VHmKrYzA9nPzV4b3vqL8z1x8WZzGk2t9DjRK"]} ``` ## Address Blocking Methods ### `opp2p_blockAddr` Blocks connections from a specific IP address. | Client | Method invocation | | ------ | ---------------------------------------------------- | | RPC | `{"method": "opp2p_blockAddr", "params": [address]}` | #### Parameters * `address` (string): The IP address to block (IPv4 or IPv6) #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_blockAddr","params":["192.168.1.100"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ### `opp2p_unblockAddr` Unblocks a previously blocked IP address. | Client | Method invocation | | ------ | ------------------------------------------------------ | | RPC | `{"method": "opp2p_unblockAddr", "params": [address]}` | #### Parameters * `address` (string): The IP address to unblock (IPv4 or IPv6) #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_unblockAddr","params":["192.168.1.100"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ### `opp2p_listBlockedAddrs` Returns a list of all blocked IP addresses. | Client | Method invocation | | ------ | -------------------------------------- | | RPC | `{"method": "opp2p_listBlockedAddrs"}` | #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_listBlockedAddrs","params":[]} {"jsonrpc":"2.0","id":1,"result":["192.168.1.100","10.0.0.50","2001:db8::1"]} ``` ## Subnet Blocking Methods ### `opp2p_blockSubnet` Blocks connections from an entire IP subnet using CIDR notation. | Client | Method invocation | | ------ | ----------------------------------------------------- | | RPC | `{"method": "opp2p_blockSubnet", "params": [subnet]}` | #### Parameters * `subnet` (string): The subnet to block in CIDR notation (e.g., "192.168.1.0/24") #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_blockSubnet","params":["192.168.1.0/24"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ### `opp2p_unblockSubnet` Unblocks a previously blocked IP subnet. | Client | Method invocation | | ------ | ------------------------------------------------------- | | RPC | `{"method": "opp2p_unblockSubnet", "params": [subnet]}` | #### Parameters * `subnet` (string): The subnet to unblock in CIDR notation #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_unblockSubnet","params":["192.168.1.0/24"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ### `opp2p_listBlockedSubnets` Returns a list of all blocked IP subnets. | Client | Method invocation | | ------ | ---------------------------------------- | | RPC | `{"method": "opp2p_listBlockedSubnets"}` | #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_listBlockedSubnets","params":[]} {"jsonrpc":"2.0","id":1,"result":["192.168.1.0/24","10.0.0.0/16","2001:db8::/32"]} ``` ## Peer Protection Methods ### `opp2p_protectPeer` Protects a peer from being disconnected due to connection limits or other automatic pruning mechanisms. | Client | Method invocation | | ------ | ----------------------------------------------------- | | RPC | `{"method": "opp2p_protectPeer", "params": [peerID]}` | #### Parameters * `peerID` (string): The peer ID to protect #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_protectPeer","params":["16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ### `opp2p_unprotectPeer` Removes protection from a peer, allowing it to be disconnected by automatic pruning mechanisms. | Client | Method invocation | | ------ | ------------------------------------------------------- | | RPC | `{"method": "opp2p_unprotectPeer", "params": [peerID]}` | #### Parameters * `peerID` (string): The peer ID to unprotect #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_unprotectPeer","params":["16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ## Connection Management Methods ### `opp2p_connectPeer` Attempts to establish a connection to a specific peer using a multiaddress. | Client | Method invocation | | ------ | -------------------------------------------------------- | | RPC | `{"method": "opp2p_connectPeer", "params": [multiaddr]}` | #### Parameters * `multiaddr` (string): The multiaddress of the peer to connect to #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_connectPeer","params":["/ip4/127.0.0.1/tcp/9190/p2p/16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x"]} {"jsonrpc":"2.0","id":1,"result":null} ``` ### `opp2p_disconnectPeer` Disconnects from a specific peer by peer ID. | Client | Method invocation | | ------ | -------------------------------------------------------- | | RPC | `{"method": "opp2p_disconnectPeer", "params": [peerID]}` | #### Parameters * `peerID` (string): The peer ID to disconnect from #### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"opp2p_disconnectPeer","params":["16Uiu2HAmKVVub7edwZ3RKDnqMpZVsusYW9TKRgbwpH54nvDWLE4x"]} {"jsonrpc":"2.0","id":1,"result":null} ``` # Rollup RPC Methods Source: https://docs.optimism.io/node-operators/kona-node/rpc/rollup The `optimism` API provides methods for interacting with Kona's rollup state and configuration. ## `optimism_outputAtBlock` Returns the output root at a specific block number, including the L2 block reference, withdrawal storage root, state root, and sync status. | Client | Method invocation | | ------ | --------------------------------------------------------------- | | RPC | `{"method": "optimism_outputAtBlock", "params": [blockNumber]}` | ### Parameters * `blockNumber` (`BlockNumberOrTag`): The block number to get the output for. Can be a number, "latest", "earliest", "pending", "safe", or "finalized". ### Returns `OutputResponse` - An object containing: * `version` (`string`): The output version hash * `outputRoot` (`string`): The output root hash * `blockRef` (`L2BlockInfo`): Reference to the L2 block * `withdrawalStorageRoot` (`string`): The withdrawal storage root * `stateRoot` (`string`): The state root * `syncStatus` (`SyncStatus`): The current sync status of the node ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"optimism_outputAtBlock","params":["latest"]} { "jsonrpc": "2.0", "id": 1, "result": { "version": "0x0000000000000000000000000000000000000000000000000000000000000000", "outputRoot": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "blockRef": { "hash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", "number": 12345, "parentHash": "0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba", "timestamp": 1699123456, "l1Origin": { "hash": "0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321", "number": 18123456 }, "sequenceNumber": 42 }, "withdrawalStorageRoot": "0x567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234", "stateRoot": "0xcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab", "syncStatus": { "current_l1": { "hash": "0x1111111111111111111111111111111111111111111111111111111111111111", "number": 18123456 }, "current_l1_finalized": { "hash": "0x2222222222222222222222222222222222222222222222222222222222222222", "number": 18123400 }, "head_l1": { "hash": "0x3333333333333333333333333333333333333333333333333333333333333333", "number": 18123460 }, "safe_l1": { "hash": "0x4444444444444444444444444444444444444444444444444444444444444444", "number": 18123450 }, "finalized_l1": { "hash": "0x5555555555555555555555555555555555555555555555555555555555555555", "number": 18123400 }, "unsafe_l2": { "hash": "0x6666666666666666666666666666666666666666666666666666666666666666", "number": 12350, "parentHash": "0x7777777777777777777777777777777777777777777777777777777777777777", "timestamp": 1699123500, "l1Origin": { "hash": "0x8888888888888888888888888888888888888888888888888888888888888888", "number": 18123460 }, "sequenceNumber": 47 }, "safe_l2": { "hash": "0x9999999999999999999999999999999999999999999999999999999999999999", "number": 12345, "parentHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "timestamp": 1699123456, "l1Origin": { "hash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "number": 18123456 }, "sequenceNumber": 42 }, "finalized_l2": { "hash": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "number": 12340, "parentHash": "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "timestamp": 1699123400, "l1Origin": { "hash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "number": 18123400 }, "sequenceNumber": 37 }, "cross_unsafe_l2": { "hash": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "number": 12350, "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000001", "timestamp": 1699123500, "l1Origin": { "hash": "0x0000000000000000000000000000000000000000000000000000000000000002", "number": 18123460 }, "sequenceNumber": 47 }, "local_safe_l2": { "hash": "0x0000000000000000000000000000000000000000000000000000000000000003", "number": 12345, "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000004", "timestamp": 1699123456, "l1Origin": { "hash": "0x0000000000000000000000000000000000000000000000000000000000000005", "number": 18123456 }, "sequenceNumber": 42 } } } } ``` ## `optimism_syncStatus` Returns the current synchronization status of the rollup node, including information about L1 and L2 block states. | Client | Method invocation | | ------ | ------------------------------------------------- | | RPC | `{"method": "optimism_syncStatus", "params": []}` | ### Returns `SyncStatus` - An object containing detailed sync information: * `current_l1` (`BlockInfo`): The current L1 block that derivation is idled at * `current_l1_finalized` (`BlockInfo`): The current L1 finalized block (legacy/deprecated) * `head_l1` (`BlockInfo`): The L1 head block reference * `safe_l1` (`BlockInfo`): The L1 safe head block reference * `finalized_l1` (`BlockInfo`): The finalized L1 block reference * `unsafe_l2` (`L2BlockInfo`): The unsafe L2 block reference (absolute tip) * `safe_l2` (`L2BlockInfo`): The safe L2 block reference (derived from L1) * `finalized_l2` (`L2BlockInfo`): The finalized L2 block reference * `cross_unsafe_l2` (`L2BlockInfo`): Cross-unsafe L2 block with verified cross-L2 dependencies * `local_safe_l2` (`L2BlockInfo`): Local safe L2 block derived from L1, not yet cross-verified ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"optimism_syncStatus","params":[]} { "jsonrpc": "2.0", "id": 1, "result": { "current_l1": { "hash": "0x1111111111111111111111111111111111111111111111111111111111111111", "number": 18123456 }, "current_l1_finalized": { "hash": "0x2222222222222222222222222222222222222222222222222222222222222222", "number": 18123400 }, "head_l1": { "hash": "0x3333333333333333333333333333333333333333333333333333333333333333", "number": 18123460 }, "safe_l1": { "hash": "0x4444444444444444444444444444444444444444444444444444444444444444", "number": 18123450 }, "finalized_l1": { "hash": "0x5555555555555555555555555555555555555555555555555555555555555555", "number": 18123400 }, "unsafe_l2": { "hash": "0x6666666666666666666666666666666666666666666666666666666666666666", "number": 12350, "parentHash": "0x7777777777777777777777777777777777777777777777777777777777777777", "timestamp": 1699123500, "l1Origin": { "hash": "0x8888888888888888888888888888888888888888888888888888888888888888", "number": 18123460 }, "sequenceNumber": 47 }, "safe_l2": { "hash": "0x9999999999999999999999999999999999999999999999999999999999999999", "number": 12345, "parentHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "timestamp": 1699123456, "l1Origin": { "hash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "number": 18123456 }, "sequenceNumber": 42 }, "finalized_l2": { "hash": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "number": 12340, "parentHash": "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "timestamp": 1699123400, "l1Origin": { "hash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "number": 18123400 }, "sequenceNumber": 37 }, "cross_unsafe_l2": { "hash": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "number": 12350, "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000001", "timestamp": 1699123500, "l1Origin": { "hash": "0x0000000000000000000000000000000000000000000000000000000000000002", "number": 18123460 }, "sequenceNumber": 47 }, "local_safe_l2": { "hash": "0x0000000000000000000000000000000000000000000000000000000000000003", "number": 12345, "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000004", "timestamp": 1699123456, "l1Origin": { "hash": "0x0000000000000000000000000000000000000000000000000000000000000005", "number": 18123456 }, "sequenceNumber": 42 } } } ``` ## `optimism_rollupConfig` Returns the rollup configuration parameters that define the rollup chain's behavior and properties. | Client | Method invocation | | ------ | --------------------------------------------------- | | RPC | `{"method": "optimism_rollupConfig", "params": []}` | ### Returns `RollupConfig` - An object containing the complete rollup configuration: * `genesis` (`ChainGenesis`): The genesis state of the rollup * `blockTime` (`number`): The block time of the L2 in seconds * `maxSequencerDrift` (`number`): Maximum sequencer drift in seconds * `seqWindowSize` (`number`): The sequencer window size * `channelTimeout` (`number`): Number of L1 blocks between channel open/close * `graniteChannelTimeout` (`number`): Channel timeout after Granite hardfork * `l1ChainId` (`number`): The L1 chain ID * `l2ChainId` (`number`): The L2 chain ID * `batchInboxAddress` (`string`): L1 address where batches are sent * `depositContractAddress` (`string`): L1 address for deposits * `l1SystemConfigAddress` (`string`): L1 address for system config * `protocolVersionsAddress` (`string`): L1 address for protocol versions * Additional configuration fields for hardforks, fees, and interoperability ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"optimism_rollupConfig","params":[]} { "jsonrpc": "2.0", "id": 1, "result": { "genesis": { "l1": { "hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "number": 18000000 }, "l2": { "hash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", "number": 0, "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp": 1699000000, "l1Origin": { "hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "number": 18000000 }, "sequenceNumber": 0 }, "l2Time": 1699000000, "systemConfig": { "batcherAddr": "0x1234567890123456789012345678901234567890", "overhead": "0x00000000000000000000000000000000000000000000000000000000000000bc", "scalar": "0x00000000000000000000000000000000000000000000000000000000000f4240", "gasLimit": 30000000 } }, "blockTime": 2, "maxSequencerDrift": 600, "seqWindowSize": 3600, "channelTimeout": 300, "graniteChannelTimeout": 50, "l1ChainId": 1, "l2ChainId": 10, "batchInboxAddress": "0xff00000000000000000000000000000000000010", "depositContractAddress": "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed", "l1SystemConfigAddress": "0x229047fed2591dbec1eF1118d64F7aF3dB9EB290", "protocolVersionsAddress": "0x8062AbC286f5e7D9428a0Ccb9AbD71e50d93b935", "superchainConfigAddress": "0x95703e0982140D16f8ebA6d158FccEde42f04a4C", "blobs_data": 1710374400, "interopMessageExpiryWindow": 3600, "chainOpConfig": { "canyon_denominator": 250, "canyon_elasticity": 6 } } } ``` ## `optimism_version` Returns the software version of the Kona rollup node. | Client | Method invocation | | ------ | ---------------------------------------------- | | RPC | `{"method": "optimism_version", "params": []}` | ### Returns `string` - The version string of the Kona software (e.g., "0.1.0") ### Example ```js theme={null} // > {"jsonrpc":"2.0","id":1,"method":"optimism_version","params":[]} { "jsonrpc": "2.0", "id": 1, "result": "0.1.0" } ``` ## Deprecated Methods ### `optimism_safeHeadAtL1Block` This RPC endpoint is **not supported** in Kona. It was used to track the safe head for every L1 block, but this is no longer necessary post-interop. Calling this method will return a "Method not found" error. | Client | Method invocation | | ------ | ------------------------------------------------------------------- | | RPC | `{"method": "optimism_safeHeadAtL1Block", "params": [blockNumber]}` | ### Returns This method returns an error with code `-32601` (Method not found). # Run Kona Node as a Binary Source: https://docs.optimism.io/node-operators/kona-node/run/binary Run the kona-node binary against an op-reth execution client, from starting both clients to watching the node sync. If you don't have a `kona-node` binary yet, download the latest pre-built binary from the [GitHub releases page](https://github.com/ethereum-optimism/optimism/releases), or head over to the [Installation](/node-operators/kona-node/install/overview) guide to build one yourself. `kona-node` is an L2 consensus client (also called a "rollup node"). This means that the node is a *consensus*-layer client, which needs a corresponding execution-layer client in order to sync and follow the L2 chain. The OP Stack uses a minimal diff approach to L1 execution clients, and [`op-reth`][op-reth] is the primary L2 execution layer client. This section will illustrate running the `kona-node` with an instance of [`op-reth`][op-reth]. Out of the box, the `kona-node` can be used for any `OP Stack` chain that is part of the [`superchain-registry`][scr]. In order to use an out-of-band `OP Stack` chain, for example a new devnet, you'll need to specify the rollup config using the custom `--l2-config-file` cli flag. See [rollup configuration loading](/node-operators/kona-node/configuration#rollup-configuration-loading) for details. This tutorial walks through running the `kona-node` as a binary. To use docker, head over to the [Docker Guide](/node-operators/kona-node/run/docker) which uses a `docker-compose` setup provided by `kona`. The `docker-compose` setup automatically bootstraps the `kona-node` with `op-reth`, provisioning grafana dashboards and a default Prometheus configuration. It is encouraged to follow the [Docker Guide](/node-operators/kona-node/run/docker) to avoid misconfigurations. The `kona-node` requires a few CLI flags. * `--l1-eth-rpc ` URL of the L1 execution client RPC API. * `--l1-beacon ` URL of the L1 beacon API. * `--l2-engine-rpc ` URL of the engine API endpoint of an L2 execution client. The L2 engine RPC points to the execution layer client's engine API, [`op-reth`][op-reth]. An L1 beacon endpoint and rpc endpoint are also required to fetch the L1 chain data that the L2 chain is derived from. First, start an instance of [`op-reth`][op-reth]. The [`op-reth` docs][op-reth-docs] provide very detailed instructions for running `op-reth` nodes for OP Stack chains (L2). For this demo, we'll use `base`, but any other OP Stack chain will do. ``` op-reth node \ --chain base \ --rollup.sequencer-http https://mainnet-sequencer.base.org \ --http \ --ws \ --authrpc.port 9551 \ --authrpc.jwtsecret /path/to/jwt.hex ``` Kona has a `generate-jwt` justfile target that can be used to create the `jwt.hex` file. Run `just generate-jwt`. The JWT token file path passed into `--authrpc.jwtsecret` **MUST** be the same as the one passed into the `kona-node`. This JWT token is how the `op-reth` client authenticates requests made by the `kona-node` to the engine rpc. By default, the `kona-node` will attempt to read a JWT token from a `jwt.hex` file in the local directory. If it cannot find one, it will create a JWT token in a new `jwt.hex` file. To specify the path to the file that contains the JWT token, pass the file path into the `--l2.jwt-secret` CLI flag or use the `KONA_NODE_L2_ENGINE_AUTH` environment variable. Then, run the `kona-node` using Base's chain id - `8453`. ``` kona-node node \ --chain 8453 \ --l1-eth-rpc \ --l1-beacon \ --l2-engine-rpc http://127.0.0.1:9551 \ ``` That's it! Your node should connect to P2P and start syncing quickly. By default, `kona-node` trusts its RPC providers and doesn't perform additional verification, which is suitable for local nodes. When pointing the node at public RPC endpoints, follow [configure RPC trust](/node-operators/kona-node/run/rpc-trust) to enable block hash verification. #### What to Expect Now, when the `kona-node` starts up, it should immediately spin up the P2P stack. It will begin discovering valid peers on the network with the same chain id (base - `8453`) and OP Stack enr key "opstack". When valid peers are discovered, they are sent to the libp2p swarm which attempts to connect to them and listen for block gossip. Depending on the chain, and the P2P network topology, it may take longer for the `kona-node` to establish a strong set of peers and begin receiving block gossip. For larger, more mature chains like OP Mainnet and Base, peer discovery should happen quickly via the chain's P2P bootnodes. Once the first unsafe L2 payload attributes (block) is received from peers in the libp2p swarm, it is sent off to the `kona-node`'s engine actor which will kick off execution layer sync on the `op-reth` execution client. When this happens, the `op-reth` logs will start to show that it is fetching past L2 blocks to sync the chain to tip. Once EL sync is finished, `kona-node`'s derivation actor will kick off the derivation pipeline and begin deriving the L2 chain. All the while, the P2P stack is separately receiving unsafe L2 blocks from the chain's sequencer, and sending them off to the engine actor to insert into the chain. #### Next Steps * The node's default ports, default behavior, and every available CLI flag - including the sequencer and interop flag sets - are catalogued in the [Kona node CLI reference](/node-operators/kona-node/configuration). * To adjust log verbosity or set up metrics dashboards, see [Monitoring](/node-operators/kona-node/monitoring). * To learn more about running a `kona-node` using docker, check out the [docker guide](/node-operators/kona-node/run/docker). [scr]: https://github.com/ethereum-optimism/superchain-registry/tree/main [op-reth-docs]: https://reth.rs/run/opstack [op-reth]: https://github.com/paradigmxyz/reth/blob/main/crates/optimism/bin/src/main.rs [buildx]: https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/docker [packages]: https://github.com/orgs/op-rs/packages?repo_name=kona [pdocs]: https://github.com/ethereum-optimism/optimism/pkgs/container/kona%2Fkona-node/446969659?tag=latest # Docker Guide Source: https://docs.optimism.io/node-operators/kona-node/run/docker Run kona-node with op-reth using Kona's pre-packaged docker-compose setup, including Grafana dashboards and Prometheus. This guide uses Kona's pre-packaged docker config. For detailed usage of the `kona-node` binary, head over to [the binary guide](/node-operators/kona-node/run/binary). To run an op-node + op-reth stack with Docker instead, see [Running a Node With Docker](/node-operators/tutorials/node-from-docker). Kona provides a [`kona-node` docker recipe][recipe] with detailed instructions for running a complete node setup. ## Quick Start The easiest way to run `kona-node` with Docker is using the provided recipe: 1. **Navigate to the recipe directory:** ```bash theme={null} cd docker/recipes/kona-node ``` 2. **Configure environment variables:** Edit `cfg.env` to set your L1 RPC endpoints: ```bash theme={null} L1_PROVIDER_RPC=https://your-l1-rpc-endpoint L1_BEACON_API=https://your-l1-beacon-endpoint ``` 3. **Start the services:** ```bash theme={null} just up ``` This will start: * `kona-node` - The OP Stack node implementation * `op-reth` - Execution layer client * `prometheus` - Metrics collection * `grafana` - Monitoring dashboards (accessible at [http://localhost:3000](http://localhost:3000)) ## Docker Compose In the [provided docker compose][compose], there are a few services aside from the `kona-node` and `op-reth`. These are `prometheus` and `grafana` which automatically come provisioned with dashboards for monitoring and insight into the `kona-node` and `op-reth` services. For more detail into how Prometheus and Grafana work, head over to the [Monitoring][monitoring] docs. The `docker-compose.yaml` uses published images from GitHub Container Registry: * **`op-reth`**: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-reth:develop * **`kona-node`**: us-docker.pkg.dev/oplabs-tools-artifacts/images/kona-node:develop ### Service Configuration #### kona-node Service The `kona-node` service is configured with the following key settings: * **Ports**: * `5060` - RPC endpoint * `9223` - P2P discovery (TCP/UDP) * `9002` - Metrics * **Environment**: L1 RPC and Beacon API endpoints are required * **Volumes**: Persistent data storage and JWT token for engine API authentication #### op-reth Service The `op-reth` service provides the execution layer: * **Ports**: * `8545` - HTTP RPC * `8551` - Engine API (authenticated) * `30303` - P2P discovery * `9001` - Metrics * **Configuration**: Pre-configured for OP Sepolia testnet ## Configuration ### Network Selection By default, the recipe is configured for **OP Sepolia**. To sync a different OP Stack chain: 1. Set appropriate L1 endpoints for your target network in `cfg.env` 2. Modify the docker-compose.yaml: * Update `op-reth --chain` parameter * Update `op-reth --rollup.sequencer-http` endpoint * Update `kona-node --chain` parameter ### RPC Trust Configuration By default, `kona-node` trusts RPC providers (both L1 and L2). When using public or untrusted RPC endpoints, you should disable trust to enable block hash verification: ```bash theme={null} # In cfg.env or as environment variables: KONA_NODE_L1_TRUST_RPC=false KONA_NODE_L2_TRUST_RPC=false ``` Or modify the docker-compose.yaml command: ```yaml theme={null} kona-node: command: | node --chain op-sepolia --l1-eth-rpc ${L1_PROVIDER_RPC} --l1-beacon ${L1_BEACON_API} --l1-trust-rpc false # Add this for untrusted L1 RPCs --l2-engine-rpc ws://op-reth:8551 --l2-trust-rpc false # Add this for untrusted L2 RPCs ``` See [configure RPC trust](/node-operators/kona-node/run/rpc-trust) for more details on RPC trust settings. ### Port Configuration All host ports can be customized via environment variables in `cfg.env`: ```bash theme={null} # Kona Node ports KONA_NODE_RPC_PORT=5060 KONA_NODE_DISCOVERY_PORT=9223 KONA_NODE_METRICS_PORT=9002 # OP Reth ports OP_RETH_RPC_PORT=8545 OP_RETH_ENGINE_PORT=8551 OP_RETH_METRICS_PORT=9001 OP_RETH_DISCOVERY_PORT=30303 # Monitoring PROMETHEUS_PORT=9090 ``` ### Logging Adjust log levels by setting the `RUST_LOG` environment variable: ```bash theme={null} export RUST_LOG=engine_builder=trace,runtime=debug ``` ## Management Commands The recipe includes convenient Just commands: ```bash theme={null} # Start all services just up # Stop all services just down # Restart all services just restart # Generate JWT token (if needed) ./generate-jwt.sh ``` ## Getting the kona-node Image The recipe pulls published `kona-node` and `op-reth` images automatically. Use this section when you want to pull or build the `kona-node` image yourself, for example to pin a release version or test local changes. ### Pulling a published image Kona docker images are published with every release on GitHub Container Registry. You can obtain the latest `kona-node` image with: ```bash theme={null} docker pull us-docker.pkg.dev/oplabs-tools-artifacts/images/kona-node ``` Specify a specific version (e.g. v0.1.0) like so. ```bash theme={null} docker pull us-docker.pkg.dev/oplabs-tools-artifacts/images/kona-node:v0.1.0 ``` You can test the image with: ```bash theme={null} docker run --rm us-docker.pkg.dev/oplabs-tools-artifacts/images/kona-node --version ``` If you can see the [latest release](https://github.com/ethereum-optimism/optimism/releases) version, then you've successfully installed Kona via Docker. ### Building the Docker image To build the image from source, navigate to the root of the [kona directory](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona) in the monorepo and run: ```bash theme={null} just build-local kona-node ``` This will create an image with the tag `kona:local`. To specify a custom tag, just pass it in after `kona-node` in the command above, like so: ```bash theme={null} just build-local kona-node my-custom-tag ``` The build will likely take several minutes. Once it's built, test it with: ```bash theme={null} docker run kona:local --version ``` To use the locally built image with the recipe, update `docker-compose.yaml` to use `kona:local` instead of the published image. [monitoring]: ../monitoring.mdx [recipe]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/docker/recipes/kona-node/README.md [compose]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/docker/recipes/kona-node/docker-compose.yaml # How it Works Source: https://docs.optimism.io/node-operators/kona-node/run/mechanics Kona brings together a powerful suite of `no-std` and `std` Rust components, purpose-built for the OP Stack. At the heart of this ecosystem is the `kona-node` — a modern, modular rollup node (L2 consensus node) that can be used as a drop-in binary or as a foundation for custom services. The `kona-node` is a fully compliant implementation of the ["Rollup Node" Specifications][rollup-node] and is released as a [binary][package] in the [kona repository][kona]. Whether you're running a production network, building new rollup features, or experimenting with the OP Stack, `kona-node` is built to be both robust and extensible. ### Background A rollup node is responsible for deriving the canonical L2 chain from L1 blocks and their receipts. It validates these blocks using the [Engine API][engine-api], passing them to the execution layer for processing. Paired with an execution engine like op-reth or op-geth, `kona-node` tracks the unsafe, safe, and finalized tips of the L2 OP Stack chain, ensuring the node is always in sync with the latest state. Rollup nodes hold minimal state. Unsafe and safe payloads alike are sent away to the execution engine client which holds the chain's db. This way, the rollup node holds a view of the tip of the chain - unsafe, safe, and finalized block info. All data otherwise needed is held in memory. There are a few core architectural pieces of the `kona-node`. * **Derivation Pipeline:** Constructs L2 payload attributes from L1 blocks, forming the backbone of rollup logic. * **Execution Engine Integration:** Executes L2 payload attributes via the [Engine API][engine-api], abstracting away different EL clients. * **P2P Networking:** Enables block gossip and peer discovery. For an in-depth breakdown of these three pillars and a detailed design of the `kona-node`, visit the [Node Design section](/node-operators/kona-node/design/intro). Additionally, an RPC server exposes essential methods, including the [L2 Output RPC method][l2o-rpc]. ### Syncing The `kona-node` syncs the L2 chain in two main phases: 1. **Execution Layer (EL) Sync:** When starting, the node initially has an empty engine task queue. Once an unsafe block is received from P2P gossip, an `InsertTask` is executed. That task inserts the payload and sends a forkchoice update through the engine api. Since the engine state is lazily initialized (the safe and finalized heads are zero), the forkchoice update kicks off EL sync on the execution layer (EL) client (such as op-reth or op-geth). EL sync instructs the execution client to fetch and sync L2 blocks directly from peers. During this phase, the `kona-node` effectively waits for the EL client to reach the chain tip, when it returns that it is `synced`. No L2 blocks are derived from L1 during this period. 2. **Consensus Layer (CL) Sync:** Once the EL client is fully synced to the tip, the node transitions to consensus layer (CL) sync. In this phase, `kona-node` begins deriving new L2 payload attributes from the L1 chain, following the rollup derivation process. `OpAttributesWithParent` values derived this way are executed as an engine task which submits the payloads to the execution engine for validation and execution. * `kona-node` does **not** support historical CL sync or backfilling L2 blocks from L1 for past chain history. It relies on the EL client to perform the initial sync of the L2 chain. * Only after the EL is fully synced does the node begin deriving and following new L2 blocks from L1. ### Extensibility The `kona-node` is designed as a modular, actor-based node SDK, making it possible to extend or customize node behavior by adding new actors or swapping out existing ones. This extensibility is currently in **beta**, but the architecture is intentionally built to support advanced use cases and custom integrations. #### Actor Model At the core of `kona-node` is the concept of **actors**: independent, async services that communicate over channels. Each actor implements the [`NodeActor` trait][node-actor], a minimal interface with a single `step` method that the service drives in a loop until the actor reports a fatal error or the node shuts down. The [`RollupNode` service][node] builds and spawns a fixed set of actors covering derivation, the execution engine and its read-only engine RPC, the L1 watcher, P2P networking, the node's RPC server, and, in sequencer mode, block building. The [Node Design section](/node-operators/kona-node/design/intro) is the canonical description of that actor set and of what each actor does. #### Extending with Custom Actors You can write your own actor by implementing the `NodeActor` trait. This allows you to introduce new background services, event processors, or integrations with external systems. The trait has one associated type and one method. Each call to `step` handles a single inbound request, event, or scheduled tick. Returning `Ok(())` means the actor is ready to be stepped again; returning an error is fatal and stops the actor. Cancellation is handled by the caller that drives the loop, so the actor itself does not own a cancellation token. **Example: Defining a Custom Actor** ```rust theme={null} use async_trait::async_trait; use kona_node_service::NodeActor; struct MyCustomActor; #[async_trait] impl NodeActor for MyCustomActor { type Error = std::io::Error; async fn step(&mut self) -> Result<(), Self::Error> { // Your actor logic for one step here. Ok(()) } } ``` #### Running Custom Actors There is no trait-based extension point for swapping actors into the standard node today. [`RollupNode`][node] is a concrete type rather than a trait, its actor set is fixed in that type's `start` method, and the helper that spawns and supervises those actors is internal to the `kona-node-service` crate. Running a custom actor therefore means composing the node yourself. The built-in actors are public API of the `kona-node-service` crate. The request and payload types they exchange over channels are public too, spread across `kona-node-service`, sibling kona crates such as `kona-rpc` and `kona-gossip`, and the shared alloy engine types. A custom binary can therefore construct the actors it needs, wire them together over channels, add its own `NodeActor` implementations, and drive each actor's `step` method in its own task. #### Programmatic Node Construction The [`RollupNodeBuilder`][builder] provides a convenient way to construct a standard node, but for advanced use cases, you can build your own node by composing actors directly, or by implementing your own builder pattern. #### Current Limitations * The actor and service APIs are **beta** and may change. * The standard `RollupNode` exposes no hook for overriding an individual actor or pipeline, so extending the node means composing actors in your own binary rather than wrapping `RollupNode`. * Documentation and examples for advanced extensibility are still evolving—contributions and feedback are welcome! #### Learn More * See the [`NodeActor` trait documentation][node-actor] for details on implementing actors. * Explore the [kona-node-service crate][service] for source code and more examples. [cli-docs]: ../configuration.mdx [subcommands]: ../subcommands.mdx [service]: https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/crates/node/service [node-actor]: https://docs.rs/kona-node-service/latest/kona_node_service/trait.NodeActor.html [node]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/crates/node/service/src/service/node.rs [builder]: https://github.com/ethereum-optimism/optimism/blob/develop/rust/kona/crates/node/service/src/service/builder.rs [kona]: https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona [packages]: https://github.com/orgs/op-rs/packages?repo_name=kona [rollup-node]: https://specs.optimism.io/protocol/rollup-node.html [package]: https://github.com/ethereum-optimism/optimism/pkgs/container/kona%2Fkona-node [pdocs]: https://github.com/ethereum-optimism/optimism/pkgs/container/kona%2Fkona-node/446969659?tag=latest [buildx]: https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/docker [engine-api]: https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md [l2o-rpc]: https://specs.optimism.io/protocol/rollup-node.html#l2-output-rpc-method # Run a Node Source: https://docs.optimism.io/node-operators/kona-node/run/overview Now that you have [installed the `kona-node`](/node-operators/kona-node/install/overview), it's time to run it. In this section, we'll guide you through running the kona-node on various networks and with different configurations. ## Supported Networks Kona uses the [superchain-registry][scr] to dynamically load chain configurations for the specified network. As such, Kona can only support networks that are defined this way. [scr]: https://github.com/ethereum-optimism/superchain-registry To view available networks, the `kona-node` binary provides a `registry` subcommand that lists all available networks: ```bash theme={null} kona-node registry ``` Want to add support for a new network? Feel free to [add a chain](https://github.com/ethereum-optimism/superchain-registry/blob/main/docs/ops.md#adding-a-chain) to the superchain-registry! ## Configuration & Monitoring Learn how to configure and monitor your node: * **[Configuration](/node-operators/kona-node/configuration)** - Configure your node * **[Monitoring](/node-operators/kona-node/monitoring)** - Set up logs, metrics, and observability # Configure RPC Trust Source: https://docs.optimism.io/node-operators/kona-node/run/rpc-trust Decide when to enable RPC response verification on kona-node and configure the --l1-trust-rpc and --l2-trust-rpc flags for trusted and untrusted providers. The `--l1-trust-rpc` and `--l2-trust-rpc` flags control whether Kona performs additional verification on RPC responses to protect against malicious or faulty RPC providers. This guide helps you choose the right setting for your infrastructure and shows how to configure it. ## Trust Modes **Default Behavior (trust enabled, `true`):** * No additional block hash verification is performed * Optimized for performance * Suitable for local nodes and trusted infrastructure * Assumes the RPC provider is reliable and honest **Verification Mode (trust disabled, `false`):** * All fetched blocks have their hashes verified against the requested hashes * Protects against malicious RPC providers returning incorrect blocks * Recommended for public or third-party RPC endpoints * Small performance overhead due to hash verification ## Examples **Using trusted local RPCs (default):** ```bash theme={null} kona-node node \ --l1-eth-rpc http://localhost:8545 \ --l2-engine-rpc http://localhost:8551 \ # trust-rpc defaults to true, no need to specify ``` **Using untrusted public RPCs:** ```bash theme={null} kona-node node \ --l1-eth-rpc https://public-eth-rpc.com \ --l1-trust-rpc false \ --l2-engine-rpc https://public-l2-rpc.com \ --l2-trust-rpc false ``` **Mixed trust configuration:** ```bash theme={null} kona-node node \ --l1-eth-rpc https://public-eth-rpc.com \ --l1-trust-rpc false \ --l2-engine-rpc http://localhost:8551 \ # L2 trust-rpc defaults to true for local engine ``` ## Security Recommendations 1. **Local Infrastructure**: Keep the default `true` setting for RPCs you control 2. **Public RPCs**: Always set `--trust-rpc false` when using third-party endpoints 3. **Shared Infrastructure**: Consider setting `--trust-rpc false` as a precaution 4. **Performance Testing**: The verification overhead is minimal but can be measured in high-throughput scenarios ## Next Steps * Both flags are catalogued with the rest of the node's options in the [Kona node CLI reference](/node-operators/kona-node/configuration). * To get a node running end to end, follow the [binary guide](/node-operators/kona-node/run/binary) or the [Docker guide](/node-operators/kona-node/run/docker). # Run a Sequencer Node Source: https://docs.optimism.io/node-operators/kona-node/run/sequencer Run kona-node in sequencer mode from the command line, including required arguments, sequencer-specific flags, and example configurations. This guide shows how to run `kona-node` in **sequencer mode** from the command line. For how sequencer mode works internally and how to configure it programmatically through the Node SDK, see the [sequencer mode design](/node-operators/kona-node/design/sequencer) page. Sequencer mode is an advanced configuration primarily used by rollup operators. Most users will run nodes in the default validator mode. ## Basic Sequencer Setup To run a Kona node in sequencer mode: ```bash theme={null} kona-node node \ --mode=Sequencer \ --l1-eth-rpc=http://l1-node:8545 \ --l1-beacon=http://l1-beacon:5052 \ --l2-engine-rpc=http://l2-execution:8551 \ --l2.jwt-secret=./jwt.hex \ --chain=123456 ``` ## Required Arguments **Required Configuration** Sequencer mode requires all standard node arguments plus the `--mode=Sequencer` flag. Missing any required argument will prevent the node from starting. | Argument | Flag | Environment Variable | Description | | -------------- | ----------------- | -------------------------- | --------------------------- | | **Mode** | `--mode` | `KONA_NODE_MODE` | Must be set to `Sequencer` | | **L1 RPC** | `--l1-eth-rpc` | `KONA_NODE_L1_ETH_RPC` | L1 execution client RPC URL | | **L1 Beacon** | `--l1-beacon` | `KONA_NODE_L1_BEACON` | L1 beacon API URL | | **L2 Engine** | `--l2-engine-rpc` | `KONA_NODE_L2_ENGINE_RPC` | L2 engine API endpoint | | **JWT Secret** | `--l2.jwt-secret` | `KONA_NODE_L2_ENGINE_AUTH` | Path to JWT secret file | | **Chain ID** | `--chain` | `KONA_NODE_L2_CHAIN_ID` | L2 chain identifier | ## Sequencer-Specific Flags | Flag | Environment Variable | Default | Description | | -------------------------- | ---------------------------------- | ------- | ------------------------------------------- | | `--sequencer.stopped` | `KONA_NODE_SEQUENCER_STOPPED` | `false` | Start sequencer in stopped state | | `--sequencer.max-safe-lag` | `KONA_NODE_SEQUENCER_MAX_SAFE_LAG` | `0` | Max L2 blocks between safe and unsafe heads | | `--sequencer.l1-confs` | `KONA_NODE_SEQUENCER_L1_CONFS` | `4` | L1 confirmations for origin selection | | `--sequencer.recover` | `KONA_NODE_SEQUENCER_RECOVER` | `false` | Force recovery mode operation | | `--conductor.rpc` | `KONA_NODE_CONDUCTOR_RPC` | - | Conductor service RPC endpoint | | `--conductor.rpc.timeout` | `KONA_NODE_CONDUCTOR_RPC_TIMEOUT` | `1` | Conductor RPC timeout (seconds) | The full flag catalogue, including the standard node arguments shared with validator mode, lives in the [Kona node CLI reference](/node-operators/kona-node/configuration). ## Example Configurations ### Basic Sequencer ```bash theme={null} kona-node node \ --mode=Sequencer \ --l1-eth-rpc=http://localhost:8545 \ --l1-beacon=http://localhost:5052 \ --l2-engine-rpc=http://localhost:8551 \ --chain=42161 ``` ### Sequencer with Conductor ```bash theme={null} kona-node node \ --mode=Sequencer \ --conductor.rpc=http://conductor:8080 \ --conductor.rpc.timeout=5 \ --sequencer.l1-confs=6 \ --l1-eth-rpc=http://l1-node:8545 \ --l1-beacon=http://l1-beacon:5052 \ --l2-engine-rpc=http://l2-execution:8551 \ --chain=123456 ``` ### Recovery Mode Sequencer ```bash theme={null} kona-node node \ --mode=Sequencer \ --sequencer.recover=true \ --sequencer.max-safe-lag=100 \ --l1-eth-rpc=http://localhost:8545 \ --l1-beacon=http://localhost:5052 \ --l2-engine-rpc=http://localhost:8551 \ --chain=42161 ``` ## Key Considerations **Sequencer Operation** * **L1 Confirmations**: The `--sequencer.l1-confs` setting determines how many L1 blocks the sequencer waits before using an L1 block as an origin. Higher values provide more safety but increase latency. * **Recovery Mode**: Use `--sequencer.recover=true` when the sequencer needs to catch up after being offline. * **Conductor Integration**: For multi-sequencer deployments, configure the conductor service for proper leader election. Running a sequencer in production requires careful consideration of infrastructure, monitoring, and failover procedures. Ensure proper JWT secret management and secure network configuration. # `kona-node` Subcommands Source: https://docs.optimism.io/node-operators/kona-node/subcommands Below are the available subcommands for `kona-node`: * **node**: Runs the main consensus node service. This is the primary subcommand for operating a rollup node. * **info**: Displays information about the node, build, and environment. * **bootstore**: Manages the P2P bootstore (used for peer discovery and persistence). * **net**: Provides network-related utilities and diagnostics. * **registry**: Interacts with the chain registry for configuration and metadata. For more details on each subcommand and their flags, run: ``` kona-node --help ``` # op-reth Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth Reth ```bash theme={null} $ op-reth --help ``` ```txt theme={null} Usage: op-reth [OPTIONS] Commands: node Start the node init Initialize the database from a genesis file init-state Initialize the database from a state dump file import-op This syncs RLP encoded OP blocks below Bedrock from a file, without executing import-receipts-op This imports RLP encoded receipts from a file dump-genesis Dumps genesis block JSON configuration to stdout db Database debugging utilities stage Manipulate individual stages p2p P2P Debugging utilities config Write config to stdout prune Prune according to the configuration without any limits re-execute Re-execute blocks in parallel to verify historical sync correctness proofs Manage storage of historical proofs in expanded trie db in fault proof window help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') -V, --version Print version Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth config Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/config Write config to stdout ```bash theme={null} $ op-reth config --help ``` ```txt theme={null} Usage: op-reth config [OPTIONS] Options: --config The path to the configuration file to use. --default Show the default config -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db Database debugging utilities ```bash theme={null} $ op-reth db --help ``` ```txt theme={null} Usage: op-reth db [OPTIONS] Commands: stats Lists all the tables, their entry count and their size list Lists the contents of a table checksum Calculates the content checksum of a table or static file segment copy Copies the MDBX database to a new location (bundled mdbx_copy) diff Create a diff between two database tables or two entire databases get Gets the content of a table for the given key drop Deletes all database entries clear Deletes all table entries repair-trie Verifies trie consistency and outputs any inconsistencies static-file-header Reads and displays the static file segment header version Lists current and local database versions path Returns the full database path settings Manage storage settings prune-checkpoints View or set prune checkpoints stage-checkpoints `reth db stage-checkpoints` subcommand account-storage Gets storage size information for an account state Gets account state and storage at a specific block migrate-v2 Migrate storage layout from v1 (MDBX-only) to v2 (static files + RocksDB) help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db account-storage Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/account-storage Gets storage size information for an account ```bash theme={null} $ op-reth db account-storage --help ``` ```txt theme={null} Usage: op-reth db account-storage [OPTIONS]
Arguments:
The account address to check storage for Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db checksum Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/checksum Calculates the content checksum of a table or static file segment ```bash theme={null} $ op-reth db checksum --help ``` ```txt theme={null} Usage: op-reth db checksum [OPTIONS] Commands: mdbx Calculates the checksum of a database table static-file Calculates the checksum of a static file segment rocksdb Calculates the checksum of a RocksDB table help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db checksum mdbx Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/checksum/mdbx Calculates the checksum of a database table ```bash theme={null} $ op-reth db checksum mdbx --help ``` ```txt theme={null} Usage: op-reth db checksum mdbx [OPTIONS] Arguments:
The table name Options: --start-key The start of the range to checksum --end-key The end of the range to checksum --limit The maximum number of records that are queried and used to compute the checksum -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db checksum rocksdb Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/checksum/rocksdb Calculates the checksum of a RocksDB table ```bash theme={null} $ op-reth db checksum rocksdb --help ``` ```txt theme={null} Usage: op-reth db checksum rocksdb [OPTIONS]
Arguments:
The RocksDB table Possible values: - transaction-hash-numbers: Transaction hash to transaction number mapping - accounts-history: Account history indices - storages-history: Storage history indices Options: --limit The maximum number of records to checksum -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db checksum static-file Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/checksum/static-file Calculates the checksum of a static file segment ```bash theme={null} $ op-reth db checksum static-file --help ``` ```txt theme={null} Usage: op-reth db checksum static-file [OPTIONS] Arguments: The static file segment Possible values: - headers: Static File segment responsible for the `CanonicalHeaders`, `Headers`, `HeaderTerminalDifficulties` tables - transactions: Static File segment responsible for the `Transactions` table - receipts: Static File segment responsible for the `Receipts` table - transaction-senders: Static File segment responsible for the `TransactionSenders` table - account-change-sets: Static File segment responsible for the `AccountChangeSets` table - storage-change-sets: Static File segment responsible for the `StorageChangeSets` table Options: --start-block The block number to start from (inclusive) --end-block The block number to end at (inclusive) --limit The maximum number of rows to checksum -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db clear Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/clear Deletes all table entries ```bash theme={null} $ op-reth db clear --help ``` ```txt theme={null} Usage: op-reth db clear [OPTIONS] Commands: mdbx Deletes all database table entries static-file Deletes all static file segment entries help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db clear mdbx Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/clear/mdbx Deletes all database table entries ```bash theme={null} $ op-reth db clear mdbx --help ``` ```txt theme={null} Usage: op-reth db clear mdbx [OPTIONS]
Arguments:
Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db clear static-file Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/clear/static-file Deletes all static file segment entries ```bash theme={null} $ op-reth db clear static-file --help ``` ```txt theme={null} Usage: op-reth db clear static-file [OPTIONS] Arguments: Possible values: - headers: Static File segment responsible for the `CanonicalHeaders`, `Headers`, `HeaderTerminalDifficulties` tables - transactions: Static File segment responsible for the `Transactions` table - receipts: Static File segment responsible for the `Receipts` table - transaction-senders: Static File segment responsible for the `TransactionSenders` table - account-change-sets: Static File segment responsible for the `AccountChangeSets` table - storage-change-sets: Static File segment responsible for the `StorageChangeSets` table Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db copy Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/copy Copies the MDBX database to a new location (bundled mdbx\_copy) ```bash theme={null} $ op-reth db copy --help ``` ```txt theme={null} Usage: op-reth db copy [OPTIONS] Arguments: Destination path for the database copy Options: -c, --compact Compact the database while copying (reclaims free space) -d, --force-dynamic-size Force dynamic size for the destination database -p, --throttle-mvcc Throttle to avoid MVCC pressure on writers -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db diff Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/diff Create a diff between two database tables or two entire databases ```bash theme={null} $ op-reth db diff --help ``` ```txt theme={null} Usage: op-reth db diff [OPTIONS] --secondary-datadir --output Options: --secondary-datadir The path to the data dir for all reth files and subdirectories. -h, --help Print help (see a summary with '-h') Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics --table
The table name to diff. If not specified, all tables are diffed. --output The output directory for the diff report. Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db drop Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/drop Deletes all database entries ```bash theme={null} $ op-reth db drop --help ``` ```txt theme={null} Usage: op-reth db drop [OPTIONS] Options: -f, --force Bypasses the interactive confirmation and drops the database directly -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db get Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/get Gets the content of a table for the given key ```bash theme={null} $ op-reth db get --help ``` ```txt theme={null} Usage: op-reth db get [OPTIONS] Commands: mdbx Gets the content of a database table for the given key static-file Gets the content of a static file segment for the given key rocksdb Gets the content of a RocksDB table for the given key help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db get mdbx Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/get/mdbx Gets the content of a database table for the given key ```bash theme={null} $ op-reth db get mdbx --help ``` ```txt theme={null} Usage: op-reth db get mdbx [OPTIONS]
[SUBKEY] [END_KEY] [END_SUBKEY] Arguments:
The key to get content for [SUBKEY] The subkey to get content for [END_KEY] Optional end key for range query (exclusive upper bound) [END_SUBKEY] Optional end subkey for range query (exclusive upper bound) Options: --raw Output bytes instead of human-readable decoded value -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db get rocksdb Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/get/rocksdb Gets the content of a RocksDB table for the given key ```bash theme={null} $ op-reth db get rocksdb --help ``` ```txt theme={null} Usage: op-reth db get rocksdb [OPTIONS]
Arguments:
The RocksDB table Possible values: - transaction-hash-numbers: Transaction hash to transaction number mapping - accounts-history: Account history indices - storages-history: Storage history indices The key to get content for. For history tables, this can be a plain address Options: --block Target block number for history tables. Seeks to the shard containing this block. Defaults to the latest shard if not specified --storage-key Storage key for storages-history table lookups --all-shards List all shards for the given key (history tables only) --raw Output bytes instead of human-readable decoded value -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db get static-file Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/get/static-file Gets the content of a static file segment for the given key ```bash theme={null} $ op-reth db get static-file --help ``` ```txt theme={null} Usage: op-reth db get static-file [OPTIONS] [SUBKEY] Arguments: Possible values: - headers: Static File segment responsible for the `CanonicalHeaders`, `Headers`, `HeaderTerminalDifficulties` tables - transactions: Static File segment responsible for the `Transactions` table - receipts: Static File segment responsible for the `Receipts` table - transaction-senders: Static File segment responsible for the `TransactionSenders` table - account-change-sets: Static File segment responsible for the `AccountChangeSets` table - storage-change-sets: Static File segment responsible for the `StorageChangeSets` table The key to get content for [SUBKEY] The subkey to get content for, for example address in changeset Options: --raw Output bytes instead of human-readable decoded value -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db list Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/list Lists the contents of a table ```bash theme={null} $ op-reth db list --help ``` ```txt theme={null} Usage: op-reth db list [OPTIONS]
Arguments:
The table name Options: -s, --skip Skip first N entries [default: 0] -r, --reverse Reverse the order of the entries. If enabled last table entries are read -l, --len How many items to take from the walker [default: 5] --search Search parameter for both keys and values. Prefix it with `0x` to search for binary data, and text otherwise. ATTENTION! For compressed tables (`Transactions` and `Receipts`), there might be missing results since the search uses the raw uncompressed value from the database. --min-row-size Minimum size of row in bytes [default: 0] --min-key-size Minimum size of key in bytes [default: 0] --min-value-size Minimum size of value in bytes [default: 0] -c, --count Returns the number of rows found -j, --json Dump as JSON instead of using TUI --raw Output bytes instead of human-readable decoded value -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db migrate-v2 Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/migrate-v2 Migrate storage layout from v1 (MDBX-only) to v2 (static files + RocksDB) ```bash theme={null} $ op-reth db migrate-v2 --help ``` ```txt theme={null} Usage: op-reth db migrate-v2 [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db path Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/path Returns the full database path ```bash theme={null} $ op-reth db path --help ``` ```txt theme={null} Usage: op-reth db path [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db prune-checkpoints Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/prune-checkpoints View or set prune checkpoints ```bash theme={null} $ op-reth db prune-checkpoints --help ``` ```txt theme={null} Usage: op-reth db prune-checkpoints [OPTIONS] Commands: get Get prune checkpoint(s) from database set Set a prune checkpoint for a segment help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db prune-checkpoints get Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/prune-checkpoints/get Get prune checkpoint(s) from database. ```bash theme={null} $ op-reth db prune-checkpoints get --help ``` ```txt theme={null} Usage: op-reth db prune-checkpoints get [OPTIONS] Options: --segment Specific segment to query. If omitted, shows all segments [possible values: sender-recovery, transaction-lookup, receipts, contract-logs, account-history, storage-history, bodies] -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db prune-checkpoints set Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/prune-checkpoints/set Set a prune checkpoint for a segment. ```bash theme={null} $ op-reth db prune-checkpoints set --help ``` ```txt theme={null} Usage: op-reth db prune-checkpoints set [OPTIONS] --segment --mode Options: --segment The prune segment to update [possible values: sender-recovery, transaction-lookup, receipts, contract-logs, account-history, storage-history, bodies] --block-number Highest pruned block number --tx-number Highest pruned transaction number --mode Prune mode to write: full, distance, or before Possible values: - full: Prune all blocks - distance: Keep the last N blocks (requires --mode-value) - before: Prune blocks before a specific block number (requires --mode-value) --mode-value Value for distance or before mode (required unless mode is full) -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db repair-trie Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/repair-trie Verifies trie consistency and outputs any inconsistencies ```bash theme={null} $ op-reth db repair-trie --help ``` ```txt theme={null} Usage: op-reth db repair-trie [OPTIONS] Options: --dry-run Only show inconsistencies without making any repairs --metrics Enable Prometheus metrics. The metrics will be served at the given interface and port. -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db settings Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/settings Manage storage settings ```bash theme={null} $ op-reth db settings --help ``` ```txt theme={null} Usage: op-reth db settings [OPTIONS] Commands: get Get current storage settings from database set Set storage settings in database help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db settings get Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/settings/get Get current storage settings from database ```bash theme={null} $ op-reth db settings get --help ``` ```txt theme={null} Usage: op-reth db settings get [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db settings set Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/settings/set Set storage settings in database ```bash theme={null} $ op-reth db settings set --help ``` ```txt theme={null} Usage: op-reth db settings set [OPTIONS] Commands: v2 Enable or disable v2 storage layout help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db settings set v2 Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/settings/set/v2 Enable or disable v2 storage layout ```bash theme={null} $ op-reth db settings set v2 --help ``` ```txt theme={null} Usage: op-reth db settings set v2 [OPTIONS] Arguments: [possible values: true, false] Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db stage-checkpoints Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/stage-checkpoints `reth db stage-checkpoints` subcommand ```bash theme={null} $ op-reth db stage-checkpoints --help ``` ```txt theme={null} Usage: op-reth db stage-checkpoints [OPTIONS] Commands: get Get stage checkpoint(s) from database set Set a stage checkpoint help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db stage-checkpoints get Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/stage-checkpoints/get Get stage checkpoint(s) from database ```bash theme={null} $ op-reth db stage-checkpoints get --help ``` ```txt theme={null} Usage: op-reth db stage-checkpoints get [OPTIONS] Options: --stage Specific stage to query. If omitted, shows all stages [possible values: era, headers, bodies, sender-recovery, execution, prune-sender-recovery, merkle-unwind, account-hashing, storage-hashing, merkle-execute, transaction-lookup, index-storage-history, index-account-history, prune, finish] -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db stage-checkpoints set Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/stage-checkpoints/set Set a stage checkpoint ```bash theme={null} $ op-reth db stage-checkpoints set --help ``` ```txt theme={null} Usage: op-reth db stage-checkpoints set [OPTIONS] --stage --block-number Options: --stage Stage to update [possible values: era, headers, bodies, sender-recovery, execution, prune-sender-recovery, merkle-unwind, account-hashing, storage-hashing, merkle-execute, transaction-lookup, index-storage-history, index-account-history, prune, finish] --block-number Block number to set as stage checkpoint --clear-stage-unit Clear stage-specific unit checkpoint payload -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db state Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/state Gets account state and storage at a specific block ```bash theme={null} $ op-reth db state --help ``` ```txt theme={null} Usage: op-reth db state [OPTIONS]
Arguments:
The account address to get state for Options: -b, --block Block number to query state at (uses current state if not provided) -l, --limit Maximum number of storage slots to display [default: 100] -f, --format Output format (table, json, csv) [default: table] [possible values: table, json, csv] -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db static-file-header Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/static-file-header Reads and displays the static file segment header ```bash theme={null} $ op-reth db static-file-header --help ``` ```txt theme={null} Usage: op-reth db static-file-header [OPTIONS] Commands: block Query by segment and block number path Query by path to static file help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db static-file-header block Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/static-file-header/block Query by segment and block number ```bash theme={null} $ op-reth db static-file-header block --help ``` ```txt theme={null} Usage: op-reth db static-file-header block [OPTIONS] Arguments: Static file segment Possible values: - headers: Static File segment responsible for the `CanonicalHeaders`, `Headers`, `HeaderTerminalDifficulties` tables - transactions: Static File segment responsible for the `Transactions` table - receipts: Static File segment responsible for the `Receipts` table - transaction-senders: Static File segment responsible for the `TransactionSenders` table - account-change-sets: Static File segment responsible for the `AccountChangeSets` table - storage-change-sets: Static File segment responsible for the `StorageChangeSets` table Block number to query Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db static-file-header path Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/static-file-header/path Query by path to static file ```bash theme={null} $ op-reth db static-file-header path --help ``` ```txt theme={null} Usage: op-reth db static-file-header path [OPTIONS] Arguments: Path to the static file Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db stats Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/stats Lists all the tables, their entry count and their size ```bash theme={null} $ op-reth db stats --help ``` ```txt theme={null} Usage: op-reth db stats [OPTIONS] Options: --skip-consistency-checks Skip consistency checks for static files --detailed-sizes Show only the total size for static files --detailed-segments Show detailed information per static file segment --checksum Show a checksum of each table in the database. WARNING: this option will take a long time to run, as it needs to traverse and hash the entire database. For individual table checksums, use the `reth db checksum` command. -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth db version Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/db/version Lists current and local database versions ```bash theme={null} $ op-reth db version --help ``` ```txt theme={null} Usage: op-reth db version [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth dump-genesis Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/dump-genesis Dumps genesis block JSON configuration to stdout ```bash theme={null} $ op-reth dump-genesis --help ``` ```txt theme={null} Usage: op-reth dump-genesis [OPTIONS] Options: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth import-op Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/import-op This syncs RLP encoded OP blocks below Bedrock from a file, without executing ```bash theme={null} $ op-reth import-op --help ``` ```txt theme={null} Usage: op-reth import-op [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --chunk-len Chunk byte length to read from file. The path to a block file for import. The online stages (headers and bodies) are replaced by a file import, after which the remaining stages are executed. Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth import-receipts-op Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/import-receipts-op This imports RLP encoded receipts from a file ```bash theme={null} $ op-reth import-receipts-op --help ``` ```txt theme={null} Usage: op-reth import-receipts-op [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --chunk-len Chunk byte length to read from file. The path to a receipts file for import. File must use `OpGethReceiptFileCodec` (used for exporting OP chain segment below Bedrock block via testinprod/op-geth). Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth init Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/init Initialize the database from a genesis file ```bash theme={null} $ op-reth init --help ``` ```txt theme={null} Usage: op-reth init [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth init-state Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/init-state Initialize the database from a state dump file ```bash theme={null} $ op-reth init-state --help ``` ```txt theme={null} Usage: op-reth init-state [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --without-evm Specifies whether to initialize the state without relying on EVM historical data. When enabled, and before inserting the state, it creates a dummy chain up to the last EVM block specified. It then appends the first provided block. - **Note**: **Do not** import receipts and blocks beforehand, or this will fail or be ignored. --header Header file containing the header in an RLP encoded format. --header-hash Hash of the header. --without-ovm Specifies whether to initialize the state without relying on OVM or EVM historical data. When enabled, and before inserting the state, it creates a dummy chain up to the last OVM block (#105235062) (14GB / 90 seconds). It then, appends the Bedrock block. This is hardcoded for OP mainnet, for other OP chains you will need to pass in a header. - **Note**: **Do not** import receipts and blocks beforehand, or this will fail or be ignored. JSONL file with state dump. Must contain accounts in following format, additional account fields are ignored. Must also contain { "root": \ } as first line. { "balance": "\", "nonce": \, "code": "\", "storage": { "\": "\", .. }, "address": "\", } Allows init at a non-genesis block. Caution! Blocks must be manually imported up until and including the non-genesis block to init chain at. See 'import' command. Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth node Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/node Start the node ```bash theme={null} $ op-reth node --help ``` ```txt theme={null} Usage: op-reth node [OPTIONS] Options: --config The path to the configuration file to use. --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] --instance Add a new instance of a node. Configures the ports of the node to avoid conflicts with the defaults. This is useful for running multiple nodes on the same machine. Max number of instances is 200. It is chosen in a way so that it's not possible to have port numbers that conflict with each other. Changes to the following port numbers: - `DISCOVERY_PORT`: default + `instance` - 1 - `AUTH_PORT`: default + `instance` * 100 - 100 - `HTTP_RPC_PORT`: default - `instance` + 1 - `WS_RPC_PORT`: default + `instance` * 2 - 2 - `IPC_PATH`: default + `-instance` --with-unused-ports Sets all ports to unused, allowing the OS to choose random unused ports when sockets are bound. Mutually exclusive with `--instance`. -h, --help Print help (see a summary with '-h') Metrics: --metrics Enable Prometheus metrics. The metrics will be served at the given interface and port. --metrics.prometheus.push.url URL for pushing Prometheus metrics to a push gateway. If set, the node will periodically push metrics to the specified push gateway URL. --metrics.prometheus.push.interval Interval in seconds for pushing metrics to push gateway. Default: 5 seconds [default: 5] Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. Networking: -d, --disable-discovery Disable the discovery service --disable-dns-discovery Disable the DNS discovery --disable-discv4-discovery Disable Discv4 discovery --disable-discv5-discovery Disable Discv5 discovery --disable-nat Disable Nat discovery --discovery.addr The UDP address to use for devp2p peer discovery version 4. If unset and `--net-if.experimental` is used, discv4 binds to the resolved interface address. [default: 0.0.0.0] --discovery.port The UDP port to use for devp2p peer discovery version 4 [default: 30303] --discovery.v5.addr The UDP IPv4 address to use for devp2p peer discovery version 5. Overwritten by `RLPx` address, if it's also IPv4 --discovery.v5.addr.ipv6 The UDP IPv6 address to use for devp2p peer discovery version 5. Overwritten by `RLPx` address, if it's also IPv6 --discovery.v5.port The UDP IPv4 port to use for devp2p peer discovery version 5. Not used unless `--addr` is IPv4, or `--discovery.v5.addr` is set [default: 9200] --discovery.v5.port.ipv6 The UDP IPv6 port to use for devp2p peer discovery version 5. Not used unless `--addr` is IPv6, or `--discovery.addr.ipv6` is set. If not provided, discovery V5 defaults to same port as discovery V4 (--discovery.port). [default: 9200] --discovery.v5.lookup-interval The interval in seconds at which to carry out periodic lookup queries, for the whole run of the program [default: 20] --discovery.v5.bootstrap.lookup-interval The interval in seconds at which to carry out boost lookup queries, for a fixed number of times, at bootstrap [default: 5] --discovery.v5.bootstrap.lookup-countdown The number of times to carry out boost lookup queries at bootstrap [default: 200] --trusted-peers Comma separated enode URLs of trusted peers for P2P connections. --trusted-peers enode://abcd@192.168.0.1:30303 --trusted-only Connect to or accept from trusted peers only --bootnodes Comma separated enode URLs for P2P discovery bootstrap. Will fall back to a network-specific default if not specified. --dns-retries Amount of DNS resolution requests retries to perform when peering [default: 0] --peers-file The path to the known peers file. Connected peers are dumped to this file on nodes shutdown, and read on startup. Cannot be used with `--no-persist-peers`. --identity Custom node identity [default: op-reth/-/] --p2p-secret-key Secret key to use for this node. This will also deterministically set the peer ID. If not specified, it will be set in the data dir for the chain being used. --p2p-secret-key-hex Hex encoded secret key to use for this node. This will also deterministically set the peer ID. Cannot be used together with `--p2p-secret-key`. --no-persist-peers Do not persist peers. --nat NAT resolution method (any|none|upnp|publicip|extip:\) [default: any] --addr Network listening address [default: 0.0.0.0] --port Network listening port [default: 30303] --max-outbound-peers Maximum number of outbound peers. default: 100 --max-inbound-peers Maximum number of inbound peers. default: 30 --max-peers Maximum number of total peers (inbound + outbound). Splits peers using approximately 2:1 inbound:outbound ratio. Cannot be used together with `--max-outbound-peers` or `--max-inbound-peers`. --max-tx-reqs Max concurrent `GetPooledTransactions` requests. [default: 130] --max-tx-reqs-peer Max concurrent `GetPooledTransactions` requests per peer. [default: 1] --max-seen-tx-history Max number of seen transactions to remember per peer. Default is 320 transaction hashes. [default: 320] --max-pending-imports Max number of transactions to import concurrently. [default: 4096] --pooled-tx-response-soft-limit Experimental, for usage in research. Sets the max accumulated byte size of transactions to pack in one response. Spec'd at 2MiB. [default: 2097152] --pooled-tx-pack-soft-limit Experimental, for usage in research. Sets the max accumulated byte size of transactions to request in one request. Since `RLPx` protocol version 68, the byte size of a transaction is shared as metadata in a transaction announcement (see `RLPx` specs). This allows a node to request a specific size response. By default, nodes request only 128 KiB worth of transactions, but should a peer request more, up to 2 MiB, a node will answer with more than 128 KiB. Default is 128 KiB. [default: 131072] --max-tx-pending-fetch Max capacity of cache of hashes for transactions pending fetch. [default: 25600] --tx-channel-memory-limit Memory limit (in bytes) for the channel that buffers transaction events flowing from the network manager to the transactions manager. When the budget is exhausted, new events are dropped (see metric `total_dropped_tx_events_at_full_capacity`). Acts as a backstop against unbounded memory growth under sustained P2P transaction flooding. [default: 1073741824] --net-if.experimental Name of network interface used to communicate with peers. If flag is set, but no value is passed, the default interface for docker `eth0` is tried. If `--discovery.addr` is left at its default, discv4 will also bind to the resolved interface address. --tx-propagation-policy Transaction Propagation Policy The policy determines which peers transactions are gossiped to. [default: All] --tx-ingress-policy Transaction ingress policy Determines which peers' transactions are accepted over P2P. [default: All] --disable-tx-gossip Disable transaction pool gossip Disables gossiping of transactions in the mempool to peers. This can be omitted for personal nodes, though providers should always opt to enable this flag. --tx-propagation-mode Sets the transaction propagation mode by determining how new pending transactions are propagated to other peers in full. Examples: sqrt, all, max:10 [default: sqrt] --required-block-hashes Comma separated list of required block hashes or block number=hash pairs. Peers that don't have these blocks will be filtered out. Format: hash or `block_number=hash` (e.g., 23115201=0x1234...) --network-id Optional network ID to override the chain specification's network ID for P2P connections --eth-max-message-size Maximum allowed ETH message size in bytes. Default is 10 MiB --netrestrict Restrict network communication to the given IP networks (CIDR masks). Comma separated list of CIDR network specifications. Only peers with IP addresses within these ranges will be allowed to connect. Example: --netrestrict "192.168.0.0/16,10.0.0.0/8" --enforce-enr-fork-id Enforce EIP-868 ENR fork ID validation for discovered peers. When enabled, peers discovered without a confirmed fork ID are not added to the peer set until their fork ID is verified via EIP-868 ENR request. This filters out peers from other networks that pollute the discovery table. RPC: --http Enable the HTTP-RPC server --http.addr Http server address to listen on [default: 127.0.0.1] --http.port Http server port to listen on [default: 8545] --http.disable-compression Disable compression for HTTP responses --http.api Rpc Modules to be configured for the HTTP server [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev, testing] --http.corsdomain Http Corsdomain to allow request from --ws Enable the WS-RPC server --ws.addr Ws server address to listen on [default: 127.0.0.1] --ws.port Ws server port to listen on [default: 8546] --ws.origins Origins from which to accept `WebSocket` requests --ws.api Rpc Modules to be configured for the WS server [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev, testing] --ipcdisable Disable the IPC-RPC server --ipcpath Filename for IPC socket/pipe within the datadir [default: .ipc] --ipc.permissions Set the permissions for the IPC socket file, in octal format. If not specified, the permissions will be set by the system's umask. --authrpc.addr Auth server address to listen on [default: 127.0.0.1] --authrpc.port Auth server port to listen on [default: 8551] --authrpc.jwtsecret Path to a JWT secret to use for the authenticated engine-API RPC server. This will enforce JWT authentication for all requests coming from the consensus layer. If no path is provided, a secret will be generated and stored in the datadir under `//jwt.hex`. For mainnet this would be `~/.local/share/reth/mainnet/jwt.hex` by default. --auth-ipc Enable auth engine API over IPC --auth-ipc.path Filename for auth IPC socket/pipe within the datadir [default: _engine_api.ipc] --disable-auth-server Disable the auth/engine API server. This will prevent the authenticated engine-API server from starting. Use this if you're running a node that doesn't need to serve engine API requests. --rpc.jwtsecret Hex encoded JWT secret to authenticate the regular RPC server(s), see `--http.api` and `--ws.api`. This is __not__ used for the authenticated engine-API RPC server, see `--authrpc.jwtsecret`. --rpc.disable-metrics Disable built-in RPC request metrics --rpc.max-request-size Set the maximum RPC request payload size for both HTTP and WS in megabytes [default: 15] --rpc.max-response-size Set the maximum RPC response payload size for both HTTP and WS in megabytes [default: 160] [aliases: --rpc.returndata.limit] --rpc.max-subscriptions-per-connection Set the maximum concurrent subscriptions per connection [default: 1024] --rpc.max-connections Maximum number of RPC server connections [default: 500] --rpc.max-tracing-requests Maximum number of concurrent tracing requests. By default this chooses a sensible value based on the number of available cores. Tracing requests are generally CPU bound. Choosing a value that is higher than the available CPU cores can have a negative impact on the performance of the node and affect the node's ability to maintain sync. [default: ] --rpc.max-blocking-io-requests Maximum number of concurrent blocking IO requests. Blocking IO requests include `eth_call`, `eth_estimateGas`, and similar methods that require EVM execution. These are spawned as blocking tasks to avoid blocking the async runtime. [default: 256] --rpc.max-trace-filter-blocks Maximum number of blocks for `trace_filter` requests [default: 100] --rpc.max-blocks-per-filter Maximum number of blocks that could be scanned per filter request. (0 = entire chain) [default: 100000] --rpc.max-logs-per-response Maximum number of logs that can be returned in a single response. (0 = no limit) [default: 20000] --rpc.gascap Maximum gas limit for `eth_call` and call tracing RPC methods [default: 50000000] --rpc.evm-memory-limit Maximum memory the EVM can allocate per RPC request [default: 4294967295] --rpc.txfeecap Maximum eth transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap) [default: 1.0] --rpc.max-simulate-blocks Maximum number of blocks for `eth_simulateV1` call [default: 256] --rpc.compute-state-root-for-eth-simulate Compute state roots for `eth_simulateV1` responses [env: RETH_RPC_COMPUTE_STATE_ROOT_FOR_ETH_SIMULATE=] --rpc.eth-proof-window The maximum proof window for historical proof generation. This value allows for generating historical proofs up to configured number of blocks from current tip (up to `tip - window`) [default: 0] --rpc.proof-permits Maximum number of concurrent getproof requests [default: 25] --rpc.pending-block Configures the pending block behavior for RPC responses. Options: full (include all transactions), empty (header only), none (disable pending blocks). [default: full] --rpc.forwarder Endpoint to forward transactions to --builder.disallow Path to file containing disallowed addresses, json-encoded list of strings. Block validation API will reject blocks containing transactions from these addresses RPC State Cache: --rpc-cache.max-blocks Max number of blocks in cache [default: 5000] --rpc-cache.max-receipts Max number receipts in cache [default: 2000] --rpc-cache.max-headers Max number of headers in cache [default: 1000] --rpc-cache.max-bals Max number of revm block access lists in cache [default: 1000] --rpc-cache.max-concurrent-db-requests Max number of concurrent database requests [default: 512] --rpc-cache.max-cached-tx-hashes Maximum number of transaction hashes to cache for transaction lookups [default: 30000] Gas Price Oracle: --gpo.blocks Number of recent blocks to check for gas price [default: 20] --gpo.ignoreprice Gas Price below which gpo will ignore transactions [default: 0] --gpo.maxprice Maximum transaction priority fee(or gasprice before London Fork) to be recommended by gpo [default: 500000000000] --gpo.percentile The percentile of gas prices to use for the estimate [default: 60] --gpo.default-suggested-fee The default gas price to use if there are no blocks to use --rpc.send-raw-transaction-sync-timeout Timeout for `send_raw_transaction_sync` RPC method [default: 30s] --testing.skip-invalid-transactions Skip invalid transactions in `testing_buildBlockV1` instead of failing. When enabled, transactions that fail execution will be skipped, and all subsequent transactions from the same sender will also be skipped. --rpc.force-blob-sidecar-upcasting Force upcasting EIP-4844 blob sidecars to EIP-7594 format when Osaka is active. When enabled, blob transactions submitted via `eth_sendRawTransaction` with EIP-4844 sidecars will be automatically converted to EIP-7594 format if the next block is Osaka. By default this is disabled, meaning transactions are submitted as-is. TxPool: --txpool.pending-max-count Max number of transactions in the pending sub-pool [default: 10000] --txpool.pending-max-size Max size of the pending sub-pool in megabytes [default: 20] --txpool.basefee-max-count Max number of transactions in the basefee sub-pool [default: 10000] --txpool.basefee-max-size Max size of the basefee sub-pool in megabytes [default: 20] --txpool.queued-max-count Max number of transactions in the queued sub-pool [default: 10000] --txpool.queued-max-size Max size of the queued sub-pool in megabytes [default: 20] --txpool.blobpool-max-count Max number of transactions in the blobpool [default: 10000] --txpool.blobpool-max-size Max size of the blobpool in megabytes [default: 20] --txpool.blob-cache-size Max number of entries for the in memory cache of the blob store --txpool.disable-blobs-support Disable EIP-4844 blob transaction support --txpool.max-account-slots Max number of executable transaction slots guaranteed per account [default: 16] --txpool.pricebump Price bump (in %) for the transaction pool underpriced check [default: 10] --txpool.minimal-protocol-fee Minimum base fee required by the protocol [default: 7] --txpool.minimum-priority-fee Minimum priority fee required for transaction acceptance into the pool. Transactions with priority fee below this value will be rejected --txpool.gas-limit The default enforced gas limit for transactions entering the pool [default: 30000000] --txpool.max-tx-gas Maximum gas limit for individual transactions. Transactions exceeding this limit will be rejected by the transaction pool --blobpool.pricebump Price bump percentage to replace an already existing blob transaction [default: 100] --txpool.max-tx-input-bytes Max size in bytes of a single transaction allowed to enter the pool [default: 131072] --txpool.max-cached-entries The maximum number of blobs to keep in the in memory blob cache [default: 100] --txpool.nolocals Flag to disable local transaction exemptions --txpool.locals Flag to allow certain addresses as local --txpool.no-local-transactions-propagation Flag to toggle local transaction propagation --txpool.additional-validation-tasks Number of additional transaction validation tasks to spawn [default: 1] --txpool.max-pending-txns Maximum number of pending transactions from the network to buffer [default: 2048] --txpool.max-new-txns Maximum number of new transactions to buffer [default: 1024] --txpool.max-new-pending-txs-notifications How many new pending transactions to buffer and send to in progress pending transaction iterators [default: 200] --txpool.lifetime Maximum amount of time non-executable transaction are queued [default: 10800] --txpool.transactions-backup Path to store the local transaction backup at, to survive node restarts --txpool.disable-transactions-backup Disables transaction backup to disk on node shutdown --txpool.max-batch-size Max batch size for transaction pool insertions [default: 1] Builder: --builder.extradata Block extra data set by the payload builder. If the value is a `0x`-prefixed hex string, it is decoded into raw bytes. Otherwise, the raw UTF-8 bytes of the string are used. [default: reth//] --builder.gaslimit Target gas limit for built blocks --builder.interval The interval at which the job should build a new payload after the last. Interval is specified in seconds or in milliseconds if the value ends with `ms`: * `50ms` -> 50 milliseconds * `1` -> 1 second [default: 1] --builder.deadline The deadline for when the payload builder job should resolve [default: 12] --builder.max-tasks Maximum number of tasks to spawn for building a payload [default: 3] --builder.max-blobs Maximum number of blobs to include per block Debug: --debug.terminate Flag indicating whether the node should be terminated after the pipeline sync --debug.tip Set the chain tip manually for testing purposes. NOTE: This is a temporary flag --debug.max-block Runs the sync only up to the specified block --debug.etherscan [] Runs a fake consensus client that advances the chain using recent block hashes on Etherscan. If specified, requires an `ETHERSCAN_API_KEY` environment variable --debug.rpc-consensus-url Runs a fake consensus client using blocks fetched from an RPC endpoint. Supports both HTTP and `WebSocket` endpoints - `WebSocket` endpoints will use subscriptions, while HTTP endpoints will poll for new blocks --debug.skip-fcu If provided, the engine will skip `n` consecutive FCUs --debug.skip-new-payload If provided, the engine will skip `n` consecutive new payloads --debug.skip-genesis-validation If set, bypasses genesis hash validation during init. Intended for tools that direct-write the database (e.g. snapshot importers, state-actor) and want reth to trust the DB-resident genesis state instead of recomputing it from the chainspec's alloc. When the bypass fires, a structured `tracing::warn!` is emitted so the divergence stays observable in operator logs --debug.reorg-frequency If provided, the chain will be reorged at specified frequency --debug.reorg-depth The reorg depth for chain reorgs --debug.engine-api-store The path to store engine API messages at. If specified, all of the intercepted engine API messages will be written to specified location --debug.invalid-block-hook Determines which type of invalid block hook to install Example: `witness,prestate` [default: witness] [possible values: witness, pre-state, opcode] --debug.healthy-node-rpc-url The RPC URL of a healthy node to use for comparing invalid block hook results against. Debug setting that enables execution witness comparison for troubleshooting bad blocks. When enabled, the node will collect execution witnesses from the specified source and compare them against local execution when a bad block is encountered, helping identify discrepancies in state execution. --ethstats The URL of the ethstats server to connect to. Example: `nodename:secret@host:port` --debug.startup-sync-state-idle Set the node to idle state when the backfill is not running. This makes the `eth_syncing` RPC return "Idle" when the node has just started or finished the backfill, but did not yet receive any new blocks. Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Dev testnet: --dev Start the node in dev mode This mode uses a local proof-of-authority consensus engine with either fixed block times or automatically mined blocks. Disables network discovery and enables local http server. Prefunds 20 accounts derived by mnemonic "test test test test test test test test test test test junk" with 10 000 ETH each. --dev.block-max-transactions How many transactions to mine per block --dev.block-time Interval between blocks. Parses strings using [`humantime::parse_duration`] --dev.block-time 12s --dev.payload-wait-time Time to wait after initiating payload building before resolving. Introduces a sleep between `fork_choice_updated` and `resolve_kind` in the local miner, giving the payload job time for multiple rebuild attempts with new transactions from the pool. Parses strings using [`humantime::parse_duration`] --dev.payload-wait-time 450ms --dev.mnemonic Derive dev accounts from a fixed mnemonic instead of random ones. [default: "test test test test test test test test test test test junk"] Pruning: --full Run full node. Only the most recent [`MINIMUM_UNWIND_SAFE_DISTANCE`] block states are stored --minimal Run minimal storage mode with maximum pruning and smaller static files. This mode configures the node to use minimal disk space by: - Fully pruning sender recovery, transaction lookup, receipts - Leaving 10,064 blocks for account, storage history and block bodies - Using 10,000 blocks per static file segment --prune.block-interval Minimum pruning interval measured in blocks --prune.sender-recovery.full Prunes all sender recovery data --prune.sender-recovery.distance Prune sender recovery data before the `head-N` block number. In other words, keep last N + 1 blocks --prune.sender-recovery.before Prune sender recovery data before the specified block number. The specified block number is not pruned --prune.transaction-lookup.full Prunes all transaction lookup data --prune.transaction-lookup.distance Prune transaction lookup data before the `head-N` block number. In other words, keep last N + 1 blocks --prune.transaction-lookup.before Prune transaction lookup data before the specified block number. The specified block number is not pruned --prune.receipts.full Prunes all receipt data --prune.receipts.pre-merge Prune receipts before the merge block --prune.receipts.distance Prune receipts before the `head-N` block number. In other words, keep last N + 1 blocks --prune.receipts.before Prune receipts before the specified block number. The specified block number is not pruned --prune.receiptslogfilter Configure receipts log filter. Format: <`address`>:<`prune_mode`>... where <`prune_mode`> can be 'full', 'distance:<`blocks`>', or 'before:<`block_number`>' --prune.account-history.full Prunes all account history --prune.account-history.distance Prune account before the `head-N` block number. In other words, keep last N + 1 blocks --prune.account-history.before Prune account history before the specified block number. The specified block number is not pruned --prune.storage-history.full Prunes all storage history data --prune.storage-history.distance Prune storage history before the `head-N` block number. In other words, keep last N + 1 blocks --prune.storage-history.before Prune storage history before the specified block number. The specified block number is not pruned --prune.bodies.pre-merge Prune bodies before the merge block --prune.bodies.distance Prune bodies before the `head-N` block number. In other words, keep last N + 1 blocks --prune.bodies.before Prune storage history before the specified block number. The specified block number is not pruned --prune.minimum-distance Minimum pruning distance from the tip. This controls the safety margin for reorgs and manual unwinds Engine: --engine.persistence-threshold Configure persistence threshold for the engine. This determines how many canonical blocks must be in-memory, ahead of the last persisted block, before flushing canonical blocks to disk again. To persist blocks as fast as the node receives them, set this value to zero. This will cause more frequent DB writes. [default: 2] --engine.persistence-backpressure-threshold Configure the maximum canonical-minus-persisted gap before engine API processing stalls. If omitted, this defaults to the larger of the default backpressure threshold and twice `--engine.persistence-threshold`. This value must be greater than `--engine.persistence-threshold`. --engine.memory-block-buffer-target Configure the target number of blocks to keep in memory [default: 0] --engine.invalid-header-cache-hit-eviction-threshold Configure how many cache hits an invalid header can accumulate before it is evicted and reprocessed. Set to `0` to effectively disable the cache because entries are evicted on the first lookup. [default: 128] --engine.disable-state-cache Disable state cache --engine.disable-prewarming Disable parallel prewarming --engine.state-provider-metrics Enable state provider latency metrics. This allows the engine to collect and report stats about how long state provider calls took during execution, but this does introduce slight overhead to state provider calls --engine.cross-block-cache-size Configure the size of cross-block cache in megabytes [default: 4096] --engine.state-root-task-compare-updates Enable comparing trie updates from the state root task to the trie updates from the regular state root calculation --engine.accept-execution-requests-hash Enables accepting requests hash instead of an array of requests in `engine_newPayloadV4` --engine.multiproof-chunk-size Multiproof task chunk size for proof targets [default: 5] --engine.reserved-cpu-cores Configure the number of reserved CPU cores for non-reth processes [default: 1] --engine.disable-precompile-cache Disable precompile cache --engine.state-root-fallback Enable state root fallback, useful for testing --engine.always-process-payload-attributes-on-canonical-head Always process payload attributes and begin a payload build process even if `forkchoiceState.headBlockHash` is already the canonical head or an ancestor. See `TreeConfig::always_process_payload_attributes_on_canonical_head` for more details. Note: This is a no-op on OP Stack. --engine.allow-unwind-canonical-header Allow unwinding canonical header to ancestor during forkchoice updates. See `TreeConfig::unwind_canonical_header` for more details --engine.storage-worker-count Configure the number of storage proof workers in the Tokio blocking pool. If not specified, defaults to 2x available parallelism --engine.account-worker-count Configure the number of account proof workers in the Tokio blocking pool. If not specified, defaults to the same count as storage workers --engine.prewarming-threads Configure the number of prewarming threads. If not specified, defaults to available parallelism --engine.disable-cache-metrics Disable cache metrics recording, which can take up to 50ms with large cached state --engine.sparse-trie-max-hot-slots LFU hot-slot capacity: max storage slots retained across sparse trie prune cycles [default: 1500] --engine.sparse-trie-max-hot-accounts LFU hot-account capacity: max account addresses retained across sparse trie prune cycles [default: 1000] --engine.slow-block-threshold Configure the slow block logging threshold in milliseconds. When set, blocks that take longer than this threshold to execute will be logged with detailed metrics including timing, state operations, and cache statistics. Set to 0 to log all blocks (useful for debugging/profiling). When not set, slow block logging is disabled (default). --engine.disable-sparse-trie-cache-pruning Fully disable sparse trie cache pruning. When set, the cached sparse trie is preserved without any node pruning or storage trie eviction between blocks. Useful for benchmarking the effects of retaining the full trie cache --engine.state-root-task-timeout Configure the timeout for the state root task before spawning a sequential fallback. If the state root task takes longer than this, a sequential computation starts in parallel and whichever finishes first is used. --engine.state-root-task-timeout 4s --engine.state-root-task-timeout 400ms Set to 0s to disable. [default: 4s] --engine.share-execution-cache-with-payload-builder Whether to share execution cache with the payload builder. When enabled, each payload job will get an instance of cross-block execution cache from the engine. Note: this should only be enabled if node would not be requested to process any payloads in parallel with payload building. --engine.share-sparse-trie-with-payload-builder Whether to share the sparse trie with the payload builder. Replaces the payload builder's blocking `state_root_with_updates()` call with the sparse trie, computing the state root concurrently with transaction execution. The engine and payload builder contend for the same trie — if a builder task is still running when `newPayload` arrives, the engine will block until the trie is stored back. The builder also anchors the trie at the built block's state root, so if the next `newPayload` is not on top of that block, the trie cache is invalidated and cleared. --engine.suppress-persistence-during-build Suppress persistence while building a payload. When enabled, persistence cycles are deferred from the moment an FCU with payload attributes arrives until the next FCU clears the build. Useful on chains with short block times where persistence I/O can interfere with block building latency. --engine.disable-bal-parallel-execution Disable BAL (Block Access List, EIP-7928) based parallel execution --engine.disable-bal-parallel-state-root Disable BAL-driven parallel state root computation. This is only valid together with `--engine.disable-bal-parallel-execution` --engine.disable-bal-batch-io Disable BAL (Block Access List) storage prefetch IO during prewarming. When set, BAL storage slots are not read into the execution cache ERA: --era.enable Enable import from ERA1 files --era.path The path to a directory for import. The ERA1 files are read from the local directory parsing headers and bodies. --era.url The URL to a remote host where the ERA1 files are hosted. The ERA1 files are read from the remote host using HTTP GET requests parsing headers and bodies. Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] JIT: --jit Enable JIT compilation of EVM bytecode --jit.hot-threshold Number of observed misses before a bytecode is promoted to JIT compilation [default: 8] --jit.worker-count Number of JIT compilation worker threads --jit.channel-capacity Capacity of the lookup-observed event channel. Events are silently dropped when the channel is full [default: 4096] --jit.max-pending-jobs Maximum number of pending JIT compilation jobs [default: 2048] --jit.max-bytecode-len Maximum bytecode length eligible for JIT compilation. Contracts with bytecode larger than this are never promoted to JIT. 0 means no limit [default: 0] --jit.code-cache-bytes Maximum total resident compiled code size in bytes. When exceeded, the backend evicts least-recently-used entries. 0 means no limit [default: 1073741824] --jit.idle-evict-duration Duration after which a compiled program with no lookup hits is evicted [default: 1h] --jit.debug Enable compiler debug dumps. IR, assembly, and bytecode are written to `/jit///` for each compiled contract. Note that this is not ever cleaned up, and has a non negligible performance overhead. Rollup: --rollup.sequencer Endpoint for the sequencer mempool (can be both HTTP and WS) [aliases: --rollup.sequencer-http, --rollup.sequencer-ws] --rollup.disable-tx-pool-gossip Disable transaction pool gossip --rollup.compute-pending-block By default the pending block equals the latest block to save resources and not leak txs from the tx-pool, this flag enables computing of the pending block from the tx-pool instead. If `compute_pending_block` is not enabled, the payload builder will use the payload attributes from the latest block. Note that this flag is not yet functional. --rollup.discovery.v4 enables discovery v4 if provided --rollup.enable-tx-conditional Enable transaction conditional support on sequencer --rollup.retain-forwarded-txs Retain RPC-submitted transactions in the local pool after forwarding them to the sequencer. This flag only has an effect when `rollup.sequencer` is present. --rollup.operator-sdm-opt-in Local operator opt-in for SDM `PostExec` production at process boot. The admin RPC (`admin_setOperatorSdmOptIn`) can still toggle it at runtime. Defaults to disabled [env: OP_RETH_OPERATOR_SDM_OPT_IN=] [default: false] [possible values: true, false] --rollup.interop-http HTTP endpoint(s) for the interop filter, used to validate the interop messages referenced by incoming transactions. Repeat the flag to configure multiple endpoints; each check is fanned out to all of them and combined by quorum agreement (see `--rollup.interop-min-responses`). When none are set, interop transaction validation is disabled: a node that builds blocks will then include transactions carrying invalid interop messages, producing invalid blocks. It is only safe to leave this unset on nodes that do not build blocks --rollup.interop-min-responses Minimum number of definitive verdicts required to decide an interop check across the configured `--rollup.interop-http` endpoints. A transaction is accepted only when this many endpoints return a definitive verdict and all of them agree it is valid; if they disagree the transaction is rejected. Defaults to the number of endpoints (unanimity, fail-closed). Note this means any single unreachable or out-of-sync endpoint blocks ALL interop admission until it recovers, so adding endpoints under the default REDUCES availability. Set a majority quorum (e.g. N/2+1) to tolerate a degraded endpoint while still only accepting on unanimous agreement among responders. Disagreement detection is best-effort: once the quorum is reached the remaining endpoints are not awaited, so a slow dissenter beyond the quorum may go unseen. --rollup.interop-safety-level Safety level for interop filter validation [default: CrossUnsafe] --rollup.sequencer-headers Optional headers to use when connecting to the sequencer --rollup.historicalrpc RPC endpoint for historical data --min-suggested-priority-fee Minimum suggested priority fee (tip) in wei, default `1_000_000` [default: 1000000] --rollup.max-uncompressed-block-size Maximum cumulative uncompressed (EIP-2718 encoded) block size in bytes. When set, the payload builder stops including mempool transactions once the block's total uncompressed transaction size would exceed this value. This bounds the size of the `engine_getPayload` response so it stays within the limits assumed by consensus-layer clients (e.g. the common 10 MiB JSON payload cap). Unset means no limit. --flashblocks-url A URL pointing to a secure websocket subscription that streams out flashblocks. If given, the flashblocks are received to build pending block. All request with "pending" block tag will use the pending state based on flashblocks. --flashblock-consensus Enable flashblock consensus client to drive the chain forward When enabled, the flashblock consensus client will process flashblock sequences and submit them to the engine API to advance the chain. Requires `flashblocks_url` to be set. --proofs-history If true, initialize external-proofs exex to save and serve trie nodes to provide proofs faster --proofs-history.storage-path Path to the proofs-history storage DB. Defaults to `/historical-proofs` (chain-namespaced via reth's `--datadir`) --proofs-history.storage-version Storage schema version. Must match the version used when starting the node Possible values: - v1: V1 storage schema (original single-table-per-domain layout). Default - v2: V2 storage schema with changeset and history-bitmap tables, enabling history-aware reads at any block number within the proof window [default: v1] --proofs-history.window The window to span blocks for proofs history. Value is the number of blocks. Default is 1 month of blocks based on 2 seconds block time (`30 * 24 * 60 * 60 / 2 = 1_296_000`) [default: 1296000] --proofs-history.verification-interval Verification interval: perform full block execution every N blocks for data integrity. - 0: Disabled (Default) (always use fast path with pre-computed data from notifications) - 1: Always verify (always execute blocks, slowest) - N: Verify every Nth block (e.g., 100 = every 100 blocks) Periodic verification helps catch data corruption or consensus bugs while maintaining good performance. CLI: `--proofs-history.verification-interval 100` [default: 0] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth p2p Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/p2p P2P Debugging utilities ```bash theme={null} $ op-reth p2p --help ``` ```txt theme={null} Usage: op-reth p2p [OPTIONS] Commands: header Download block header body Download block body rlpx RLPx commands bootnode Bootnode command enode Print enode identifier help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth p2p body Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/p2p/body Download block body ```bash theme={null} $ op-reth p2p body --help ``` ```txt theme={null} Usage: op-reth p2p body [OPTIONS] Options: --retries The number of retries per request [default: 5] -h, --help Print help (see a summary with '-h') Networking: -d, --disable-discovery Disable the discovery service --disable-dns-discovery Disable the DNS discovery --disable-discv4-discovery Disable Discv4 discovery --disable-discv5-discovery Disable Discv5 discovery --disable-nat Disable Nat discovery --discovery.addr The UDP address to use for devp2p peer discovery version 4. If unset and `--net-if.experimental` is used, discv4 binds to the resolved interface address. [default: 0.0.0.0] --discovery.port The UDP port to use for devp2p peer discovery version 4 [default: 30303] --discovery.v5.addr The UDP IPv4 address to use for devp2p peer discovery version 5. Overwritten by `RLPx` address, if it's also IPv4 --discovery.v5.addr.ipv6 The UDP IPv6 address to use for devp2p peer discovery version 5. Overwritten by `RLPx` address, if it's also IPv6 --discovery.v5.port The UDP IPv4 port to use for devp2p peer discovery version 5. Not used unless `--addr` is IPv4, or `--discovery.v5.addr` is set [default: 9200] --discovery.v5.port.ipv6 The UDP IPv6 port to use for devp2p peer discovery version 5. Not used unless `--addr` is IPv6, or `--discovery.addr.ipv6` is set. If not provided, discovery V5 defaults to same port as discovery V4 (--discovery.port). [default: 9200] --discovery.v5.lookup-interval The interval in seconds at which to carry out periodic lookup queries, for the whole run of the program [default: 20] --discovery.v5.bootstrap.lookup-interval The interval in seconds at which to carry out boost lookup queries, for a fixed number of times, at bootstrap [default: 5] --discovery.v5.bootstrap.lookup-countdown The number of times to carry out boost lookup queries at bootstrap [default: 200] --trusted-peers Comma separated enode URLs of trusted peers for P2P connections. --trusted-peers enode://abcd@192.168.0.1:30303 --trusted-only Connect to or accept from trusted peers only --bootnodes Comma separated enode URLs for P2P discovery bootstrap. Will fall back to a network-specific default if not specified. --dns-retries Amount of DNS resolution requests retries to perform when peering [default: 0] --peers-file The path to the known peers file. Connected peers are dumped to this file on nodes shutdown, and read on startup. Cannot be used with `--no-persist-peers`. --identity Custom node identity [default: op-reth/-/] --p2p-secret-key Secret key to use for this node. This will also deterministically set the peer ID. If not specified, it will be set in the data dir for the chain being used. --p2p-secret-key-hex Hex encoded secret key to use for this node. This will also deterministically set the peer ID. Cannot be used together with `--p2p-secret-key`. --no-persist-peers Do not persist peers. --nat NAT resolution method (any|none|upnp|publicip|extip:\) [default: any] --addr Network listening address [default: 0.0.0.0] --port Network listening port [default: 30303] --max-outbound-peers Maximum number of outbound peers. default: 100 --max-inbound-peers Maximum number of inbound peers. default: 30 --max-peers Maximum number of total peers (inbound + outbound). Splits peers using approximately 2:1 inbound:outbound ratio. Cannot be used together with `--max-outbound-peers` or `--max-inbound-peers`. --max-tx-reqs Max concurrent `GetPooledTransactions` requests. [default: 130] --max-tx-reqs-peer Max concurrent `GetPooledTransactions` requests per peer. [default: 1] --max-seen-tx-history Max number of seen transactions to remember per peer. Default is 320 transaction hashes. [default: 320] --max-pending-imports Max number of transactions to import concurrently. [default: 4096] --pooled-tx-response-soft-limit Experimental, for usage in research. Sets the max accumulated byte size of transactions to pack in one response. Spec'd at 2MiB. [default: 2097152] --pooled-tx-pack-soft-limit Experimental, for usage in research. Sets the max accumulated byte size of transactions to request in one request. Since `RLPx` protocol version 68, the byte size of a transaction is shared as metadata in a transaction announcement (see `RLPx` specs). This allows a node to request a specific size response. By default, nodes request only 128 KiB worth of transactions, but should a peer request more, up to 2 MiB, a node will answer with more than 128 KiB. Default is 128 KiB. [default: 131072] --max-tx-pending-fetch Max capacity of cache of hashes for transactions pending fetch. [default: 25600] --tx-channel-memory-limit Memory limit (in bytes) for the channel that buffers transaction events flowing from the network manager to the transactions manager. When the budget is exhausted, new events are dropped (see metric `total_dropped_tx_events_at_full_capacity`). Acts as a backstop against unbounded memory growth under sustained P2P transaction flooding. [default: 1073741824] --net-if.experimental Name of network interface used to communicate with peers. If flag is set, but no value is passed, the default interface for docker `eth0` is tried. If `--discovery.addr` is left at its default, discv4 will also bind to the resolved interface address. --tx-propagation-policy Transaction Propagation Policy The policy determines which peers transactions are gossiped to. [default: All] --tx-ingress-policy Transaction ingress policy Determines which peers' transactions are accepted over P2P. [default: All] --disable-tx-gossip Disable transaction pool gossip Disables gossiping of transactions in the mempool to peers. This can be omitted for personal nodes, though providers should always opt to enable this flag. --tx-propagation-mode Sets the transaction propagation mode by determining how new pending transactions are propagated to other peers in full. Examples: sqrt, all, max:10 [default: sqrt] --required-block-hashes Comma separated list of required block hashes or block number=hash pairs. Peers that don't have these blocks will be filtered out. Format: hash or `block_number=hash` (e.g., 23115201=0x1234...) --network-id Optional network ID to override the chain specification's network ID for P2P connections --eth-max-message-size Maximum allowed ETH message size in bytes. Default is 10 MiB --netrestrict Restrict network communication to the given IP networks (CIDR masks). Comma separated list of CIDR network specifications. Only peers with IP addresses within these ranges will be allowed to connect. Example: --netrestrict "192.168.0.0/16,10.0.0.0/8" --enforce-enr-fork-id Enforce EIP-868 ENR fork ID validation for discovered peers. When enabled, peers discovered without a confirmed fork ID are not added to the peer set until their fork ID is verified via EIP-868 ENR request. This filters out peers from other networks that pollute the discovery table. Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use. --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] The block number or hash Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth p2p bootnode Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/p2p/bootnode Bootnode command ```bash theme={null} $ op-reth p2p bootnode --help ``` ```txt theme={null} Usage: op-reth p2p bootnode [OPTIONS] Options: --addr Listen address for the bootnode (default: "0.0.0.0:30301") [default: 0.0.0.0:30301] --p2p-secret-key Secret key to use for the bootnode. This will also deterministically set the peer ID. If a path is provided but no key exists at that path, a new random secret will be generated and stored there. If no path is specified, a new ephemeral random secret will be used. --nat NAT resolution method (any|none|upnp|publicip|extip:\). Can be repeated with one IPv4 and one IPv6 `extip:` to advertise a dual-stack discv5 ENR (discv4 binds a single socket and always advertises only the `--addr` family). [default: any] --v5 Also run discv5, sharing the discv4 UDP port (`--addr`) -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth p2p enode Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/p2p/enode Print enode identifier ```bash theme={null} $ op-reth p2p enode --help ``` ```txt theme={null} Usage: op-reth p2p enode [OPTIONS] Arguments: Path to the secret key file for discovery Options: --ip Optional IP address to include in the enode URL. If not provided, defaults to 0.0.0.0. -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth p2p header Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/p2p/header Download block header ```bash theme={null} $ op-reth p2p header --help ``` ```txt theme={null} Usage: op-reth p2p header [OPTIONS] Options: --retries The number of retries per request [default: 5] -h, --help Print help (see a summary with '-h') Networking: -d, --disable-discovery Disable the discovery service --disable-dns-discovery Disable the DNS discovery --disable-discv4-discovery Disable Discv4 discovery --disable-discv5-discovery Disable Discv5 discovery --disable-nat Disable Nat discovery --discovery.addr The UDP address to use for devp2p peer discovery version 4. If unset and `--net-if.experimental` is used, discv4 binds to the resolved interface address. [default: 0.0.0.0] --discovery.port The UDP port to use for devp2p peer discovery version 4 [default: 30303] --discovery.v5.addr The UDP IPv4 address to use for devp2p peer discovery version 5. Overwritten by `RLPx` address, if it's also IPv4 --discovery.v5.addr.ipv6 The UDP IPv6 address to use for devp2p peer discovery version 5. Overwritten by `RLPx` address, if it's also IPv6 --discovery.v5.port The UDP IPv4 port to use for devp2p peer discovery version 5. Not used unless `--addr` is IPv4, or `--discovery.v5.addr` is set [default: 9200] --discovery.v5.port.ipv6 The UDP IPv6 port to use for devp2p peer discovery version 5. Not used unless `--addr` is IPv6, or `--discovery.addr.ipv6` is set. If not provided, discovery V5 defaults to same port as discovery V4 (--discovery.port). [default: 9200] --discovery.v5.lookup-interval The interval in seconds at which to carry out periodic lookup queries, for the whole run of the program [default: 20] --discovery.v5.bootstrap.lookup-interval The interval in seconds at which to carry out boost lookup queries, for a fixed number of times, at bootstrap [default: 5] --discovery.v5.bootstrap.lookup-countdown The number of times to carry out boost lookup queries at bootstrap [default: 200] --trusted-peers Comma separated enode URLs of trusted peers for P2P connections. --trusted-peers enode://abcd@192.168.0.1:30303 --trusted-only Connect to or accept from trusted peers only --bootnodes Comma separated enode URLs for P2P discovery bootstrap. Will fall back to a network-specific default if not specified. --dns-retries Amount of DNS resolution requests retries to perform when peering [default: 0] --peers-file The path to the known peers file. Connected peers are dumped to this file on nodes shutdown, and read on startup. Cannot be used with `--no-persist-peers`. --identity Custom node identity [default: op-reth/-/] --p2p-secret-key Secret key to use for this node. This will also deterministically set the peer ID. If not specified, it will be set in the data dir for the chain being used. --p2p-secret-key-hex Hex encoded secret key to use for this node. This will also deterministically set the peer ID. Cannot be used together with `--p2p-secret-key`. --no-persist-peers Do not persist peers. --nat NAT resolution method (any|none|upnp|publicip|extip:\) [default: any] --addr Network listening address [default: 0.0.0.0] --port Network listening port [default: 30303] --max-outbound-peers Maximum number of outbound peers. default: 100 --max-inbound-peers Maximum number of inbound peers. default: 30 --max-peers Maximum number of total peers (inbound + outbound). Splits peers using approximately 2:1 inbound:outbound ratio. Cannot be used together with `--max-outbound-peers` or `--max-inbound-peers`. --max-tx-reqs Max concurrent `GetPooledTransactions` requests. [default: 130] --max-tx-reqs-peer Max concurrent `GetPooledTransactions` requests per peer. [default: 1] --max-seen-tx-history Max number of seen transactions to remember per peer. Default is 320 transaction hashes. [default: 320] --max-pending-imports Max number of transactions to import concurrently. [default: 4096] --pooled-tx-response-soft-limit Experimental, for usage in research. Sets the max accumulated byte size of transactions to pack in one response. Spec'd at 2MiB. [default: 2097152] --pooled-tx-pack-soft-limit Experimental, for usage in research. Sets the max accumulated byte size of transactions to request in one request. Since `RLPx` protocol version 68, the byte size of a transaction is shared as metadata in a transaction announcement (see `RLPx` specs). This allows a node to request a specific size response. By default, nodes request only 128 KiB worth of transactions, but should a peer request more, up to 2 MiB, a node will answer with more than 128 KiB. Default is 128 KiB. [default: 131072] --max-tx-pending-fetch Max capacity of cache of hashes for transactions pending fetch. [default: 25600] --tx-channel-memory-limit Memory limit (in bytes) for the channel that buffers transaction events flowing from the network manager to the transactions manager. When the budget is exhausted, new events are dropped (see metric `total_dropped_tx_events_at_full_capacity`). Acts as a backstop against unbounded memory growth under sustained P2P transaction flooding. [default: 1073741824] --net-if.experimental Name of network interface used to communicate with peers. If flag is set, but no value is passed, the default interface for docker `eth0` is tried. If `--discovery.addr` is left at its default, discv4 will also bind to the resolved interface address. --tx-propagation-policy Transaction Propagation Policy The policy determines which peers transactions are gossiped to. [default: All] --tx-ingress-policy Transaction ingress policy Determines which peers' transactions are accepted over P2P. [default: All] --disable-tx-gossip Disable transaction pool gossip Disables gossiping of transactions in the mempool to peers. This can be omitted for personal nodes, though providers should always opt to enable this flag. --tx-propagation-mode Sets the transaction propagation mode by determining how new pending transactions are propagated to other peers in full. Examples: sqrt, all, max:10 [default: sqrt] --required-block-hashes Comma separated list of required block hashes or block number=hash pairs. Peers that don't have these blocks will be filtered out. Format: hash or `block_number=hash` (e.g., 23115201=0x1234...) --network-id Optional network ID to override the chain specification's network ID for P2P connections --eth-max-message-size Maximum allowed ETH message size in bytes. Default is 10 MiB --netrestrict Restrict network communication to the given IP networks (CIDR masks). Comma separated list of CIDR network specifications. Only peers with IP addresses within these ranges will be allowed to connect. Example: --netrestrict "192.168.0.0/16,10.0.0.0/8" --enforce-enr-fork-id Enforce EIP-868 ENR fork ID validation for discovered peers. When enabled, peers discovered without a confirmed fork ID are not added to the peer set until their fork ID is verified via EIP-868 ENR request. This filters out peers from other networks that pollute the discovery table. Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use. --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] The header number or hash Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth p2p rlpx Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/p2p/rlpx RLPx commands ```bash theme={null} $ op-reth p2p rlpx --help ``` ```txt theme={null} Usage: op-reth p2p rlpx [OPTIONS] Commands: ping ping node help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth p2p rlpx ping Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/p2p/rlpx/ping ping node ```bash theme={null} $ op-reth p2p rlpx ping --help ``` ```txt theme={null} Usage: op-reth p2p rlpx ping [OPTIONS] Arguments: The node to ping Options: -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth proofs Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/proofs Manage storage of historical proofs in expanded trie db in fault proof window ```bash theme={null} $ op-reth proofs --help ``` ```txt theme={null} Usage: op-reth proofs [OPTIONS] Commands: init Initialize the proofs storage with the current state of the chain backfill Backfill proofs history to an older earliest block prune Prune old proof history to reclaim space snapshot Build or drop the trie-state snapshot unwind Unwind the proofs storage to a specific block help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth proofs backfill Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/proofs/backfill Backfill proofs history to an older earliest block ```bash theme={null} $ op-reth proofs backfill --help ``` ```txt theme={null} Usage: op-reth proofs backfill [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --proofs-history.storage-path Path to the proofs-history storage DB. Defaults to `/historical-proofs` (chain-namespaced via reth's `--datadir`) --proofs-history.storage-version Storage schema version. Must match the version used when starting the node Possible values: - v1: V1 storage schema (original single-table-per-domain layout). Default - v2: V2 storage schema with changeset and history-bitmap tables, enabling history-aware reads at any block number within the proof window [default: v1] --proofs-history.window The window to span blocks for proofs history. Value is the number of blocks. Default is 1 month of blocks based on 2 seconds block time (`30 * 24 * 60 * 60 / 2 = 1_296_000`) [default: 1296000] --proofs-history.backfill-batch-size Number of blocks committed per MDBX write transaction (>= 1). Larger N amortizes commit/fsync; trade-off is higher peak RSS and up to N blocks of progress lost on crash. Very large N can also exceed MDBX's per-tx dirty-page ceiling on storage-heavy blocks — the batch fails cleanly (whole tx rolls back) and can be retried with a lower value. Default 25 measured ~2.6× throughput vs K=1 on op-mainnet — the sweet spot on the K sweep before dirty-page pressure starts slowing cursor reads. [default: 25] --proofs-history.use-snapshot [] Use the trie-state snapshot to accelerate per-block reads during backfill. If no snapshot exists, one is bootstrapped at the current `earliest` before the backfill loop begins. Requires v2 storage. Defaults to `true`. Pass `--proofs-history.use-snapshot false` to force the non-snapshot path (per-block reads via the reth DB). [default: true] [possible values: true, false] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth proofs init Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/proofs/init Initialize the proofs storage with the current state of the chain ```bash theme={null} $ op-reth proofs init --help ``` ```txt theme={null} Usage: op-reth proofs init [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --proofs-history.storage-path Path to the proofs-history storage DB. Defaults to `/historical-proofs` (chain-namespaced via reth's `--datadir`) --proofs-history.storage-version Storage schema version. Must match the version used when starting the node Possible values: - v1: V1 storage schema (original single-table-per-domain layout). Default - v2: V2 storage schema with changeset and history-bitmap tables, enabling history-aware reads at any block number within the proof window [default: v1] --proofs-history.skip-backfill Skip the post-init backward backfill. By default, after the snapshot of the current chain state is captured the proof window is extended back by `--proofs-history.window` blocks using the snapshot-accelerated path. Set this flag to leave the window at `[latest, latest]` and run `op-proofs backfill` later instead. No effect on V1 storage (V1 does not support backfill) --proofs-history.window The window to span blocks for proofs history. Value is the number of blocks. Default is 1 month of blocks based on 2 seconds block time (`30 * 24 * 60 * 60 / 2 = 1_296_000`) [default: 1296000] --proofs-history.backfill-batch-size Number of blocks committed per MDBX write transaction (>= 1). Larger N amortizes commit/fsync; trade-off is higher peak RSS and up to N blocks of progress lost on crash. Very large N can also exceed MDBX's per-tx dirty-page ceiling on storage-heavy blocks — the batch fails cleanly (whole tx rolls back) and can be retried with a lower value. Default 25 measured ~2.6× throughput vs K=1 on op-mainnet — the sweet spot on the K sweep before dirty-page pressure starts slowing cursor reads. [default: 25] --proofs-history.use-snapshot [] Use the trie-state snapshot to accelerate per-block reads during backfill. If no snapshot exists, one is bootstrapped at the current `earliest` before the backfill loop begins. Requires v2 storage. Defaults to `true`. Pass `--proofs-history.use-snapshot false` to force the non-snapshot path (per-block reads via the reth DB). [default: true] [possible values: true, false] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth proofs prune Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/proofs/prune Prune old proof history to reclaim space ```bash theme={null} $ op-reth proofs prune --help ``` ```txt theme={null} Usage: op-reth proofs prune [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --proofs-history.storage-path Path to the proofs-history storage DB. Defaults to `/historical-proofs` (chain-namespaced via reth's `--datadir`) --proofs-history.storage-version Storage schema version. Must match the version used when starting the node Possible values: - v1: V1 storage schema (original single-table-per-domain layout). Default - v2: V2 storage schema with changeset and history-bitmap tables, enabling history-aware reads at any block number within the proof window [default: v1] --proofs-history.window The window to span blocks for proofs history. Value is the number of blocks. Default is 1 month of blocks based on 2 seconds block time (`30 * 24 * 60 * 60 / 2 = 1_296_000`) [default: 1296000] --proofs-history.prune-batch-size The batch size for pruning operations [default: 1000] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth proofs snapshot Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/proofs/snapshot Build or drop the trie-state snapshot ```bash theme={null} $ op-reth proofs snapshot --help ``` ```txt theme={null} Usage: op-reth proofs snapshot [OPTIONS] Commands: init Build a snapshot at a target block and mark it Ready drop Drop the snapshot tables and meta row help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth proofs snapshot drop Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/proofs/snapshot/drop Drop the snapshot tables and meta row ```bash theme={null} $ op-reth proofs snapshot drop --help ``` ```txt theme={null} Usage: op-reth proofs snapshot drop [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --proofs-history.storage-path Path to the proofs-history storage DB. Defaults to `/historical-proofs` (chain-namespaced via reth's `--datadir`) --proofs-history.storage-version Storage schema version. Must match the version used when starting the node Possible values: - v1: V1 storage schema (original single-table-per-domain layout). Default - v2: V2 storage schema with changeset and history-bitmap tables, enabling history-aware reads at any block number within the proof window [default: v1] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth proofs snapshot init Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/proofs/snapshot/init Build a snapshot at a target block and mark it Ready ```bash theme={null} $ op-reth proofs snapshot init --help ``` ```txt theme={null} Usage: op-reth proofs snapshot init [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --proofs-history.storage-path Path to the proofs-history storage DB. Defaults to `/historical-proofs` (chain-namespaced via reth's `--datadir`) --proofs-history.storage-version Storage schema version. Must match the version used when starting the node Possible values: - v1: V1 storage schema (original single-table-per-domain layout). Default - v2: V2 storage schema with changeset and history-bitmap tables, enabling history-aware reads at any block number within the proof window [default: v1] --proofs-history.snapshot-target-block Target block for the snapshot anchor. Must fall inside the proofs window `[earliest, latest]`. Defaults to `earliest` — that's the anchor the snapshot-accelerated backfill flow picks up Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth proofs unwind Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/proofs/unwind Unwind the proofs storage to a specific block ```bash theme={null} $ op-reth proofs unwind --help ``` ```txt theme={null} Usage: op-reth proofs unwind [OPTIONS] --target Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --proofs-history.storage-path Path to the proofs-history storage DB. Defaults to `/historical-proofs` (chain-namespaced via reth's `--datadir`) --proofs-history.storage-version Storage schema version. Must match the version used when starting the node Possible values: - v1: V1 storage schema (original single-table-per-domain layout). Default - v2: V2 storage schema with changeset and history-bitmap tables, enabling history-aware reads at any block number within the proof window [default: v1] --target The target block number to unwind to. All history *after* this block will be removed. Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth prune Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/prune Prune according to the configuration without any limits ```bash theme={null} $ op-reth prune --help ``` ```txt theme={null} Usage: op-reth prune [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] Metrics: --metrics Enable Prometheus metrics. The metrics will be served at the given interface and port. --metrics.prometheus.push.url URL for pushing Prometheus metrics to a push gateway. If set, the node will periodically push metrics to the specified push gateway URL. --metrics.prometheus.push.interval Interval in seconds for pushing metrics to push gateway. Default: 5 seconds [default: 5] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth re-execute Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/re-execute Re-execute blocks in parallel to verify historical sync correctness ```bash theme={null} $ op-reth re-execute --help ``` ```txt theme={null} Usage: op-reth re-execute [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --from The height to start at [default: 1] --to The height to end at. Defaults to the latest block --num-tasks Number of tasks to run in parallel. Defaults to the number of available CPUs --blocks-per-chunk Number of blocks each worker processes before grabbing the next chunk [default: 5000] --skip-invalid-blocks Continues with execution when an invalid block is encountered and collects these blocks JIT: --jit Enable JIT compilation of EVM bytecode --jit.hot-threshold Number of observed misses before a bytecode is promoted to JIT compilation [default: 8] --jit.worker-count Number of JIT compilation worker threads --jit.channel-capacity Capacity of the lookup-observed event channel. Events are silently dropped when the channel is full [default: 4096] --jit.max-pending-jobs Maximum number of pending JIT compilation jobs [default: 2048] --jit.max-bytecode-len Maximum bytecode length eligible for JIT compilation. Contracts with bytecode larger than this are never promoted to JIT. 0 means no limit [default: 0] --jit.code-cache-bytes Maximum total resident compiled code size in bytes. When exceeded, the backend evicts least-recently-used entries. 0 means no limit [default: 1073741824] --jit.idle-evict-duration Duration after which a compiled program with no lookup hits is evicted [default: 1h] --jit.debug Enable compiler debug dumps. IR, assembly, and bytecode are written to `/jit///` for each compiled contract. Note that this is not ever cleaned up, and has a non negligible performance overhead. Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage Manipulate individual stages ```bash theme={null} $ op-reth stage --help ``` ```txt theme={null} Usage: op-reth stage [OPTIONS] Commands: run Run a single stage drop Drop a stage's tables from the database dump Dumps a stage from a range into a new database unwind Unwinds a certain block range, deleting it from the database help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage drop Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/drop Drop a stage's tables from the database ```bash theme={null} $ op-reth stage drop --help ``` ```txt theme={null} Usage: op-reth stage drop [OPTIONS] Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] Possible values: - headers: The headers stage within the pipeline - bodies: The bodies stage within the pipeline - senders: The senders stage within the pipeline - execution: The execution stage within the pipeline - account-hashing: The account hashing stage within the pipeline - storage-hashing: The storage hashing stage within the pipeline - hashing: The account and storage hashing stages within the pipeline - merkle: The merkle stage within the pipeline - tx-lookup: The transaction lookup stage within the pipeline - account-history: The account history stage within the pipeline - storage-history: The storage history stage within the pipeline Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage dump Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/dump Dumps a stage from a range into a new database ```bash theme={null} $ op-reth stage dump --help ``` ```txt theme={null} Usage: op-reth stage dump [OPTIONS] Commands: execution Execution stage storage-hashing `StorageHashing` stage account-hashing `AccountHashing` stage merkle Merkle stage help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage dump account-hashing Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/dump/account-hashing `AccountHashing` stage ```bash theme={null} $ op-reth stage dump account-hashing --help ``` ```txt theme={null} Usage: op-reth stage dump account-hashing [OPTIONS] --output-datadir --from --to Options: --output-datadir The path to the new datadir folder. -f, --from From which block -t, --to To which block -d, --dry-run If passed, it will dry-run a stage execution from the newly created database right after dumping -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage dump execution Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/dump/execution Execution stage ```bash theme={null} $ op-reth stage dump execution --help ``` ```txt theme={null} Usage: op-reth stage dump execution [OPTIONS] --output-datadir --from --to Options: --output-datadir The path to the new datadir folder. -f, --from From which block -t, --to To which block -d, --dry-run If passed, it will dry-run a stage execution from the newly created database right after dumping -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage dump merkle Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/dump/merkle Merkle stage ```bash theme={null} $ op-reth stage dump merkle --help ``` ```txt theme={null} Usage: op-reth stage dump merkle [OPTIONS] --output-datadir --from --to Options: --output-datadir The path to the new datadir folder. -f, --from From which block -t, --to To which block -d, --dry-run If passed, it will dry-run a stage execution from the newly created database right after dumping -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage dump storage-hashing Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/dump/storage-hashing `StorageHashing` stage ```bash theme={null} $ op-reth stage dump storage-hashing --help ``` ```txt theme={null} Usage: op-reth stage dump storage-hashing [OPTIONS] --output-datadir --from --to Options: --output-datadir The path to the new datadir folder. -f, --from From which block -t, --to To which block -d, --dry-run If passed, it will dry-run a stage execution from the newly created database right after dumping -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage run Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/run Run a single stage. ```bash theme={null} $ op-reth stage run --help ``` ```txt theme={null} Usage: op-reth stage run [OPTIONS] --from --to Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --metrics Enable Prometheus metrics. The metrics will be served at the given interface and port. --from The height to start at -t, --to The end of the stage --batch-size Batch size for stage execution and unwind -s, --skip-unwind Normally, running the stage requires unwinding for stages that already have been run, in order to not rewrite to the same database slots. You can optionally skip the unwinding phase if you're syncing a block range that has not been synced before. -c, --commit Commits the changes in the database. WARNING: potentially destructive. Useful when you want to run diagnostics on the database. NOTE: This flag is currently required for the headers, bodies, and execution stages because they use static files and must commit to properly unwind and run. --checkpoints Save stage checkpoints The name of the stage to run Possible values: - headers: The headers stage within the pipeline - bodies: The bodies stage within the pipeline - senders: The senders stage within the pipeline - execution: The execution stage within the pipeline - account-hashing: The account hashing stage within the pipeline - storage-hashing: The storage hashing stage within the pipeline - hashing: The account and storage hashing stages within the pipeline - merkle: The merkle stage within the pipeline - tx-lookup: The transaction lookup stage within the pipeline - account-history: The account history stage within the pipeline - storage-history: The storage history stage within the pipeline Networking: -d, --disable-discovery Disable the discovery service --disable-dns-discovery Disable the DNS discovery --disable-discv4-discovery Disable Discv4 discovery --disable-discv5-discovery Disable Discv5 discovery --disable-nat Disable Nat discovery --discovery.addr The UDP address to use for devp2p peer discovery version 4. If unset and `--net-if.experimental` is used, discv4 binds to the resolved interface address. [default: 0.0.0.0] --discovery.port The UDP port to use for devp2p peer discovery version 4 [default: 30303] --discovery.v5.addr The UDP IPv4 address to use for devp2p peer discovery version 5. Overwritten by `RLPx` address, if it's also IPv4 --discovery.v5.addr.ipv6 The UDP IPv6 address to use for devp2p peer discovery version 5. Overwritten by `RLPx` address, if it's also IPv6 --discovery.v5.port The UDP IPv4 port to use for devp2p peer discovery version 5. Not used unless `--addr` is IPv4, or `--discovery.v5.addr` is set [default: 9200] --discovery.v5.port.ipv6 The UDP IPv6 port to use for devp2p peer discovery version 5. Not used unless `--addr` is IPv6, or `--discovery.addr.ipv6` is set. If not provided, discovery V5 defaults to same port as discovery V4 (--discovery.port). [default: 9200] --discovery.v5.lookup-interval The interval in seconds at which to carry out periodic lookup queries, for the whole run of the program [default: 20] --discovery.v5.bootstrap.lookup-interval The interval in seconds at which to carry out boost lookup queries, for a fixed number of times, at bootstrap [default: 5] --discovery.v5.bootstrap.lookup-countdown The number of times to carry out boost lookup queries at bootstrap [default: 200] --trusted-peers Comma separated enode URLs of trusted peers for P2P connections. --trusted-peers enode://abcd@192.168.0.1:30303 --trusted-only Connect to or accept from trusted peers only --bootnodes Comma separated enode URLs for P2P discovery bootstrap. Will fall back to a network-specific default if not specified. --dns-retries Amount of DNS resolution requests retries to perform when peering [default: 0] --peers-file The path to the known peers file. Connected peers are dumped to this file on nodes shutdown, and read on startup. Cannot be used with `--no-persist-peers`. --identity Custom node identity [default: op-reth/-/] --p2p-secret-key Secret key to use for this node. This will also deterministically set the peer ID. If not specified, it will be set in the data dir for the chain being used. --p2p-secret-key-hex Hex encoded secret key to use for this node. This will also deterministically set the peer ID. Cannot be used together with `--p2p-secret-key`. --no-persist-peers Do not persist peers. --nat NAT resolution method (any|none|upnp|publicip|extip:\) [default: any] --addr Network listening address [default: 0.0.0.0] --port Network listening port [default: 30303] --max-outbound-peers Maximum number of outbound peers. default: 100 --max-inbound-peers Maximum number of inbound peers. default: 30 --max-peers Maximum number of total peers (inbound + outbound). Splits peers using approximately 2:1 inbound:outbound ratio. Cannot be used together with `--max-outbound-peers` or `--max-inbound-peers`. --max-tx-reqs Max concurrent `GetPooledTransactions` requests. [default: 130] --max-tx-reqs-peer Max concurrent `GetPooledTransactions` requests per peer. [default: 1] --max-seen-tx-history Max number of seen transactions to remember per peer. Default is 320 transaction hashes. [default: 320] --max-pending-imports Max number of transactions to import concurrently. [default: 4096] --pooled-tx-response-soft-limit Experimental, for usage in research. Sets the max accumulated byte size of transactions to pack in one response. Spec'd at 2MiB. [default: 2097152] --pooled-tx-pack-soft-limit Experimental, for usage in research. Sets the max accumulated byte size of transactions to request in one request. Since `RLPx` protocol version 68, the byte size of a transaction is shared as metadata in a transaction announcement (see `RLPx` specs). This allows a node to request a specific size response. By default, nodes request only 128 KiB worth of transactions, but should a peer request more, up to 2 MiB, a node will answer with more than 128 KiB. Default is 128 KiB. [default: 131072] --max-tx-pending-fetch Max capacity of cache of hashes for transactions pending fetch. [default: 25600] --tx-channel-memory-limit Memory limit (in bytes) for the channel that buffers transaction events flowing from the network manager to the transactions manager. When the budget is exhausted, new events are dropped (see metric `total_dropped_tx_events_at_full_capacity`). Acts as a backstop against unbounded memory growth under sustained P2P transaction flooding. [default: 1073741824] --net-if.experimental Name of network interface used to communicate with peers. If flag is set, but no value is passed, the default interface for docker `eth0` is tried. If `--discovery.addr` is left at its default, discv4 will also bind to the resolved interface address. --tx-propagation-policy Transaction Propagation Policy The policy determines which peers transactions are gossiped to. [default: All] --tx-ingress-policy Transaction ingress policy Determines which peers' transactions are accepted over P2P. [default: All] --disable-tx-gossip Disable transaction pool gossip Disables gossiping of transactions in the mempool to peers. This can be omitted for personal nodes, though providers should always opt to enable this flag. --tx-propagation-mode Sets the transaction propagation mode by determining how new pending transactions are propagated to other peers in full. Examples: sqrt, all, max:10 [default: sqrt] --required-block-hashes Comma separated list of required block hashes or block number=hash pairs. Peers that don't have these blocks will be filtered out. Format: hash or `block_number=hash` (e.g., 23115201=0x1234...) --network-id Optional network ID to override the chain specification's network ID for P2P connections --eth-max-message-size Maximum allowed ETH message size in bytes. Default is 10 MiB --netrestrict Restrict network communication to the given IP networks (CIDR masks). Comma separated list of CIDR network specifications. Only peers with IP addresses within these ranges will be allowed to connect. Example: --netrestrict "192.168.0.0/16,10.0.0.0/8" --enforce-enr-fork-id Enforce EIP-868 ENR fork ID validation for discovered peers. When enabled, peers discovered without a confirmed fork ID are not added to the peer set until their fork ID is verified via EIP-868 ENR request. This filters out peers from other networks that pollute the discovery table. Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage unwind Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/unwind Unwinds a certain block range, deleting it from the database ```bash theme={null} $ op-reth stage unwind --help ``` ```txt theme={null} Usage: op-reth stage unwind [OPTIONS] Commands: to-block Unwinds the database from the latest block, until the given block number or hash has been reached, that block is not included num-blocks Unwinds the database from the latest block, until the given number of blocks have been reached help Print this message or the help of the given subcommand(s) Options: -h, --help Print help (see a summary with '-h') Datadir: --datadir The path to the data dir for all reth files and subdirectories. Defaults to the OS-specific data directory: - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` - Windows: `{FOLDERID_RoamingAppData}/reth/` - macOS: `$HOME/Library/Application Support/reth/` [default: default] --datadir.static-files The absolute path to store static files in. --datadir.rocksdb The absolute path to store `RocksDB` database in. --datadir.pprof-dumps The absolute path to store pprof dumps in. --config The path to the configuration file to use --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Database: --db.log-level Database logging level. Levels higher than "notice" require a debug build Possible values: - fatal: Enables logging for critical conditions, i.e. assertion failures - error: Enables logging for error conditions - warn: Enables logging for warning conditions - notice: Enables logging for normal but significant condition - verbose: Enables logging for verbose informational - debug: Enables logging for debug-level messages - trace: Enables logging for trace debug-level messages - extra: Enables logging for extra debug-level messages --db.exclusive Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume [possible values: true, false] --db.max-size Maximum database size (e.g., 4TB, 8TB). This sets the "map size" of the database. If the database grows beyond this limit, the node will stop with an "environment map size limit reached" error. The default value is 8TB. --db.page-size Database page size (e.g., 4KB, 8KB, 16KB). Specifies the page size used by the MDBX database. The page size determines the maximum database size. MDBX supports up to 2^31 pages, so with the default 4KB page size, the maximum database size is 8TB. To allow larger databases, increase this value to 8KB or higher. WARNING: This setting is only configurable at database creation; changing it later requires re-syncing. --db.growth-step Database growth step (e.g., 4GB, 4KB) --db.read-transaction-timeout Read transaction timeout in seconds, 0 means no timeout --db.max-readers Maximum number of readers allowed to access the database concurrently --db.sync-mode Controls how aggressively the database synchronizes data to disk --db.rocksdb-block-cache-size `RocksDB` block cache size (e.g., 512MB, 4GB). Controls the size of the in-memory LRU cache for decompressed `RocksDB` blocks. A larger cache reduces repeated decompression of hot blocks, improving read performance for history lookups. --db.balstore-cache-size Number of recent blocks to keep in the in-memory BAL store cache --db.disable-metrics Disable built-in database metrics Static Files: --static-files.blocks-per-file.headers Number of blocks per file for the headers segment --static-files.blocks-per-file.transactions Number of blocks per file for the transactions segment --static-files.blocks-per-file.receipts Number of blocks per file for the receipts segment --static-files.blocks-per-file.transaction-senders Number of blocks per file for the transaction senders segment --static-files.blocks-per-file.account-change-sets Number of blocks per file for the account changesets segment --static-files.blocks-per-file.storage-change-sets Number of blocks per file for the storage changesets segment Storage: --storage.v2 [] Enable V2 (hot/cold) storage layout for new databases. When set, new databases will be initialized with the V2 storage layout that separates hot and cold data. Existing databases always use the settings persisted in their metadata regardless of this flag. [default: true] [possible values: true, false] --offline If this is enabled, then all stages except headers, bodies, and sender recovery will be unwound Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage unwind num-blocks Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/unwind/num-blocks Unwinds the database from the latest block, until the given number of blocks have been reached ```bash theme={null} $ op-reth stage unwind num-blocks --help ``` ```txt theme={null} Usage: op-reth stage unwind num-blocks [OPTIONS] Arguments: Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # op-reth stage unwind to-block Source: https://docs.optimism.io/node-operators/op-reth/cli/op-reth/stage/unwind/to-block Unwinds the database from the latest block, until the given block number or hash has been reached, that block is not included ```bash theme={null} $ op-reth stage unwind to-block --help ``` ```txt theme={null} Usage: op-reth stage unwind to-block [OPTIONS] Arguments: Options: -h, --help Print help (see a summary with '-h') Datadir: --chain The chain this node is running. Possible values are either a built-in chain or the path to a chain specification file. Built-in chains: optimism, op-mainnet, optimism_sepolia, optimism-sepolia, automata, bob, boba, celo, cyber, ethernity, fraxtal, funki, hashkeychain, ink, lisk, lyra, metal, mint, mode, op, orderly, polynomial, race, redstone, settlus-mainnet, shape, silent-data-mainnet, soneium, sseed, swan, tbn, unichain, worldchain, xterio-eth, zora, boba-sepolia, camp-sepolia, celo-sep-sepolia, cyber-sepolia, funki-sepolia, ink-sepolia, lisk-sepolia, metal-sepolia, mode-sepolia, op-sepolia, ozean-sepolia, pivotal-sepolia, race-sepolia, radius_testnet-sepolia, settlus-sepolia-sepolia, shape-sepolia, soneium-minato-sepolia, tbn-sepolia, unichain-sepolia, worldchain-sepolia, zora-sepolia, oplabs-devnet-0-sepolia-dev-0, sepolia-devnet-2-sepolia-devnet-2, dev [default: optimism] Logging: --log.stdout.format The format to use for logs written to stdout Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.stdout.filter The filter to use for logs written to stdout [default: ""] --log.file.format The format to use for logs written to the log file Possible values: - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications - terminal: Represents terminal-friendly formatting for logs [default: terminal] --log.file.filter The filter to use for logs written to the log file [default: debug] --log.file.directory The path to put log files in [default: /logs] --log.file.name The prefix name of the log files [default: reth.log] --log.file.max-size The maximum size (in MB) of one log file [default: 200] --log.file.max-files The maximum amount of log files that will be stored. If set to 0, background file logging is disabled. Default: 5 for `node` command, 0 for non-node utility subcommands. --log.journald Write logs to journald --log.journald.filter The filter to use for logs written to journald [default: error] --color Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting Possible values: - always: Colors on - auto: Auto-detect - never: Colors off [default: always] --logs-otlp[=] Enable `Opentelemetry` logs export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317` Example: --logs-otlp=http://collector:4318/v1/logs [env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=] --logs-otlp.filter Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --logs-otlp.filter=info,reth=debug Defaults to INFO if not specified. [default: info] Display: -v, --verbosity... Set the minimum log level. -v Errors -vv Warnings -vvv Info -vvvv Debug -vvvvv Traces (warning: very verbose!) -q, --quiet Silence all log output Tracing: --tracing-otlp[=] Enable `Opentelemetry` tracing export to an OTLP endpoint. If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` Example: --tracing-otlp=http://collector:4318/v1/traces [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] --tracing-otlp-protocol OTLP transport protocol to use for exporting traces and logs. - `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path Defaults to HTTP if not specified. Possible values: - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path - grpc: gRPC transport, port 4317 [env: OTEL_EXPORTER_OTLP_PROTOCOL=] [default: http] --tracing-otlp.filter Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off Defaults to TRACE if not specified. [default: debug] --tracing-otlp.sample-ratio Trace sampling ratio to control the percentage of traces to export. Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling Example: --tracing-otlp.sample-ratio=0.0. [env: OTEL_TRACES_SAMPLER_ARG=] ``` # Understanding the op-reth CLI Source: https://docs.optimism.io/node-operators/op-reth/cli/overview Understand how the op-reth command-line interface is organized, how chain selection works through the Superchain Registry, and where configuration values come from. This page explains how the `op-reth` command-line interface is organized, so you can find the right command and understand where its configuration comes from. To install and start a node, follow [Execution client configuration](/node-operators/guides/configuration/execution-clients). For the full flag catalogue of every command, see the [generated CLI reference](/node-operators/op-reth/cli/op-reth). ## One binary, many commands `op-reth` ships as a single binary. The command you run day to day is `op-reth node`, which starts the execution client itself. The other subcommands are operational tools: most work against the same data directory — initializing it, importing history into it, inspecting it, or repairing it — so you rarely run them while the node is running. A couple (`config` and `dump-genesis`) simply print information to stdout. | Command | What it does | | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------- | | [`node`](/node-operators/op-reth/cli/op-reth/node) | Start the node | | [`init`](/node-operators/op-reth/cli/op-reth/init) | Initialize the database from a genesis file | | [`init-state`](/node-operators/op-reth/cli/op-reth/init-state) | Initialize the database from a state dump file | | [`import-op`](/node-operators/op-reth/cli/op-reth/import-op) | Sync RLP-encoded OP blocks below Bedrock from a file, without executing | | [`import-receipts-op`](/node-operators/op-reth/cli/op-reth/import-receipts-op) | Import RLP-encoded receipts from a file | | [`dump-genesis`](/node-operators/op-reth/cli/op-reth/dump-genesis) | Dump the genesis block JSON configuration to stdout | | [`db`](/node-operators/op-reth/cli/op-reth/db) | Database debugging utilities | | [`stage`](/node-operators/op-reth/cli/op-reth/stage) | Manipulate individual sync stages | | [`p2p`](/node-operators/op-reth/cli/op-reth/p2p) | P2P debugging utilities | | [`config`](/node-operators/op-reth/cli/op-reth/config) | Write the configuration to stdout | | [`prune`](/node-operators/op-reth/cli/op-reth/prune) | Prune according to the configuration without any limits | | [`re-execute`](/node-operators/op-reth/cli/op-reth/re-execute) | Re-execute blocks in parallel to verify historical sync correctness | | [`proofs`](/node-operators/op-reth/cli/op-reth/proofs) | Manage storage of historical proofs within the fault proof window | The [CLI reference](/node-operators/op-reth/cli/op-reth) mirrors this structure: each page reproduces the output of `op-reth --help`, and nested subcommands (such as `op-reth db stats`) get their own nested pages. ### Running the node [`node`](/node-operators/op-reth/cli/op-reth/node) is the long-running command that syncs and serves the chain. It carries by far the largest flag surface, organized into functional groups — Metrics, Datadir, Networking, RPC, TxPool, Builder, Debug, Dev testnet, Pruning, Engine, and Rollup, among others — with related flags sharing a dotted prefix (for example `--txpool.*`, `--prune.*`, `--rollup.*`, or `--http.*` in the RPC group). The `Rollup` group is OP Stack-specific: flags such as `--rollup.sequencer` (the sequencer endpoint that transactions are forwarded to) and `--rollup.disable-tx-pool-gossip` configure behavior that only exists on OP Stack chains. These are covered with examples in [Execution client configuration](/node-operators/guides/configuration/execution-clients). ### Initializing and importing [`init`](/node-operators/op-reth/cli/op-reth/init) and [`init-state`](/node-operators/op-reth/cli/op-reth/init-state) create a fresh database from a genesis file or a state dump file respectively, instead of syncing from the network. [`import-op`](/node-operators/op-reth/cli/op-reth/import-op) and [`import-receipts-op`](/node-operators/op-reth/cli/op-reth/import-receipts-op) exist for one OP Stack-specific job: loading OP Mainnet history from before the Bedrock migration, which cannot be re-executed and is instead imported from files. [Sync OP Mainnet](/node-operators/op-reth/run/faq/sync-op-mainnet) explains when you need them — most operators use the minimal bootstrap path with `init-state` and skip the pre-Bedrock import entirely. ### Inspecting and maintaining The remaining commands are diagnostic and maintenance tools: * [`db`](/node-operators/op-reth/cli/op-reth/db) inspects and repairs the database: table statistics, checksums, diffs between databases, and storage settings. * [`stage`](/node-operators/op-reth/cli/op-reth/stage) runs, drops, dumps, or unwinds individual stages of reth's staged-sync pipeline (such as execution, account hashing, and merkle) — useful for debugging or re-running one part of sync without starting over. * [`p2p`](/node-operators/op-reth/cli/op-reth/p2p) debugs the networking layer: downloading a single header or body from peers, RLPx utilities, and running a bootnode. * [`config`](/node-operators/op-reth/cli/op-reth/config) and [`dump-genesis`](/node-operators/op-reth/cli/op-reth/dump-genesis) print the effective configuration and the chain's genesis JSON to stdout. * [`prune`](/node-operators/op-reth/cli/op-reth/prune) and [`re-execute`](/node-operators/op-reth/cli/op-reth/re-execute) are heavyweight maintenance passes: pruning historical data according to your configuration, and re-executing blocks in parallel to verify that historical sync produced correct results. ## Chain selection and the Superchain Registry Every command that touches chain data accepts `--chain `, which takes either a built-in chain name or the path to a chain specification file. The default is `optimism` (OP Mainnet). The built-in names come from the [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry): op-reth bakes the registry's chain configurations into the binary at build time, so chains like `base`, `unichain`, `ink`, `mode`, `zora`, and their Sepolia counterparts (for example `unichain-sepolia`) work by name with no extra configuration files. The full list of built-in chains is in the [`node` reference](/node-operators/op-reth/cli/op-reth/node) under `--chain`. For a chain that is not in the registry, pass the path to its chain specification file instead. ## Where configuration comes from op-reth is configured primarily through CLI flags. Three conventions in the help text (and the [generated reference](/node-operators/op-reth/cli/op-reth)) tell you how a flag behaves: * **Defaults** — every flag with a default value lists it as `[default: ...]`. For example, `--datadir` defaults to an OS-specific data directory (`$HOME/.local/share/reth/` or `$XDG_DATA_HOME/reth/` on Linux). * **Environment variables** — flags that can also be set through an environment variable list it as `[env: ...]`; the OpenTelemetry export flags (`--logs-otlp`, `--tracing-otlp`) are examples. * **Shared groups** — every subcommand accepts the same Logging, Display, and Tracing options, so `-vvv` or `--log.file.directory` work the same on `op-reth db stats` as on `op-reth node`. A configuration file supplements the flags: `op-reth node --config ` points the node at one, and `op-reth config` writes the resulting configuration to stdout (`op-reth config --default` shows the defaults), which is the quickest way to see what is configurable through the file. ## Next steps * Follow [Execution client configuration](/node-operators/guides/configuration/execution-clients) to install op-reth and pair it with a consensus client. * Browse the [CLI reference](/node-operators/op-reth/cli/op-reth) for the complete flag catalogue of every command. * See [Sync OP Mainnet](/node-operators/op-reth/run/faq/sync-op-mainnet) if you are bootstrapping an OP Mainnet archive node. # op-reth for node operators Source: https://docs.optimism.io/node-operators/op-reth/index op-reth is the OP Stack execution client built on reth. Start here to run it alongside a rollup node and to find its CLI reference. `op-reth` is the [OP Stack](https://docs.optimism.io/) execution client built on [reth](https://github.com/paradigmxyz/reth). It provides a high-performance execution layer for Optimism and all OP Stack chains. ## Features * **Full OP Stack support** — Deposit transactions, L2-specific fee handling, and all OP Stack protocol changes. * **Superchain Registry** — Built-in support for all chains in the [superchain registry](https://github.com/ethereum-optimism/superchain-registry). Use `--chain unichain`, `--chain base`, etc. * **High performance** — Built on reth's modular architecture with parallelized execution and efficient storage. ## Getting started * [Execution client configuration](/node-operators/guides/configuration/execution-clients): install op-reth, pair it with a consensus client, and set the OP Stack specific flags. * [Running a Node With Docker](/node-operators/tutorials/node-from-docker): bring up op-reth and op-node from the official images. * [Sync OP Mainnet](/node-operators/op-reth/run/faq/sync-op-mainnet) — Import Bedrock state and sync OP Mainnet from scratch. * [Understanding the op-reth CLI](/node-operators/op-reth/cli/overview) — How the commands, chain selection, and configuration fit together. * [CLI Reference](/node-operators/op-reth/cli/op-reth) — Full command-line reference for op-reth. # Sync OP Mainnet Source: https://docs.optimism.io/node-operators/op-reth/run/faq/sync-op-mainnet Syncing op-reth with OP Mainnet and Bedrock state. To sync OP mainnet, Bedrock state needs to be imported as a starting point. There are currently two ways: * Minimal bootstrap **(recommended)**: only state snapshot at Bedrock block is imported without any OVM historical data. * Full bootstrap **(not recommended)**: state, blocks and receipts are imported. ## Minimal bootstrap (recommended) **The state snapshot at Bedrock block is required.** It can be exported from [op-geth](https://github.com/testinprod-io/op-erigon/blob/pcw109550/bedrock-db-migration/bedrock-migration.md#export-state) (**.jsonl**) or downloaded directly from [here](https://mega.nz/file/GdZ1xbAT#a9cBv3AqzsTGXYgX7nZc_3fl--tcBmOAIwIA5ND6kwc). ### 1. Download and decompress After you downloaded the state file, ensure the state file is decompressed into **.jsonl** format: ```sh theme={null} $ unzstd /path/to/world_trie_state.jsonl.zstd ``` ### 2. Import the state Import the state snapshot: ```sh theme={null} $ op-reth init-state --without-ovm --chain optimism --datadir op-mainnet world_trie_state.jsonl ``` ### 3. Sync from Bedrock to tip Running the node with `--debug.tip ` syncs the node without help from CL until a fixed tip. The block hash can be taken from the latest block on [https://optimistic.etherscan.io](https://optimistic.etherscan.io). Eg, sync the node to a recent finalized block (e.g. 125200000) to catch up close to the tip, before pairing with op-node. ```sh theme={null} $ op-reth node --chain optimism --datadir op-mainnet --debug.tip 0x098f87b75c8b861c775984f9d5dbe7b70cbbbc30fc15adb03a5044de0144f2d0 # block #125200000 ``` ## Full bootstrap (not recommended) **Not recommended for now**: [storage consistency issue](https://github.com/paradigmxyz/reth/pull/11099) tldr: sudden crash may break the node. ### Import state To sync OP mainnet, the Bedrock datadir needs to be imported to use as starting point. Blocks lower than the OP mainnet Bedrock fork, are built on the OVM and cannot be executed on the EVM. For this reason, the chain segment from genesis until Bedrock, must be manually imported to circumvent execution in reth's sync pipeline. Importing OP mainnet Bedrock datadir requires exported data: * Blocks \[and receipts] below Bedrock * State snapshot at first Bedrock block ### Manual Export Steps The `op-geth` Bedrock datadir can be downloaded from [https://datadirs.optimism.io](https://datadirs.optimism.io). To export the OVM chain from `op-geth`, clone the `testinprod-io/op-geth` repo and checkout [testinprod-io/op-geth#1](https://github.com/testinprod-io/op-geth/pull/1). Commands to export blocks, receipts and state dump can be found in `op-geth/migrate.sh`. ### Manual Import Steps #### 1. Import Blocks Imports a `.rlp` file of blocks. Import of >100 million OVM blocks, from genesis to Bedrock, completes in 45 minutes. ```bash theme={null} $ op-reth import-op --chain optimism ``` #### 2. Import Receipts This step is optional. To run a full node, skip this step. If however receipts are to be imported, the corresponding transactions must already be imported (see [step 1](#1-import-blocks)). Imports a `.rlp` file of receipts, that has been exported with command specified in [testinprod-io/op-geth#1](https://github.com/testinprod-io/op-geth/pull/1) (command for exporting receipts uses custom RLP-encoding). Import of >100 million OVM receipts, from genesis to Bedrock, completes in 30 minutes. ```bash theme={null} $ op-reth import-receipts-op --chain optimism ``` #### 3. Import State Imports a `.jsonl` state dump. The block at which the state dump is made, must be the latest block in reth's database. This should be block 105 235 063, the first Bedrock block (see [step 1](#1-import-blocks)). Import of >4 million OP mainnet accounts at Bedrock, completes in 10 minutes. ```bash theme={null} $ op-reth init-state --chain optimism ``` ### Start with op-node Use `op-node` to track the tip. Start `op-node` with `--syncmode=execution-layer` and `--l2.enginekind=reth`. If `op-node`'s RPC connection to L1 is over localhost, `--l1.trustrpc` can be set to improve performance. # Node Operator Overview Source: https://docs.optimism.io/node-operators/overview Learn about running nodes on OP Stack networks. ## Overview This section of the documentation is dedicated to node operators who want to learn about configuring and running nodes on OP Stack networks. Because the OP Stack is an open-source, modular, and extensible stack, there are many different clients, configurations, and requirements depending on your goals and the specific network you're targeting. The information provided in this section covers standard configurations and features on the OP Stack. ## Why Run a Node? Running your own node gives you the benefit of trustless verification, enhanced privacy, and gives you local access to the blockchain. However, it also requires time and resources to set up and maintain. So you should consider your goals and use cases before deciding to run a node because there are many third-party RPC providers available. ## System requirements Before you start, check that your machine can handle the network and node type you're targeting. Requirements scale with both: * **RAM:** 16GB is the suggested minimum for an OP Mainnet node. * **CPU:** A reasonably modern CPU. * **Disk:** An SSD, sized to the network and node type. A full OP Mainnet node needs hundreds of gigabytes and grows steadily; an archive node needs multiple terabytes and grows much faster, so use an NVMe SSD for archive nodes. Test networks are far lighter than OP Mainnet: an OP Sepolia full node syncs into tens of gigabytes rather than hundreds. If you're setting up for the first time, start on OP Sepolia to validate your setup before committing OP Mainnet-scale disk. For the current OP Mainnet storage figures and their growth rates, see the [hardware requirements](/node-operators/tutorials/run-node-from-source#hardware-requirements) in the from-source tutorial. ## Node Architecture Regardless of which OP Stack network you're running a node for, all nodes share the same fundamental two-client architecture: a consensus client (rollup node, either [op-node](/op-stack/components/op-node) or [kona-node](/op-stack/components/kona-node)) paired with an execution client ([op-reth](/op-stack/components/op-reth)), communicating via the Engine API with JWT authentication. Nodes that follow every chain in an [interop](/op-stack/interop/explainer) dependency set run [op-supernode](/op-stack/interop/supernode) as the consensus layer instead. See the [architecture reference](/node-operators/reference/architecture) for how the components fit together and the current client support matrix. ## Node Types Different node types serve different purposes: * **Full node**: keeps a complete copy of the blockchain, validates all transactions and blocks, and participates on the P2P network. * **Archive node**: additionally retains all historical state for every block. On OP Mainnet, archive nodes need to restore from a [database snapshot](/op-mainnet/network-information/snapshots) before syncing. * **Sequencer node**: can be a full or archive node, but it can create new L2 blocks. ## Network upgrades Network upgrades on OP Stack networks are generally [activated by timestamps](/op-stack/protocol/network-upgrades#activations). Failing to upgrade your node before the activation timestamp causes a chain divergence that requires a resync, so follow the [node upgrade process](/op-stack/protocol/network-upgrades#upgrade-process) to stay on the canonical chain. ## Stay up to date Upgrade announcements, deprecations, and other changes that affect node operators are published on the [Network Notices](/notices) page. ## Next steps * [**Run a node with Docker**](/node-operators/tutorials/node-from-docker): recommended path; uses the official op-reth + op-node images. * [**Build and run a node from source**](/node-operators/tutorials/run-node-from-source): covers op-reth and Nethermind. * [**Run op-reth with historical proofs**](/node-operators/tutorials/reth-historical-proofs): configure op-reth's proofs-history store for permissionless withdrawal proving. * [**Consensus client configuration**](/node-operators/guides/configuration/consensus-clients): working base configuration and recommended flags for the rollup node. * [**Execution client configuration**](/node-operators/guides/configuration/execution-clients): working base configuration and recommended flags for the execution client. * [**Supernode configuration**](/node-operators/guides/configuration/supernode): recommended settings and a starter configuration for running op-supernode in an interop dependency set. * [**Node metrics and monitoring**](/node-operators/guides/monitoring/metrics): keep tabs on your node once it's running. * [**Node troubleshooting**](/node-operators/guides/troubleshooting): help with common problems. * [**Architecture reference**](/node-operators/reference/architecture): deeper detail on the two-client architecture. # Node architecture Source: https://docs.optimism.io/node-operators/reference/architecture/index Understand how the components of an OP Stack node fit together. This page explains how an OP Stack node is put together: what its components are, what each one is responsible for, and how they relate to the equivalent parts of an Ethereum node. It is background reading to build a mental model before you run a node; for the steps to actually stand one up, see the [Next steps](#next-steps) below. Every node on an OP Stack network is composed of two core software services, the Rollup Node and the Execution Client. OP Mainnet also optionally supports a third component, Legacy Geth, that can serve stateful queries for blocks and transactions created before the [Bedrock Upgrade](https://web.archive.org/web/20230608050602/https://blog.oplabs.co/introducing-optimism-bedrock/). ## Node flow diagram The following diagram shows how the Rollup Node, Execution Client, and Legacy Geth components work together to form a complete node running on OP Stack networks. This diagram uses the `op-node` implementation of the Rollup Node and shows the general architecture that applies to all execution client implementations. OP Mainnet node architecture diagram. ## Rollup node The Rollup Node is responsible for deriving L2 block payloads from L1 data and passing those payloads to the Execution Client. The Rollup Node can also optionally participate in a peer-to-peer network to receive blocks directly from the Sequencer before those blocks are submitted to L1. The Rollup Node is largely analogous to a [consensus client](https://ethereum.org/en/developers/docs/nodes-and-clients/#what-are-nodes-and-clients) in Ethereum. ### Rollup node implementations * **[op-node](/op-stack/components/op-node)** is the reference implementation of the Rollup Node, written in Go and maintained by Optimism. It is the default choice for any node role and is not deprecated. * **[kona-node](/op-stack/components/kona-node)** is the Rust implementation of the Rollup Node, built as part of the Kona project. It is in active development and should be considered experimental, so give it a role where that is acceptable. For nodes that follow every chain in an [interop](/op-stack/interop/explainer) dependency set, deploy the consensus layer as [op-supernode](/op-stack/interop/supernode), which hosts an op-node instance for each chain in one process and adds cross-chain message verification. See the [supernode configuration guide](/node-operators/guides/configuration/supernode) for recommended settings and the [op-supernode configuration reference](/node-operators/reference/op-supernode-config) for the flag catalogue. ## Execution client The Execution Client is responsible for executing the block payloads it receives from the Rollup Node over JSON-RPC via the standard [Ethereum Engine API](https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#engine-api----common-definitions). The Execution Client exposes the standard JSON-RPC API that Ethereum developers are familiar with, and can be used to query blockchain data and submit transactions to the network. The Execution Client is largely analogous to an [execution client](https://ethereum.org/en/developers/docs/nodes-and-clients/#what-are-nodes-and-clients) in Ethereum. ### Execution client implementations * **[op-reth](/op-stack/components/op-reth)** is the Optimism-maintained execution client, written in Rust and built on reth. It is the primary supported execution client for OP Stack nodes. See the [execution client configuration guide](/node-operators/guides/configuration/execution-clients) for a working configuration. * **[Nethermind](https://github.com/NethermindEth/nethermind)** is a third-party execution client written in C# that also supports OP Stack chains. The docs focus on Optimism-maintained software; for Nethermind specifics, see the [Nethermind documentation](https://docs.nethermind.io/get-started/running-node/l2-networks). **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. op-program has also reached end of support, replaced by kona-client for fault proofs; the same [notice](/notices/archive/op-geth-deprecation) covers both migrations. ## Legacy Geth OP Mainnet blocks and transactions from before the 2023 [Bedrock Upgrade](https://web.archive.org/web/20230608050602/https://blog.oplabs.co/introducing-optimism-bedrock/) can be read from any current execution client, but re-executing them (RPC calls such as `eth_call` against pre-Bedrock blocks) requires an optional third component, Legacy Geth (`l2geth`), the client that ran OP Mainnet before the upgrade. It is typically only needed for complete OP Mainnet archive nodes; see the [Legacy Geth configuration guide](/node-operators/guides/configuration/legacy-geth) for setup and request routing, and [accessing pre-regenesis history](/op-mainnet/pre-bedrock-history/regenesis-history) for the even older history that predates the current chain data entirely. ## Next steps * To get your node up and running, start with the [run a node from docker](/node-operators/tutorials/node-from-docker) or [build and run a node from source](/node-operators/tutorials/run-node-from-source) tutorial. The source tutorial covers `op-reth` (primary) and `Nethermind` execution clients. * If you've already got your node up and running, check out the [Node Metrics and Monitoring Guide](/node-operators/guides/monitoring/metrics) to learn how to keep tabs on your node and make sure it keeps running smoothly. * If you run into any problems, please visit the [Node Troubleshooting Guide](/node-operators/guides/troubleshooting) for help. # Consensus-layer sync Source: https://docs.optimism.io/node-operators/reference/consensus-layer-sync Learn about the consensus-layer sync mode. This page documents the consensus-layer sync mode, which is the default sync method for op-node but not the recommended approach for most node operators. ## Overview Consensus-layer sync is a sync approach where `op-node` reads transaction data from L1 and derives blocks, then inserts them into the execution client. Unlike execution-layer sync (snap sync), this method does not rely on P2P networking to download state or block data from other L2 nodes. While consensus-layer sync is still the default mode, **execution-layer sync (snap sync) is recommended** for faster synchronization and better performance. ## When to use consensus-layer sync This sync mode might be preferred in the following scenarios: * **Independent verification**: Decentralized developer groups who need to independently verify the entire chain by deriving all data from L1 * **No P2P connectivity**: Environments where P2P networking is restricted or unavailable * **L1-only trust model**: Applications that prefer to trust only L1 data without relying on L2 peer nodes * **Debugging and research**: Analyzing how blocks are derived from L1 data Consensus-layer sync is significantly slower than execution-layer sync (snap sync). For most node operators, snap sync is the recommended approach for faster synchronization. ## Configuration ### Configuration for op-node Set the following flag on `op-node`: ```shell theme={null} --syncmode=consensus-layer ``` The `--syncmode=consensus-layer` is the default setting for `op-node`. You don't need to specify it explicitly unless you want to be explicit about the sync mode or are overriding a different configuration. ### Configuration for op-geth Set the following flag on `op-geth`: ```shell theme={null} --syncmode=full ``` The `--syncmode=full` flag is not the default setting and must be explicitly configured. This ensures blocks are inserted by `op-node` rather than synced via P2P. ### Configuration for Nethermind Set the following flags on `Nethermind`: ```shell theme={null} --config op-mainnet --Sync.SnapSync=false --Sync.FastSync=false ``` Replace `op-mainnet` with the appropriate configuration for your network (e.g., `op-sepolia` for OP Sepolia). ## How consensus-layer sync works The consensus-layer sync process: 1. **L1 monitoring**: `op-node` continuously monitors the L1 chain for transaction batches 2. **Block derivation**: `op-node` derives L2 blocks from the L1 transaction data 3. **Block insertion**: Derived blocks are inserted into the execution client one by one 4. **State building**: The execution client builds state by executing each block sequentially This approach ensures that every block is derived from L1 and independently verified, but it's much slower than downloading state snapshots from peers. ## Performance considerations * **Sync time**: Significantly slower than snap sync or archive sync with execution-layer mode * **Network requirements**: Requires reliable L1 RPC access but minimal L2 P2P connectivity * **Resource usage**: Lower P2P bandwidth usage but more L1 RPC calls * **OP Mainnet**: For OP Mainnet, you'll still need the [bedrock datadir](/node-operators/guides/management/snapshots) for state before the Bedrock upgrade ## Comparison with other sync modes | Feature | Consensus-Layer (Legacy) | Execution-Layer (Snap Sync) | Archive with Execution-Layer | | ---------------- | ------------------------ | --------------------------- | ---------------------------- | | Data source | L1 only | L2 P2P + L1 | L2 P2P + L1 | | Sync speed | Slowest | Fastest | Medium | | State pruning | Yes (by default) | Yes | No | | Historical state | Not available | Not available | Full history | | P2P required | No | Yes | Yes | | Verification | Full L1 derivation | Cryptographic verification | Full execution | ## Next steps * See the [Archive Node guide](/node-operators/guides/management/archive-node) for running an archive node * See the [Consensus Client Configuration](/node-operators/guides/configuration/consensus-clients) and [Execution Client Configuration](/node-operators/guides/configuration/execution-clients) guides for additional explanation or customization * If you experience difficulty at any stage of this process, please reach out to [developer support](https://github.com/ethereum-optimism/developers/discussions) # Legacy Geth configuration options Source: https://docs.optimism.io/node-operators/reference/legacy-geth-config Reference for Legacy Geth (l2geth) environment variables and the RPC methods routed to it. This page catalogues the environment variables Legacy Geth (`l2geth`) accepts and the RPC methods your execution client routes to it. For what Legacy Geth is and how to set it up, see the [Legacy Geth guide](/node-operators/guides/configuration/legacy-geth). Legacy Geth applies only to networks that upgraded through Bedrock, such as OP Mainnet, where it serves execution requests and chain data for pre-Bedrock blocks. ## Environment variables Legacy Geth accepts the following environment variables: | Variable | Description | Default | | -------------------------- | ------------------------------ | ------------------------------------- | | `USING_OVM` | **Required**. Enables OVM mode | N/A (must be set to `true`) | | `ETH1_SYNC_SERVICE_ENABLE` | Enables L1 sync service | `true` (set to `false` for read-only) | | `RPC_API` | Enabled RPC APIs | `eth,net,web3` | | `RPC_ADDR` | RPC listening address | `localhost` | | `RPC_CORS_DOMAIN` | CORS domains | `localhost` | | `RPC_ENABLE` | Enable RPC server | `false` | | `RPC_PORT` | RPC port | `8545` | | `RPC_VHOSTS` | Virtual hosts | `localhost` | `USING_OVM=true` must always be set. Without it, `l2geth` panics at startup or returns invalid execution traces. ## Execution-client routing flag Both op-reth and op-geth use the same `--rollup.historicalrpc` flag to route pre-Bedrock requests to Legacy Geth. The flag takes the URL of the Legacy Geth RPC endpoint, for example `--rollup.historicalrpc=http://localhost:8545`. ## RPC methods routed to Legacy Geth This section describes op-reth. When `--rollup.historicalrpc` is set, op-reth forwards requests that target pre-Bedrock blocks to Legacy Geth and serves everything else directly. This covers both methods that require transaction execution (which op-reth cannot perform for pre-Bedrock blocks) and methods that read pre-Bedrock block or transaction data. Methods not listed below (for example `eth_getLogs`) are never routed to Legacy Geth. op-geth behaved differently: it served pre-Bedrock block and transaction data locally from its migrated database and routed only execution methods to Legacy Geth. op-geth has reached end-of-support and this behavior is no longer documented here; see the [op-geth deprecation notice](/notices/archive/op-geth-deprecation). ### State and execution methods Routed to Legacy Geth when the method's block parameter refers to a pre-Bedrock block: * `eth_call` * `eth_estimateGas` * `eth_createAccessList` * `eth_getBalance` * `eth_getCode` * `eth_getStorageAt` * `eth_getTransactionCount` * `eth_getProof` * `debug_traceCall` ### Block data methods Routed to Legacy Geth when the requested block is pre-Bedrock, or when the requested block hash is unknown to op-reth: * `eth_getBlockByNumber` / `eth_getBlockByHash` * `eth_getBlockReceipts` * `eth_getHeaderByNumber` / `eth_getHeaderByHash` * `eth_getBlockTransactionCountByNumber` / `eth_getBlockTransactionCountByHash` * `eth_getUncleCountByBlockNumber` / `eth_getUncleCountByBlockHash` * `eth_getUncleByBlockNumberAndIndex` / `eth_getUncleByBlockHashAndIndex` * `eth_getTransactionByBlockNumberAndIndex` / `eth_getTransactionByBlockHashAndIndex` * `eth_getRawTransactionByBlockNumberAndIndex` / `eth_getRawTransactionByBlockHashAndIndex` * `debug_traceBlockByNumber` / `debug_traceBlockByHash` ### Transaction data methods Routed to Legacy Geth when the transaction belongs to a pre-Bedrock block, or when the transaction is unknown to op-reth: * `eth_getTransactionByHash` * `eth_getTransactionReceipt` * `eth_getRawTransactionByHash` * `debug_traceTransaction` ### `eth_getBlockReceipts` emulation Legacy Geth (`l2geth`) predates `eth_getBlockReceipts` and does not implement it. op-reth forwards the request first; if Legacy Geth responds that the method does not exist, op-reth fetches the block's transaction hashes from Legacy Geth and assembles the response from one `eth_getTransactionReceipt` call per transaction. Receipts are returned in transaction order and passed through verbatim, with their legacy fields intact — exactly what a forwarded `eth_getTransactionReceipt` returns for the same transactions. A block unknown to Legacy Geth returns `null`, and a block without transactions returns `[]`. # op-node configuration options Source: https://docs.optimism.io/node-operators/reference/op-node-config Complete reference for all op-node command-line flags and environment variables. This page catalogues every configuration option for the op-node, the consensus-layer (rollup node) client of an OP Stack chain. For guidance on running a node — hardware, sync strategies, and monitoring — see the [node operator guides](/node-operators/tutorials/run-node-from-source). ## Flags Generated from [`op-node/v1.19.3`](https://github.com/ethereum-optimism/optimism/releases/tag/op-node%2Fv1.19.3) flag definitions. 109 flags: 3 required, 106 optional. ### Required flags | Flag | Description | Environment variable | | ----------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------ | | `--l1` | Address of L1 User JSON-RPC endpoint to use (eth namespace required) | `OP_NODE_L1_ETH_RPC` | | `--l2` | Address of L2 Engine JSON-RPC endpoints to use (engine and eth namespace required) | `OP_NODE_L2_ENGINE_RPC` | | `--l2.jwt-secret` | Path to JWT secret key. Keys are 32 bytes, hex encoded in a file. A new key will be generated if the file is empty. | `OP_NODE_L2_ENGINE_AUTH` | ### Optional flags | Flag | Description | Default | Environment variable | | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | ------------------------------------------- | | `--altda.da-server` | HTTP address of a DA Server | — | `OP_NODE_ALTDA_DA_SERVER` | | `--altda.da-service` | Use DA service type where commitments are generated by Alt-DA server | `false` | `OP_NODE_ALTDA_DA_SERVICE` | | `--altda.enabled` | Enable Alt-DA mode Alt-DA Mode is a Beta feature of the MIT licensed OP Stack. While it has received initial review from core contributors, it is still undergoing testing, and may have bugs or other issues. | `false` | `OP_NODE_ALTDA_ENABLED` | | `--altda.get-timeout` | Timeout for get requests. 0 means no timeout. | `0s` | `OP_NODE_ALTDA_GET_TIMEOUT` | | `--altda.max-concurrent-da-requests` | Maximum number of concurrent requests to the DA server | `1` | `OP_NODE_ALTDA_MAX_CONCURRENT_DA_REQUESTS` | | `--altda.put-timeout` | Timeout for put requests. 0 means no timeout. | `0s` | `OP_NODE_ALTDA_PUT_TIMEOUT` | | `--altda.verify-on-read` | Verify input data matches the commitments from the DA storage service | `true` | `OP_NODE_ALTDA_VERIFY_ON_READ` | | `--conductor.enabled` | Enable the conductor service | `false` | `OP_NODE_CONDUCTOR_ENABLED` | | `--conductor.rpc` | Conductor service rpc endpoint | `"http://127.0.0.1:8547"` | `OP_NODE_CONDUCTOR_RPC` | | `--conductor.rpc-timeout` | Conductor service rpc timeout | `1s` | `OP_NODE_CONDUCTOR_RPC_TIMEOUT` | | `--experimental.sequencer-api` | Enables experimental test sequencer RPC functionality | `false` | `OP_NODE_EXPERIMENTAL_SEQUENCER_API` | | `--fetch-withdrawal-root-from-state` | Read withdrawal\_storage\_root (aka message passer storage root) from state trie (via execution layer) instead of the block header. Restores pre-Isthmus behavior, requires an archive EL client. | `false` | `OP_NODE_FETCH_WITHDRAWAL_ROOT_FROM_STATE` | | `--finality.delay` | Number of L1 blocks to traverse before trying to finalize L2 blocks again. Uses default (64) if 0. | `0` | `OP_NODE_FINALITY_DELAY` | | `--finality.lookback` | Number of L1 blocks to look back for finality verification. Uses default calculation if 0 (considers alt-DA challenge/resolve windows if applicable). | `0` | `OP_NODE_FINALITY_LOOKBACK` | | `--interop.dependency-set` | Dependency-set configuration, point at JSON file. | — | `OP_NODE_INTEROP_DEPENDENCY_SET` | | `--l1.beacon` | Address of L1 Beacon-node HTTP endpoint to use. | — | `OP_NODE_L1_BEACON` | | `--l1.beacon-fallbacks` | Addresses of L1 Beacon-API compatible HTTP fallback endpoints. Used to fetch blob sidecars not available at the l1.beacon (e.g. expired blobs). | — | `OP_NODE_L1_BEACON_FALLBACKS` | | `--l1.beacon-header` | Optional HTTP header to add to all requests to the L1 Beacon endpoint. Format: 'X-Key: Value' | — | `OP_NODE_L1_BEACON_HEADER` | | `--l1.beacon.fetch-all-sidecars` | If true, all sidecars are fetched and filtered locally. Workaround for buggy Beacon nodes. | `false` | `OP_NODE_L1_BEACON_FETCH_ALL_SIDECARS` | | `--l1.beacon.ignore` | When false, halts op-node startup if the healthcheck to the Beacon-node endpoint fails. | `false` | `OP_NODE_L1_BEACON_IGNORE` | | `--l1.beacon.slot-duration-override` | Duration in seconds of an L1 slot. When set (non-zero), bypasses the beacon /eth/v1/config/spec fetch and uses this value as SECONDS\_PER\_SLOT. Useful for devnets where the beacon spec endpoint is unavailable (e.g. anvil). | `0` | `OP_NODE_L1_BEACON_SLOT_DURATION_OVERRIDE` | | `--l1.cache-size` | Cache size for blocks, receipts and transactions. If this flag is set to 0, 3/2 of the sequencing window size is used (usually 2400). The default value of 900 (\~3h of L1 blocks) is good for (high-throughput) networks that see frequent safe head increments. On (low-throughput) networks with infrequent safe head increments, it is recommended to set this value to 0, or a value that well covers the typical span between safe head increments. Note that higher values will cause significantly increased memory usage. | `900` | `OP_NODE_L1_CACHE_SIZE` | | `--l1.epoch-poll-interval` | Poll interval for retrieving new L1 epoch updates such as safe and finalized block changes. Disabled if 0 or negative. | `6m24s` | `OP_NODE_L1_EPOCH_POLL_INTERVAL` | | `--l1.http-poll-interval` | Polling interval for latest-block subscription when using an HTTP RPC provider. Ignored for other types of RPC endpoints. | `12s` | `OP_NODE_L1_HTTP_POLL_INTERVAL` | | `--l1.max-concurrency` | Maximum number of concurrent RPC requests to make to the L1 RPC provider. | `10` | `OP_NODE_L1_MAX_CONCURRENCY` | | `--l1.rpc-max-batch-size` | Maximum number of RPC requests to bundle, e.g. during L1 blocks receipt fetching. The L1 RPC rate limit counts this as N items, but allows it to burst at once. | `20` | `OP_NODE_L1_RPC_MAX_BATCH_SIZE` | | `--l1.rpc-rate-limit` | Optional self-imposed global rate-limit on L1 RPC requests, specified in requests / second. Disabled if set to 0. | `0` | `OP_NODE_L1_RPC_RATE_LIMIT` | | `--l1.rpckind` | The kind of RPC provider, used to inform optimal transactions receipts fetching, and thus reduce costs. Valid options: alchemy, quicknode, infura, parity, nethermind, debug\_geth, erigon, basic, any, standard | `standard` | `OP_NODE_L1_RPC_KIND` | | `--l1.runtime-config-reload-interval` | Poll interval for reloading the runtime config, useful when config events are not being picked up. Disabled if 0 or negative. | `10m0s` | `OP_NODE_L1_RUNTIME_CONFIG_RELOAD_INTERVAL` | | `--l1.trustrpc` | Trust the L1 RPC, sync faster at risk of malicious/buggy RPC providing bad or inconsistent L1 data | `false` | `OP_NODE_L1_TRUST_RPC` | | `--l2.engine-rpc-timeout` | L2 engine client rpc timeout | `10s` | `OP_NODE_L2_ENGINE_RPC_TIMEOUT` | | `--l2.enginekind` | The kind of engine client, used to control the behavior of optimism in respect to different types of engine clients. Valid options: geth, reth, erigon | `reth` | `OP_NODE_L2_ENGINE_KIND` | | `--l2.follow.source` | Address of L2 CL RPC HTTP endpoint to follow source | — | `OP_NODE_L2_FOLLOW_SOURCE` | | `--log.color` | Color the log output if in terminal mode | `false` | `OP_NODE_LOG_COLOR` | | `--log.format` | Format the log output. Supported formats: text, terminal, logfmt, logfmtms, json, jsonms | `text` | `OP_NODE_LOG_FORMAT` | | `--log.level` | The lowest log level that will be output | `INFO` | `OP_NODE_LOG_LEVEL` | | `--log.pid` | Show pid in the log | `false` | `OP_NODE_LOG_PID` | | `--metrics.addr` | Metrics listening address | `"0.0.0.0"` | `OP_NODE_METRICS_ADDR` | | `--metrics.enabled` | Enable the metrics server | `false` | `OP_NODE_METRICS_ENABLED` | | `--metrics.port` | Metrics listening port | `7300` | `OP_NODE_METRICS_PORT` | | `--network` | Predefined network selection. Available networks: every chain bundled from the [superchain-registry](https://github.com/ethereum-optimism/superchain-registry) at the release; run `op-node --help` for the exact list | — | `OP_NODE_NETWORK` | | `--override.canyon` | Manually specify the canyon fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_CANYON` | | `--override.delta` | Manually specify the delta fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_DELTA` | | `--override.ecotone` | Manually specify the ecotone fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_ECOTONE` | | `--override.fjord` | Manually specify the fjord fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_FJORD` | | `--override.granite` | Manually specify the granite fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_GRANITE` | | `--override.holocene` | Manually specify the holocene fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_HOLOCENE` | | `--override.isthmus` | Manually specify the isthmus fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_ISTHMUS` | | `--override.jovian` | Manually specify the jovian fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_JOVIAN` | | `--override.karst` | Manually specify the karst fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_KARST` | | `--override.keep-karst-upgrade-gas` | Manually set keep\_karst\_upgrade\_gas, overriding the bundled setting. When true, the Karst activation block's one-time upgrade gas is kept on every later block (for chains that activated Karst with the leak baked into their history). | `false` | `OP_NODE_OVERRIDE_KEEP_KARST_UPGRADE_GAS` | | `--override.lagoon` | Manually specify the lagoon fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_LAGOON` | | `--override.pectrablobschedule` | Manually specify the pectrablobschedule fork timestamp, overriding the bundled setting | `0` | `OP_NODE_OVERRIDE_PECTRABLOBSCHEDULE` | | `--p2p.advertise.ip` | The IP address to advertise in Discv5, put into the ENR of the node. This may also be a hostname / domain name to resolve to an IP. | — | `OP_NODE_P2P_ADVERTISE_IP` | | `--p2p.advertise.tcp` | The TCP port to advertise in Discv5, put into the ENR of the node. Set to p2p.listen.tcp value if 0. | `0` | `OP_NODE_P2P_ADVERTISE_TCP` | | `--p2p.advertise.udp` | The UDP port to advertise in Discv5 as fallback if not determined by Discv5, put into the ENR of the node. Set to p2p.listen.udp value if 0. | `0` | `OP_NODE_P2P_ADVERTISE_UDP` | | `--p2p.ban.duration` | The duration that peers are banned for. | `1h0m0s` | `OP_NODE_P2P_PEER_BANNING_DURATION` | | `--p2p.ban.peers` | Enables peer banning. | `true` | `OP_NODE_P2P_PEER_BANNING` | | `--p2p.ban.threshold` | The minimum score below which peers are disconnected and banned. | `-100` | `OP_NODE_P2P_PEER_BANNING_THRESHOLD` | | `--p2p.bootnodes` | Comma-separated base64-format ENR list. Bootnodes to start discovering other node records from. | — | `OP_NODE_P2P_BOOTNODES` | | `--p2p.disable` | Completely disable the P2P stack | `false` | `OP_NODE_P2P_DISABLE` | | `--p2p.discovery.path` | Discovered ENRs are persisted in a database to recover from a restart without having to bootstrap the discovery process again. Set to 'memory' to never persist the peerstore. | `"opnode_discovery_db"` | `OP_NODE_P2P_DISCOVERY_PATH` | | `--p2p.gossip.timestamp.threshold` | Threshold for rejecting gossip messages with payload timestamps older than this duration. Default is 60 seconds. | `1m0s` | `OP_NODE_P2P_GOSSIP_TIMESTAMP_THRESHOLD` | | `--p2p.listen.ip` | IP to bind LibP2P and Discv5 to | `"0.0.0.0"` | `OP_NODE_P2P_LISTEN_IP` | | `--p2p.listen.tcp` | TCP port to bind LibP2P to. Any available system port if set to 0. | `9222` | `OP_NODE_P2P_LISTEN_TCP_PORT` | | `--p2p.listen.udp` | UDP port to bind Discv5 to. Same as TCP port if left 0. | `0` | `OP_NODE_P2P_LISTEN_UDP_PORT` | | `--p2p.nat` | Enable NAT traversal with PMP/UPNP devices to learn external IP. | `false` | `OP_NODE_P2P_NAT` | | `--p2p.netrestrict` | Comma-separated list of CIDR masks. P2P will only try to connect on these networks | — | `OP_NODE_P2P_NETRESTRICT` | | `--p2p.no-discovery` | Disable Discv5 (node discovery) | `false` | `OP_NODE_P2P_NO_DISCOVERY` | | `--p2p.peers.grace` | Grace period to keep a newly connected peer around, if it is not misbehaving. | `30s` | `OP_NODE_P2P_PEERS_GRACE` | | `--p2p.peers.hi` | High-tide peer count. The node starts pruning peer connections slowly after reaching this number. | `30` | `OP_NODE_P2P_PEERS_HI` | | `--p2p.peers.lo` | Low-tide peer count. The node actively searches for new peer connections if below this amount. | `20` | `OP_NODE_P2P_PEERS_LO` | | `--p2p.peerstore.path` | Peerstore database location. Persisted peerstores help recover peers after restarts. Set to 'memory' to never persist the peerstore. Peerstore records will be pruned / expire as necessary. Warning: a copy of the priv network key of the local peer will be persisted here. | `"opnode_peerstore_db"` | `OP_NODE_P2P_PEERSTORE_PATH` | | `--p2p.priv.path` | Read the hex-encoded 32-byte private key for the peer ID from this txt file. Created if not already exists.Important to persist to keep the same network identity after restarting, maintaining the previous advertised identity. | `"opnode_p2p_priv.txt"` | `OP_NODE_P2P_PRIV_PATH` | | `--p2p.scoring` | Sets the peer scoring strategy for the P2P stack. Can be one of: none or light. | `"light"` | `OP_NODE_P2P_PEER_SCORING` | | `--p2p.sequencer.key` | Hex-encoded private key for signing off on p2p application messages as sequencer. | — | `OP_NODE_P2P_SEQUENCER_KEY` | | `--p2p.static` | Comma-separated multiaddr-format peer list. Static connections to make and maintain, these peers will be regarded as trusted. Addresses of the local peer are ignored. Duplicate/Alternative addresses for the same peer all apply, but only a single connection per peer is maintained. | — | `OP_NODE_P2P_STATIC` | | `--p2p.sync.req-resp` | Enables the P2P req-resp sync server, which serves payloads-by-number to peers that request them. The client side has been removed; the server will be deprecated in a future release in favor of EL P2P sync. | `true` | `OP_NODE_P2P_SYNC_REQ_RESP` | | `--pprof.addr` | pprof listening address | `"0.0.0.0"` | `OP_NODE_PPROF_ADDR` | | `--pprof.enabled` | Enable the pprof server | `false` | `OP_NODE_PPROF_ENABLED` | | `--pprof.path` | pprof file path. If it is a directory, the path is \{dir}/\{profileType}.prof | — | `OP_NODE_PPROF_PATH` | | `--pprof.port` | pprof listening port | `6060` | `OP_NODE_PPROF_PORT` | | `--pprof.type` | pprof profile type. One of cpu, heap, goroutine, threadcreate, block, mutex, allocs | — | `OP_NODE_PPROF_TYPE` | | `--rollup.config` | Rollup chain parameters | — | `OP_NODE_ROLLUP_CONFIG` | | `--rollup.l1-chain-config` | Path to .json file with the chain configuration for the L1, either in the direct format or genesis.json format (i.e. embedded under the .config property). Not necessary / will be ignored if using Ethereum mainnet or Sepolia as an L1. | — | `OP_NODE_ROLLUP_L1_CHAIN_CONFIG` | | `--rpc.addr` | rpc listening address | `"0.0.0.0"` | `OP_NODE_RPC_ADDR` | | `--rpc.admin-state` | File path used to persist state changes made via the admin API so they persist across restarts. Disabled if not set. | — | `OP_NODE_RPC_ADMIN_STATE` | | `--rpc.enable-admin` | Enable the admin API | `false` | `OP_NODE_RPC_ENABLE_ADMIN` | | `--rpc.port` | rpc listening port | `9545` | `OP_NODE_RPC_PORT` | | `--safedb.path` | File path used to persist safe head update data. Disabled if not set. | — | `OP_NODE_SAFEDB_PATH` | | `--sequencer.enabled` | Enable sequencing of new L2 blocks. A separate batch submitter has to be deployed to publish the data for verifiers. | `false` | `OP_NODE_SEQUENCER_ENABLED` | | `--sequencer.l1-confs` | Number of L1 blocks to keep distance from the L1 head as a sequencer for picking an L1 origin. | `4` | `OP_NODE_SEQUENCER_L1_CONFS` | | `--sequencer.max-safe-lag` | Maximum number of L2 blocks for restricting the distance between L2 safe and unsafe. Disabled if 0. | `0` | `OP_NODE_SEQUENCER_MAX_SAFE_LAG` | | `--sequencer.recover` | Forces the sequencer to strictly prepare the next L1 origin and create empty L2 blocks | `false` | `OP_NODE_SEQUENCER_RECOVER` | | `--sequencer.sealing-duration` | This is the amount of the time the sequencer allocates to sealing the block (i.e. it will fetch the payload from the execution engine this much prior to the block's timestamp). If this is \<= 0 it is automatically adjusted to 50ms. | `50ms` | `OP_NODE_SEQUENCER_SEALING_DURATION` | | `--sequencer.stopped` | Initialize the sequencer in a stopped state. The sequencer can be started using the admin\_startSequencer RPC | `false` | `OP_NODE_SEQUENCER_STOPPED` | | `--signer.address` | Address the signer is signing requests for | — | `OP_NODE_SIGNER_ADDRESS` | | `--signer.endpoint` | Signer endpoint the client will connect to | — | `OP_NODE_SIGNER_ENDPOINT` | | `--signer.header` | Headers to pass to the remote signer. Format `key=value`. Value can contain any character allowed in a HTTP header. When using env vars, split with commas. When using flags one key value pair per flag. | — | `OP_NODE_SIGNER_HEADER` | | `--signer.tls.ca` | tls ca cert path | `"tls/ca.crt"` | `OP_NODE_SIGNER_TLS_CA` | | `--signer.tls.cert` | tls cert path | `"tls/tls.crt"` | `OP_NODE_SIGNER_TLS_CERT` | | `--signer.tls.enabled` | Enable or disable TLS client authentication for the signer | `true` | `OP_NODE_SIGNER_TLS_ENABLED` | | `--signer.tls.key` | tls key | `"tls/tls.key"` | `OP_NODE_SIGNER_TLS_KEY` | | `--syncmode` | Blockchain sync mode (options: consensus-layer, execution-layer) | `consensus-layer` | `OP_NODE_SYNCMODE` | | `--syncmode.offset-el-safe` | After execution-layer sync completes, set safe and finalized heads to this duration behind the synced tip (converted to L2 blocks via rollup block time using ceiling division). Default 12h, matching the OP Mainnet sequencing window. | `12h0m0s` | `OP_NODE_SYNCMODE_OFFSET_EL_SAFE` | | `--verifier.l1-confs` | Number of L1 blocks to keep distance from the L1 head before deriving L2 data from. Reorgs are supported, but may be slow to perform. | `0` | `OP_NODE_VERIFIER_L1_CONFS` | ## Notes on selected flags ### network and rollup.config In addition to the required flags above, the op-node must be told which chain it serves: set exactly one of `--network` (a chain bundled from the superchain-registry, e.g. `op-mainnet`) or `--rollup.config` (a rollup configuration file, for custom chains). Setting both, or neither, is a startup error. ### l1.trustrpc If you're running an Erigon Ethereum execution client for your L1 provider you will need to include `--l1.trustrpc`. At the time of writing, Erigon doesn't support the `eth_getProof` method that op-node prefers to use to load L1 data for some processing. The trustrpc flag makes it use something else that Erigon supports, but the op-node can't verify for correctness. ### syncmode.offset-el-safe Only effective with `--syncmode=execution-layer`. After execution-layer sync completes, the safe and finalized heads are set to this duration behind the synced tip (converted to L2 blocks using the rollup block time). The default `12h` matches the OP Mainnet sequencing window. Setting this to `0` leaves safe and finalized at the synced tip. This is **not recommended and is dangerous**: the offset ensures the node does not label the EL-sync tip as safe/finalized until L1 has had time to confirm it. With `0`, an EL-sync tip that later turns out to be on a reorged (non-canonical) branch can be marked safe/finalized, and safe/finalized are not supposed to reorg. Fix a body-pruning mismatch by enlarging the EL's retained body window instead — see the warning below. op-node reads the L1-info deposit transaction from the block body at the head placed this far behind the tip, so the execution client must retain block bodies at least this far back. Body pruning (op-reth's `--minimal` mode or `--prune.bodies.distance`) is unsupported; if you enable it anyway, keep the retained body window comfortably larger than this offset (in blocks), or EL sync fails with `l2 block is missing L1 info deposit tx`. See [Pruning op-reth](/node-operators/guides/management/archive-node#pruning-op-reth). ### sequencer.l1-confs The maximum value for `sequencer.l1-confs` cannot exceed the sequencer drift, currently set to 30 minutes (1800 seconds or 150 blocks). Setting a value higher than this limit will prevent the sequencer from producing blocks within the sequence window. ### verifier.l1-confs While `verifier.l1-confs` has no strict limit, it's recommended to keep this value within 12-13 minutes (typically 10-20 blocks) for optimal performance. Exceeding this range may impact the verifier's data processing efficiency. ### altda.\* The `altda.*` flags configure Alt-DA mode, a Beta feature of the OP Stack. While it has received initial review from core contributors, it is still undergoing testing, and may have bugs or other issues. See the [Alt-DA mode guide](/chain-operators/guides/features/alt-da-mode-guide) for setup instructions. ### interop.\* The `interop.*` flags configure OP Stack interop networks. Interop is a highly experimental feature; the flags apply only to interop-enabled networks. Do not enable the interop RPC (`--interop.rpc.addr`) if you do not run a supervisor service. ### version Nodes built from source do not output the correct version numbers that are reported on the GitHub release page. ## Node log levels Node log levels determine the verbosity of log messages, allowing operators to filter messages based on importance and detail. The log levels for the `op-node` (used in Optimism) are as follows: 1. Silent (0): No log messages are displayed. This level is rarely used as it provides no feedback on the node's status. 2. Error (1): Only error messages are displayed. Use this level to focus on critical issues that need immediate attention. 3. Warn (2): Displays error messages and warnings. This level helps to identify potential problems that might not be immediately critical but require attention. 4. Info (3): Displays error messages, warnings, and normal activity logs. This is the default level and provides a balanced view of the node's operations without being too verbose. 5. Debug (4): All info-level messages plus additional debugging information. Use this level when troubleshooting issues or developing the node software. 6. Detail (5): The most verbose level, including detailed debugging information and low-level system operations. This level generates a large amount of log data and is typically used only for in-depth troubleshooting. To set the log level, use the `--log.level` flag when running the `op-node` command. For example, to set the log level to debug: ```bash theme={null} op-node --log.level=debug ``` By adjusting the log level, operators can control the amount and type of information that gets logged, helping to manage log data volume and focus on relevant details during different operational scenarios. # op-node JSON-RPC API Source: https://docs.optimism.io/node-operators/reference/op-node-json-rpc Complete reference for op-node RPC methods including rollup-specific functionality. `op-node` implements rollup-specific functionality as the Consensus Layer, similar to an L1 beacon node. It provides RPC methods for querying rollup state, managing peers, and controlling sequencer operations. Use [`eth_gasPrice`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice) instead of `rollup_gasPrices` for the L2 gas price. For the L1 gas price, you can call the [`GasPriceOracle`'s `l1BaseFee` function](https://explorer.optimism.io/address/0x420000000000000000000000000000000000000F#readProxyContract#F11). If you want to estimate the cost of a transaction, you can [use the SDK](/app-developers/tutorials/transactions/sdk-estimate-costs). ## Making RPC Requests The following examples show you how to make requests with [`curl`](https://curl.se/) and [`cast`](https://book.getfoundry.sh/cast/). Protip: piping these commands into [`jq`](https://jqlang.github.io/jq/) will give you nicely formatted JSON responses. `$ cast rpc optimism_syncStatus --rpc-url http://localhost:9545 | jq` ## optimism Namespace Optimism-specific rollup methods for querying chain state and configuration. ### optimism\_outputAtBlock Get the output root at a specific block. This method is documented in [the specifications](https://specs.optimism.io/protocol/rollup-node.html?utm_source=op-docs\&utm_medium=docs#output-method-api). ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"optimism_outputAtBlock","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc optimism_outputAtBlock --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc":"2.0", "id":1, "result":[ "0x0000000000000000000000000000000000000000000000000000000000000000", "0xabe711e34c1387c8c56d0def8ce77e454d6a0bfd26cef2396626202238442421" ] } ``` ### optimism\_syncStatus Get the synchronization status of the rollup node. This method provides detailed information about L1 and L2 block processing states. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"optimism_syncStatus","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc optimism_syncStatus --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "current_l1": { "hash": "0xff3b3253058411b727ac662f4c9ae1698918179e02ecebd304beb1a1ae8fc4fd", "number": 4427350, "parentHash": "0xb26586390c3f04678706dde13abfb5c6e6bb545e59c22774e651db224b16cd48", "timestamp": 1696478784 }, "current_l1_finalized": { "hash": "0x7157f91b8ae21ef869c604e5b268e392de5aa69a9f44466b9b0f838d56426541", "number": 4706784, "parentHash": "0x1ac2612a500b9facd650950b8755d97cf2470818da2d88552dea7cd563e86a17", "timestamp": 1700160084 }, "head_l1": { "hash": "0x6110a8e6ed4c4aaab20477a3eac81bf99e505bf6370cd4d2e3c6d34aa5f4059a", "number": 4706863, "parentHash": "0xee8a9cba5d93481f11145c24890fd8f536384f3c3c043f40006650538fbdcb56", "timestamp": 1700161272 }, "safe_l1": { "hash": "0x8407c9968ce278ab435eeaced18ba8f2f94670ad9d3bdd170560932cf46e2804", "number": 4706811, "parentHash": "0x6593cccab3e772776418ff691f6e4e75597af18505373522480fdd97219c06ef", "timestamp": 1700160480 }, "finalized_l1": { "hash": "0x7157f91b8ae21ef869c604e5b268e392de5aa69a9f44466b9b0f838d56426541", "number": 4706784, "parentHash": "0x1ac2612a500b9facd650950b8755d97cf2470818da2d88552dea7cd563e86a17", "timestamp": 1700160084 }, "unsafe_l2": { "hash": "0x9a3b2edab72150de252d45cabe2f1ac57d48ddd52bb891831ffed00e89408fe4", "number": 2338094, "parentHash": "0x935b94ec0bac0e63c67a870b1a97d79e3fa84dda86d31996516cb2f940753f53", "timestamp": 1696478728, "l1origin": { "hash": "0x38731e0a6eeb40091f0c4a00650e911c57d054aaeb5b158f55cd5705fa6a3ebf", "number": 4427339 }, "sequenceNumber": 3 }, "safe_l2": { "hash": "0x9a3b2edab72150de252d45cabe2f1ac57d48ddd52bb891831ffed00e89408fe4", "number": 2338094, "parentHash": "0x935b94ec0bac0e63c67a870b1a97d79e3fa84dda86d31996516cb2f940753f53", "timestamp": 1696478728, "l1origin": { "hash": "0x38731e0a6eeb40091f0c4a00650e911c57d054aaeb5b158f55cd5705fa6a3ebf", "number": 4427339 }, "sequenceNumber": 3 }, "finalized_l2": { "hash": "0x285b03afb46faad747be1ca7ab6ef50ef0ff1fe04e4eeabafc54f129d180fad2", "number": 2337942, "parentHash": "0x7e7f36cba1fd1ccdcdaa81577a1732776a01c0108ab5f98986cf997724eb48ac", "timestamp": 1696478424, "l1origin": { "hash": "0x983309dadf7e0ab8447f3050f2a85b179e9acde1cd884f883fb331908c356412", "number": 4427314 }, "sequenceNumber": 7 }, "pending_safe_l2": { "hash": "0x9a3b2edab72150de252d45cabe2f1ac57d48ddd52bb891831ffed00e89408fe4", "number": 2338094, "parentHash": "0x935b94ec0bac0e63c67a870b1a97d79e3fa84dda86d31996516cb2f940753f53", "timestamp": 1696478728, "l1origin": { "hash": "0x38731e0a6eeb40091f0c4a00650e911c57d054aaeb5b158f55cd5705fa6a3ebf", "number": 4427339 }, "sequenceNumber": 3 }, "queued_unsafe_l2": { "hash": "0x3af253f5b993f58fffdd5e594b3f53f5b7b254cdc18f4bdb13ea7331149942db", "number": 4054795, "parentHash": "0x284b7dc92bac97be8ec3b2cf548e75208eb288704de381f2557938ecdf86539d", "timestamp": 1699912130, "l1origin": { "hash": "0x1490a63c372090a0331e05e63ec6a7a6e84835f91776306531f28b4217394d76", "number": 4688196 }, "sequenceNumber": 2 }, "engine_sync_target": { "hash": "0x9a3b2edab72150de252d45cabe2f1ac57d48ddd52bb891831ffed00e89408fe4", "number": 2338094, "parentHash": "0x935b94ec0bac0e63c67a870b1a97d79e3fa84dda86d31996516cb2f940753f53", "timestamp": 1696478728, "l1origin": { "hash": "0x38731e0a6eeb40091f0c4a00650e911c57d054aaeb5b158f55cd5705fa6a3ebf", "number": 4427339 }, "sequenceNumber": 3 } } ``` ### optimism\_rollupConfig Get the rollup configuration parameters. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"optimism_rollupConfig","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc optimism_rollupConfig --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "genesis": { "l1": { "hash": "0x48f520cf4ddaf34c8336e6e490632ea3cf1e5e93b0b2bc6e917557e31845371b", "number": 4071408 }, "l2": { "hash": "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", "number": 0 }, "l2_time": 1691802540, "system_config": { "batcherAddr": "0x8f23bb38f531600e5d8fddaaec41f13fab46e98c", "overhead": "0x00000000000000000000000000000000000000000000000000000000000000bc", "scalar": "0x00000000000000000000000000000000000000000000000000000000000a6fe0", "gasLimit": 30000000 } }, "block_time": 2, "max_sequencer_drift": 600, "seq_window_size": 3600, "channel_timeout": 300, "l1_chain_id": 11155111, "l2_chain_id": 11155420, "regolith_time": 0, "canyon_time": 1699981200, "batch_inbox_address": "0xff00000000000000000000000000000011155420", "deposit_contract_address": "0x16fc5058f25648194471939df75cf27a2fdc48bc", "l1_system_config_address": "0x034edd2a225f7f429a63e0f1d2084b9e0a93b538" } ``` ### optimism\_version Get the software version of the op-node. At the moment, building from source will not give you the correct version, but our docker images will. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"optimism_version","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc optimism_version --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc":"2.0", "id":1, "result":"v0.0.0-" } ``` ## opp2p Namespace The `opp2p` namespace handles peer-to-peer networking interactions, allowing you to manage peer connections, discovery, and network policies. ### opp2p\_self Returns your node's peer information including peer ID, addresses, and network configuration. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_self","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_self --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "peerID": "16Uiu2HAm2y6DXp6THWHCyquczNUh8gVAm4spo6hjP3Ns1dGRiAdE", "nodeID": "75a52a90fe5f972171fefce2399ca5a73191c654e7c7ddfdd71edf4fca6697f0", "userAgent": "", "protocolVersion": "", "ENR": "enr:-J-4QFOtI_hDBa_kilrQcg4iTJt9VMAuDLCbgAAKMa--WfxoPml1xDYxypUG7IsWga83FOlvr78LG3oH8CfzRzUmsDyGAYvKqIZ2gmlkgnY0gmlwhGxAaceHb3BzdGFja4Xc76gFAIlzZWNwMjU2azGhAnAON-FvpiWY2iG_LXJDYosknGyikaajPDd1cQARsVnBg3RjcIIkBoN1ZHCC0Vs", "addresses": [ "/ip4/127.0.0.1/tcp/9222/p2p/16Uiu2HAm2y6DXp6THWHCyquczNUh8gVAm4spo6hjP3Ns1dGRiAdE", "/ip4/192.168.1.71/tcp/9222/p2p/16Uiu2HAm2y6DXp6THWHCyquczNUh8gVAm4spo6hjP3Ns1dGRiAdE", "/ip4/108.64.105.199/tcp/9222/p2p/16Uiu2HAm2y6DXp6THWHCyquczNUh8gVAm4spo6hjP3Ns1dGRiAdE" ], "protocols": null, "connectedness": 0, "direction": 0, "protected": false, "chainID": 0, "latency": 0, "gossipBlocks": true, "scores": { "gossip": { "total": 0, "blocks": { "timeInMesh": 0, "firstMessageDeliveries": 0, "meshMessageDeliveries": 0, "invalidMessageDeliveries": 0 }, "IPColocationFactor": 0, "behavioralPenalty": 0 }, "reqResp": { "validResponses": 0, "errorResponses": 0, "rejectedPayloads": 0 } } } } ``` ### opp2p\_peers Returns a list of your node's peers with detailed connection information. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_peers","params":[true],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_peers true --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "totalConnected": 20, "peers": { "16Uiu2HAkvNYscHu4V1uj6fVWkwrAMCRsqXDSq4mUbhpGq4LttYsC": { "peerID": "16Uiu2HAkvNYscHu4V1uj6fVWkwrAMCRsqXDSq4mUbhpGq4LttYsC", "nodeID": "d693c5b58424016c0c38ec5539c272c754cb6b8007b322e0ecf16a4ee13f96fb", "userAgent": "optimism", "protocolVersion": "", "ENR": "", "addresses": [ "/ip4/20.249.62.215/tcp/9222/p2p/16Uiu2HAkvNYscHu4V1uj6fVWkwrAMCRsqXDSq4mUbhpGq4LttYsC" ], "protocols": [ "/ipfs/ping/1.0.0", "/meshsub/1.0.0", "/meshsub/1.1.0", "/opstack/req/payload_by_number/11155420/0", "/floodsub/1.0.0", "/ipfs/id/1.0.0", "/ipfs/id/push/1.0.0" ], "connectedness": 1, "direction": 1, "protected": false, "chainID": 0, "latency": 0, "gossipBlocks": true, "scores": { "gossip": { "total": -5.04, "blocks": { "timeInMesh": 0, "firstMessageDeliveries": 0, "meshMessageDeliveries": 0, "invalidMessageDeliveries": 0 }, "IPColocationFactor": 0, "behavioralPenalty": 0 }, "reqResp": { "validResponses": 0, "errorResponses": 0, "rejectedPayloads": 0 } } } }, "bannedPeers": [], "bannedIPS": [], "bannedSubnets": [] } } ``` ### opp2p\_peerStats Returns aggregate statistics about your peer connections. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_peerStats","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_peerStats --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "connected": 20, "table": 94, "blocksTopic": 20, "blocksTopicV2": 18, "banned": 0, "known": 71 } } ``` ### opp2p\_discoveryTable Returns your peer discovery table containing node records (ENRs) of discovered peers. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_discoveryTable","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_discoveryTable --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": [ "enr:-J24QGC_SzoGG4EqyvO_082paQOwhvECeWGT-kaenrHdE2_iLTLeGmH-IOVpqEjC0L-yWmkI-c7598VaCjHQRNWn1CyGAYsqDgrFgmlkgnY0gmlwhNgp3WeHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQPiq20PNZYzyvpEifcGVrOXHfM94JeWSgDL07I2hSl0d4N0Y3CCJAaDdWRwgiQG", "enr:-J24QKvt2ThBM8-FPeHfAmpoaVLdfVD2cw1cRpNuwmvH_bQtQ1dqrrZw9FqiMbXbFRQf9IvjrlKSFLodbsRALIFATICGAYuQClJigmlkgnY0gmlwhKI3ZuaHb3BzdGFja4O6BACJc2VjcDI1NmsxoQLQRz2CH95qQd6vmF5saV-WOoTZobNfSt-FUdVa7R35nYN0Y3CCIyuDdWRwgiMr" ] } ``` ### opp2p\_blockPeer Blocks a peer by peer ID, preventing future connections. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_blockPeer","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_blockPeer --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_unblockPeer Unblocks a previously blocked peer. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_unblockPeer","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_unblockPeer --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_listBlockedPeers Returns a list of blocked peer IDs. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_listBlockedPeers","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_listBlockedPeers --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": [ "16Uiu2HAmV3PueiaHj7Rg2bs3mrRUo2RVhjXRMpH67k9iZquDGQ8v" ] } ``` ### opp2p\_blockAddr Blocks connections from a specific IP address. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_blockAddr","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_blockAddr --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_unblockAddr Unblocks a previously blocked IP address. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_unblockAddr","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_unblockAddr --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_listBlockedAddrs Returns a list of blocked IP addresses. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_listBlockedAddrs","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_listBlockedAddrs --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": [ "2607:f8b0:4002:c0c::65" ] } ``` ### opp2p\_blockSubnet Blocks connections from a specific subnet (CIDR notation). ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_blockSubnet","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_blockSubnet --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_unblockSubnet Unblocks a previously blocked subnet. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_unblockSubnet","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_unblockSubnet --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_listBlockedSubnets Returns a list of blocked subnets. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_listBlockedSubnets","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_listBlockedSubnets --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": [] } ``` ### opp2p\_protectPeer Protects a peer from being pruned from the connection pool. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_protectPeer","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_protectPeer --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_unprotectPeer Removes protection from a peer, allowing it to be pruned if necessary. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_unprotectPeer","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_unprotectPeer --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_connectPeer Initiates a connection to a peer using its multiaddress. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_connectPeer","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_connectPeer --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### opp2p\_disconnectPeer Disconnects from a specific peer. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"opp2p_disconnectPeer","params":[""],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc opp2p_disconnectPeer --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ## admin Namespace Administrative methods for controlling sequencer operations and the derivation pipeline. ### admin\_resetDerivationPipeline Resets the derivation pipeline, forcing it to re-derive L2 blocks from L1 data. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"admin_resetDerivationPipeline","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc admin_resetDerivationPipeline --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### admin\_startSequencer Starts the sequencer if it was previously stopped. This allows the node to begin producing new blocks. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"admin_startSequencer","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc admin_startSequencer --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### admin\_stopSequencer Stops the sequencer, preventing it from producing new blocks. The node will continue to sync from other sequencers. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"admin_stopSequencer","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc admin_stopSequencer --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": null } ``` ### admin\_sequencerActive Returns whether the sequencer is currently active and producing blocks. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"admin_sequencerActive","params":[],"id":1}' \ http://localhost:9545 ``` ```sh theme={null} cast rpc admin_sequencerActive --rpc-url http://localhost:9545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": true } ``` # op-reth configuration options Source: https://docs.optimism.io/node-operators/reference/op-reth-config Where to find the op-reth CLI reference, and how op-reth pairs with op-node. op-reth's flag reference lives in one place: the [op-reth CLI reference](/node-operators/op-reth/cli/overview), imported into these docs from the op-reth source tree and versioned with it. Start there for the command taxonomy and configuration model, or jump straight to the [`op-reth node` flag listing](/node-operators/op-reth/cli/op-reth/node) for the full `--help` output of the command node operators run. This page previously carried a hand-maintained copy of the op-reth flag catalog, pinned to an old release; it has been retired in favor of the single imported surface above so the flag facts cannot drift between two pages. **op-reth is the recommended execution client for new OP Stack deployments.** op-node's `--l2.enginekind` flag defaults to `reth`, so no extra engine-kind configuration is needed when pairing the two; set it explicitly only when running a different execution client (`geth` or `erigon`). See the [op-node configuration options](/node-operators/reference/op-node-config) page for the engine-side flags. ## Related references * [op-reth JSON-RPC reference](/node-operators/reference/op-reth-json-rpc) * [op-reth historical proofs configuration](/node-operators/reference/op-reth-historical-proof-config) * [Building an archive node / pruning op-reth](/node-operators/guides/management/archive-node) * Upstream cross-reference: [Reth CLI documentation](https://reth.rs/cli/reth.html) # op-reth historical proof configuration Source: https://docs.optimism.io/node-operators/reference/op-reth-historical-proof-config Configuration options for the op-reth historical proof store (v2). This page documents the configuration options for the **historical proof store (v2)** in [op-reth](https://github.com/ethereum-optimism/optimism/tree/develop/rust/op-reth). When enabled, op-reth maintains a separate storage database for versioned trie data used to serve `eth_getProof` for historical blocks. This is critical for historical state access (for example, fault proof workloads) without requiring full archive-style behavior from the execution database. op-reth **v2.2.3 or later** is required to enable historical proofs v2. Earlier versions do not support the `--proofs-history.storage-version=v2` flag. Use the **historical proofs storage format v2** by setting `--proofs-history.storage-version=v2`. For a complete setup guide, see the tutorial on [Running op-reth with Historical Proofs](/node-operators/tutorials/reth-historical-proofs). This fork inherits all standard op-reth configuration options. See the [op-reth configuration reference](/node-operators/reference/op-reth-config). ## Historical proof store (v2) Options for configuring the v2 historical proof store. ### proofs-history If true, enable the historical proof store and keep it updated as new blocks are processed. `--proofs-history` ### proofs-history.storage-version Storage format version for the historical proofs database. For the v2 system, set this to `v2`. `--proofs-history.storage-version ` `v2` ### proofs-history.storage-path The path to the storage DB for proofs history. `--proofs-history.storage-path ` ### proofs-history.window The window to span blocks for proofs history. Value is the number of blocks. Default is 1 month of blocks based on 2 seconds block time (`30 * 24 * 60 * 60 / 2 = 1,296,000`). `--proofs-history.window ` `1296000` ### proofs-history.verification-interval Verification interval: perform full block execution every N blocks for data integrity. * `0`: Disabled (Default). Always use fast path with pre-computed data. * `1`: Always verify. Always execute blocks. * `N`: Verify every Nth block (e.g., 100 = every 100 blocks). Periodic verification helps catch data corruption while maintaining good performance. `--proofs-history.verification-interval ` `0` ## Lifecycle and management commands In v2, operators usually follow this lifecycle: 1. Run `op-reth proofs init` once to initialize the proofs DB at the current tip. 2. Start `op-reth` with `--proofs-history --proofs-history.storage-version=v2` so the node uses historical proofs storage format v2. 3. Let the store fill proofs data **forward** from the initialization point. 4. Let automatic pruning enforce the configured retention window. 5. Use manual `prune` or `unwind` only for recovery/maintenance scenarios. The `op-reth proofs` command provides these maintenance operations. ### init Initialize the proofs storage with the current state of the chain. ```bash theme={null} op-reth proofs init --chain --datadir --proofs-history.storage-path --proofs-history.storage-version=v2 ``` The first time `proofs init` runs, it can take minutes to hours. Subsequent invocations should usually take seconds. `proofs init` does **not** backfill historical proofs. It records the current chain tip as the starting point of the proofs database. After initialization, run the node with `--proofs-history` so the store fills forward as new blocks are committed. To serve proofs across the full retention window (for example, 30 days with default settings), the node must accumulate that much forward history after init. In practice, operators should initialize from a snapshot that is already old enough to satisfy the required historical window as syncing advances. ### prune Prune old proof history to reclaim space. ```bash theme={null} op-reth proofs prune --chain --datadir --proofs-history.storage-path --proofs-history.window ``` Pruning runs automatically while the node is up, driven by the engine task as new blocks are committed; no separate interval flag is required. Manual prune is mainly a recovery action, for example if op-reth detects a large mismatch between configured retention and on-disk data and refuses startup. See the [tutorial](/node-operators/tutorials/reth-historical-proofs#manual-prune) for details. ### unwind Unwind the proofs storage to a specific block ```bash theme={null} op-reth proofs unwind --datadir --proofs-history.storage-path --target ``` ## RPC Endpoints ### debug\_proofsSyncStatus Returns the current sync status of the proofs store. ``` debug_proofsSyncStatus → { "earliest": , "latest": } ``` `earliest` and `latest` define the currently available historical-proof interval in the v2 store. Once `latest` tracks chain tip, `eth_getProof` calls for blocks within `[earliest, latest]` are served from the versioned proofs store. ## v1 to v2 operator notes * The historical-proof path is now centered on a dedicated versioned proofs store lifecycle (`init` -> forward fill -> prune), rather than treating it as a standalone extension workflow. * `proofs init` establishes a starting point only; it does not reconstruct old proofs data. * Coverage is operationally measured via `debug_proofsSyncStatus` (`earliest`/`latest`). * For stable long-window proof serving, validate startup snapshots and retention settings together. ## Metrics When the `metrics` feature is enabled, the proofs-history system exposes Prometheus metrics to monitor health and performance. ### Block processing (`optimism_trie.block.*`) | Metric | Type | Description | | ------------------------------------ | --------- | ------------------------------------------- | | `total_duration_seconds` | Histogram | End-to-end time to process a block | | `execution_duration_seconds` | Histogram | Time spent in EVM execution | | `state_root_duration_seconds` | Histogram | Time spent calculating state root | | `write_duration_seconds` | Histogram | Time spent writing trie updates to storage | | `account_trie_updates_written_total` | Counter | Number of account trie branch nodes written | | `storage_trie_updates_written_total` | Counter | Number of storage trie branch nodes written | | `hashed_accounts_written_total` | Counter | Number of hashed account entries written | | `hashed_storages_written_total` | Counter | Number of hashed storage entries written | | `earliest_number` | Gauge | Earliest block number in the proofs store | | `latest_number` | Gauge | Latest block number in the proofs store | ### Pruner (`optimism_trie.pruner.*`) | Metric | Type | Description | | ------------------------------ | --------- | ------------------------------------------------ | | `total_duration_seconds` | Histogram | Duration of each prune run | | `pruned_blocks` | Gauge | Number of blocks pruned in the last run | | `account_trie_updates_written` | Gauge | Account trie entries deleted in the last prune | | `storage_trie_updates_written` | Gauge | Storage trie entries deleted in the last prune | | `hashed_accounts_written` | Gauge | Hashed account entries deleted in the last prune | | `hashed_storages_written` | Gauge | Hashed storage entries deleted in the last prune | ### RPC (`optimism_rpc.eth_api_ext.*`) | Metric | Type | Description | | -------------------------------- | --------- | --------------------------------------------- | | `get_proof_latency` | Histogram | Latency of successful `eth_getProof` requests | | `get_proof_requests` | Counter | Total `eth_getProof` requests received | | `get_proof_successful_responses` | Counter | Total successful `eth_getProof` responses | | `get_proof_failures` | Counter | Total failed `eth_getProof` requests | ### Storage operations (`optimism_trie.storage.operation.*`) Per-operation `duration_seconds` histograms are recorded for: `store_account_branch`, `store_storage_branch`, `store_hashed_account`, `store_hashed_storage`, `trie_cursor_seek_exact`, `trie_cursor_seek`, `trie_cursor_next`, `trie_cursor_current`, `hashed_cursor_seek`, `hashed_cursor_next`. # op-reth JSON-RPC API Source: https://docs.optimism.io/node-operators/reference/op-reth-json-rpc Complete reference for op-reth execution client RPC methods with OP Stack enhancements. `op-reth` is the Rust execution client for the OP Stack, based on [Reth](https://github.com/paradigmxyz/reth). It implements the same Engine API and Ethereum JSON-RPC surface as `op-geth`, so it is a drop-in alternative on OP Stack chains. This page documents the JSON-RPC methods that were tested against an OP Stack devnet running `op-reth v2.2.3` (build `reth/v2.2.0-88505c7`) with the V2 (Jovian) fee model active. ## Overview `op-reth` implements the standard Ethereum JSON-RPC API with the same OP Stack additions as `op-geth`. Familiar Ethereum tools (cast, web3.js, ethers, viem, …) work without modification. The execution engine's RPC interface is functionally identical to [the upstream Reth RPC interface](https://reth.rs/run/run-a-node.html#rpc-namespaces). The OP-specific behavior matches `op-geth`: transaction receipts include additional L1 data-availability fee fields, and deposit transactions (type `0x7e`) carry OP-specific fields. ## Key Differences from Ethereum While `op-reth` maintains compatibility with Ethereum's JSON-RPC API, there are important differences shared with the wider OP Stack: ### Transaction Receipts User transaction receipts include additional L1 data fee information. With the **V2 (Jovian) fee model** the fields are: * **`l1GasUsed`** — Amount of L1 gas attributed to L1 data availability. * **`l1GasPrice`** — L1 base fee at the time of execution. * **`l1Fee`** — Total L1 data fee charged in wei. * **`l1BaseFeeScalar`** — Scalar applied to the L1 base fee component. * **`l1BlobBaseFee`** — L1 blob base fee at the time of execution. * **`l1BlobBaseFeeScalar`** — Scalar applied to the L1 blob base fee component. * **`daFootprintGasScalar`** — Scalar applied to the data-availability footprint. The legacy single-scalar field **`l1FeeScalar`** (used by Bedrock-era chains and still shown in older `op-geth` docs) is **not** present on V2 chains. Clients that hardcode `l1FeeScalar` need to read the new scalar fields above. The `l1GasUsed`, `l1GasPrice`, and `l1Fee` fields are unchanged. ### Deposit transactions OP Stack deposit transactions (`type: 0x7e`) include extra fields in both transaction and receipt responses: * On the transaction: `sourceHash`, `mint`, `depositReceiptVersion`. * On the receipt: `depositNonce`, `depositReceiptVersion`. ### Gas Price Calculation For L2 gas prices, use the standard [`eth_gasPrice`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice) method. For L1 gas prices and end-to-end fee estimation, use the [`GasPriceOracle`](https://explorer.optimism.io/address/0x420000000000000000000000000000000000000F) predeploy or [the Optimism SDK](/app-developers/tutorials/transactions/sdk-estimate-costs). ## Standard JSON-RPC Methods All examples below were verified live against `op-reth v2.2.3`. ### eth\_blockNumber Returns the number of the most recent block. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ http://localhost:8545 ``` ```sh theme={null} cast block-number --rpc-url http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x1202c" } ``` ### eth\_chainId Returns the currently configured chain ID, used for signing replay-protected transactions. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x190a85e3" } ``` ### eth\_syncing Returns sync status. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' \ http://localhost:8545 ``` Unlike `op-geth`, `op-reth` always returns a **structured object** that lists each pipeline stage (`Headers`, `Bodies`, `Execution`, `MerkleExecute`, …) and their per-stage progress, even when the node is fully synced. Clients that treat any non-`false` response as "still syncing" need to compare `currentBlock` and `highestBlock` instead. Sample output (synced node): ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "startingBlock": "0x1202c", "currentBlock": "0x1202c", "highestBlock": "0x1202c", "stages": [ { "name": "Headers", "block": "0x1202c" }, { "name": "Bodies", "block": "0x1202c" }, { "name": "Execution", "block": "0x1202c" }, { "name": "MerkleExecute", "block": "0x1202c" }, { "name": "Finish", "block": "0x1202c" } ] } } ``` ### eth\_getBalance Returns the balance of the account at the given address. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x4200000000000000000000000000000000000015","latest"],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x0" } ``` ### eth\_getTransactionByHash Returns information about a transaction by transaction hash. Deposit transactions include `sourceHash`, `mint`, and `depositReceiptVersion`. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0x38a7db9aa2d7ec70d55ac7de90384279bdcad38ecdf68e3fcc4c6b649761daf9"],"id":1}' \ http://localhost:8545 ``` Sample success output (deposit transaction): ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "type": "0x7e", "sourceHash": "0xdbad163233eb082b43df51b26625dcfbd997bcd2f0810a58a651c633516c4941", "from": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001", "to": "0x4200000000000000000000000000000000000015", "mint": "0x0", "value": "0x0", "gas": "0xf4240", "input": "0x3db6be2b…", "hash": "0x38a7db9aa2d7ec70d55ac7de90384279bdcad38ecdf68e3fcc4c6b649761daf9", "blockHash": "0x5bbabb299894fa2f763a0b6bbccc966b80e791aa49663b80fc9789e0f04183ea", "blockNumber": "0x1202c", "transactionIndex": "0x0", "blockTimestamp": "0x69fda224", "depositReceiptVersion": "0x1", "gasPrice": "0x0", "nonce": "0x1202b", "r": "0x0", "s": "0x0", "v": "0x0", "yParity": "0x0" } } ``` ### eth\_getTransactionReceipt Returns the receipt of a transaction by hash. Includes OP Stack–specific L1 fee fields. The example below is a deposit-tx receipt (note the `depositNonce` / `depositReceiptVersion` fields and `l1Fee = 0`); a regular user-tx receipt will carry a non-zero `l1Fee` computed from the V2 scalars. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x38a7db9aa2d7ec70d55ac7de90384279bdcad38ecdf68e3fcc4c6b649761daf9"],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "type": "0x7e", "status": "0x1", "cumulativeGasUsed": "0xb44e", "logs": [], "logsBloom": "0x000…", "transactionHash": "0x38a7db9aa2d7ec70d55ac7de90384279bdcad38ecdf68e3fcc4c6b649761daf9", "transactionIndex": "0x0", "blockHash": "0x5bbabb299894fa2f763a0b6bbccc966b80e791aa49663b80fc9789e0f04183ea", "blockNumber": "0x1202c", "gasUsed": "0xb44e", "effectiveGasPrice": "0x0", "blobGasUsed": "0xabe0", "from": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001", "to": "0x4200000000000000000000000000000000000015", "contractAddress": null, "depositNonce": "0x1202b", "depositReceiptVersion": "0x1", "l1GasPrice": "0x35", "l1GasUsed": "0x6e7", "l1Fee": "0x0", "l1BaseFeeScalar": "0x558", "l1BlobBaseFee": "0x3", "l1BlobBaseFeeScalar": "0xc3c9d", "daFootprintGasScalar": "0x190" } } ``` Notice the OP-specific fields at the end of the receipt: `l1GasUsed`, `l1GasPrice`, `l1Fee`, plus the V2 scalars `l1BaseFeeScalar`, `l1BlobBaseFee`, `l1BlobBaseFeeScalar`, and `daFootprintGasScalar`. The Bedrock-era `l1FeeScalar` field is **not** present on V2 chains. ### eth\_call Executes a new message call immediately without creating a transaction on the blockchain. Example calls `GasPriceOracle.l1BaseFee()`. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x420000000000000000000000000000000000000F","data":"0x519b4bd3"},"latest"],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x0000000000000000000000000000000000000000000000000000000000000030" } ``` ### eth\_estimateGas Generates and returns an estimate of gas needed for a transaction to complete. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{"from":"0x0000000000000000000000000000000000000001","to":"0x0000000000000000000000000000000000000002","value":"0x0"}],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x52e9" } ``` `eth_estimateGas` only estimates L2 execution gas. To calculate the total transaction cost including L1 data fees, use the [Optimism SDK](/app-developers/tutorials/transactions/sdk-estimate-costs) or query the [`GasPriceOracle` predeployed contract](https://explorer.optimism.io/address/0x420000000000000000000000000000000000000F). ### eth\_sendRawTransaction Submits a signed transaction to the network. The example payload is intentionally invalid to demonstrate the error shape. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"],"id":1}' \ http://localhost:8545 ``` Sample error output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "failed to decode signed transaction" } } ``` A well-formed signed transaction returns the transaction hash as `result`. ### eth\_getBlockByNumber Returns information about a block by block number. Op-reth populates the standard post-Ecotone/Cancun fields: `withdrawalsRoot`, `blobGasUsed`, `excessBlobGas`, `parentBeaconBlockRoot`, and `requestsHash`. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1b4",false],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "hash": "0x791e5f88a078641354af3c85dbd009b5658e36e1509a2262c11f8a7fc51c2883", "parentHash": "0xa4d2ce03caea13be2262673a58860ac2e717a00d6cf02fee63d7ce61327c32b9", "miner": "0x4200000000000000000000000000000000000011", "number": "0x1b4", "gasLimit": "0x3938700", "gasUsed": "0xb44e", "timestamp": "0x69fb6534", "baseFeePerGas": "0xa787b25", "withdrawalsRoot": "0x8ed4baae3a927be3dea54996b4d5899f8c01e7594bf50b17dc1e741388ce3d12", "blobGasUsed": "0x0", "excessBlobGas": "0x0", "parentBeaconBlockRoot": "0x22096025070f565b96c8aaf633cb809ca242170c6188818cdebca9ead88756d5", "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "transactions": [ "0xd9531a51bda284c199328f058383e8376b65c311b0671056344ad3af4700787a" ], "withdrawals": [] } } ``` ### eth\_getLogs Returns an array of all logs matching a given filter object. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x1","toBlock":"0x2","address":"0x8320fe7702b96808f7bbc0d4a888ed1468216cfd"}],"id":1}' \ http://localhost:8545 ``` Sample success output (empty filter result): ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": [] } ``` ## Gas Price Methods ### eth\_gasPrice Returns the current gas price in wei for L2 execution. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0xf433b" } ``` This only returns the L2 gas price. For comprehensive transaction cost estimation including L1 data fees, use the [`GasPriceOracle` predeployed contract](https://explorer.optimism.io/address/0x420000000000000000000000000000000000000F) or [the Optimism SDK](/app-developers/tutorials/transactions/sdk-estimate-costs). ### eth\_maxPriorityFeePerGas Returns the current maximum priority fee per gas (EIP-1559). ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_maxPriorityFeePerGas","params":[],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0xf4240" } ``` ### eth\_feeHistory Returns historical base fee, gas-usage ratio, blob base fee, and priority-fee percentile data for fee estimation. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_feeHistory","params":["0x4","latest",[25,50,75]],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "oldestBlock": "0x12396", "baseFeePerGas": ["0xfb","0xfb","0xfb","0xfb","0xfb"], "gasUsedRatio": [0.0007691,0.0007691,0.0007691,0.0007691], "baseFeePerBlobGas": ["0x1","0x1","0x1","0x1","0x1"], "blobGasUsedRatio": [0.0,0.0,0.0,0.0], "reward": [["0x0","0x0","0x0"],["0x0","0x0","0x0"],["0x0","0x0","0x0"],["0x0","0x0","0x0"]] } } ``` ## Account and State Methods ### eth\_getCode Returns code at a given address. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_getCode","params":["0x420000000000000000000000000000000000000F","latest"],"id":1}' \ http://localhost:8545 ``` Sample success output (truncated): ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x60806040526004361061005e5760003560e01c80635c60da1b…" } ``` ### eth\_getStorageAt Returns the value from a storage position at a given address. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_getStorageAt","params":["0x420000000000000000000000000000000000000F","0x0","latest"],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x0000000000000000000000000000000000000000000000000000000001010101" } ``` ### eth\_getTransactionCount Returns the number of transactions sent from an address (the nonce). ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001","latest"],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x12146" } ``` ## Txpool Methods When the `txpool` namespace is enabled (`--http.api eth,net,web3,debug,txpool`), `op-reth` exposes the standard txpool inspection methods. ### txpool\_status ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"txpool_status","params":[],"id":1}' \ http://localhost:8545 ``` Sample success output: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "pending": "0x0", "queued": "0x0" } } ``` ## Debug Methods `op-reth` supports the `debug_*` namespace for transaction inspection. Enable with `--http.api …,debug`. Debug methods can be resource-intensive. Most public RPC providers disable them. You'll need to run your own node with the `debug` namespace enabled to access them. ### debug\_traceTransaction Returns the trace of a transaction, showing all internal calls and state changes. The `callTracer` is recommended for most use cases. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0x38a7db9aa2d7ec70d55ac7de90384279bdcad38ecdf68e3fcc4c6b649761daf9",{"tracer":"callTracer"}],"id":1}' \ http://localhost:8545 ``` Sample success output (deposit tx that proxies into the L1Block predeploy implementation): ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "from": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001", "gas": "0xf4240", "gasUsed": "0xb44e", "to": "0x4200000000000000000000000000000000000015", "input": "0x3db6be2b…", "calls": [ { "from": "0x4200000000000000000000000000000000000015", "gas": "0xe9b56", "gasUsed": "0x489b", "to": "0xc0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d30015", "input": "0x3db6be2b…", "value": "0x0", "type": "DELEGATECALL" } ], "value": "0x0", "type": "CALL" } } ``` ### debug\_traceCall Traces a call without executing it on-chain. ```sh theme={null} curl -X POST -H "Content-Type: application/json" --data \ '{"jsonrpc":"2.0","method":"debug_traceCall","params":[{"to":"0x420000000000000000000000000000000000000F","data":"0x519b4bd3"},"latest",{"tracer":"callTracer"}],"id":1}' \ http://localhost:8545 ``` Sample success output (call to `GasPriceOracle.l1BaseFee()`): ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "from": "0x0000000000000000000000000000000000000000", "gas": "0x2faf080", "gasUsed": "0x8e85", "to": "0x420000000000000000000000000000000000000f", "input": "0x519b4bd3", "output": "0x0000000000000000000000000000000000000000000000000000000000000030", "calls": [ { "from": "0x420000000000000000000000000000000000000f", "to": "0xc0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3000f", "input": "0x519b4bd3", "output": "0x0000000000000000000000000000000000000000000000000000000000000030", "type": "DELEGATECALL", "calls": [ { "from": "0x420000000000000000000000000000000000000f", "to": "0x4200000000000000000000000000000000000015", "input": "0x5cf24969", "output": "0x0000000000000000000000000000000000000000000000000000000000000030", "type": "STATICCALL" } ] } ], "value": "0x0", "type": "CALL" } } ``` ## WebSocket Support `op-reth` supports WebSocket connections for real-time event subscriptions using the `eth_subscribe` method. Default port is `8546`. ### eth\_subscribe Creates a subscription for specific events. Verified subscription topics include `newHeads`, `logs`, `newPendingTransactions`, and `syncing`. ```js theme={null} // Connect to WebSocket const ws = new WebSocket('ws://localhost:8546'); // Subscribe to new block headers ws.send(JSON.stringify({ "jsonrpc": "2.0", "method": "eth_subscribe", "params": ["newHeads"], "id": 1 })); // Subscribe to logs ws.send(JSON.stringify({ "jsonrpc": "2.0", "method": "eth_subscribe", "params": [ "logs", { "address": "0x8320fe7702b96808f7bbc0d4a888ed1468216cfd", "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] } ], "id": 2 })); ``` Subscription acknowledgement: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x8045a58dd94ddef0a9b0ac15ab397550" } ``` Event notification (newHeads): ```json theme={null} { "jsonrpc": "2.0", "method": "eth_subscription", "params": { "subscription": "0x8045a58dd94ddef0a9b0ac15ab397550", "result": { "hash": "0xabcc886e14fdb89b4df093032bf984e98a1704d8037a21260689d19e7bf72154", "number": "0x124b2", "timestamp": "0x69fdab30", "baseFeePerGas": "0xfb", "…": "…" } } } ``` ### eth\_unsubscribe Cancels an active subscription. ```js theme={null} ws.send(JSON.stringify({ "jsonrpc": "2.0", "method": "eth_unsubscribe", "params": ["0x8045a58dd94ddef0a9b0ac15ab397550"], "id": 1 })); ``` ## Methods that behave differently from op-geth These calls are worth flagging for tooling that auto-detects client capability: | Method | op-geth | op-reth | | ---------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `rpc_modules` | Returns the namespace → version map. | **Not implemented** — returns `-32601 Method not found`. Use `web3_clientVersion` to identify the client. | | `eth_syncing` | Returns `false` when synced. | Always returns a structured object with per-stage progress; compare `currentBlock` and `highestBlock` to determine "synced". | | `trace_*` (Parity) namespace | Not exposed; `op-geth` uses `debug_*`. | Available in `op-reth`, but only when `trace` is added to `--http.api`. Not enabled by default in our compose file. | | Receipt L1 fee scalars | Single legacy `l1FeeScalar` field on pre-Ecotone receipts. | V2 (Jovian) fields: `l1BaseFeeScalar`, `l1BlobBaseFee`, `l1BlobBaseFeeScalar`, `daFootprintGasScalar`; `l1FeeScalar` removed. (Same on `op-geth` once V2 is active.) | ## Additional Resources For a complete list of all supported JSON-RPC methods, refer to: * [Reth JSON-RPC / Namespaces Documentation](https://reth.rs/run/run-a-node.html#rpc-namespaces) * [Geth JSON-RPC Documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc) * [Ethereum JSON-RPC Specification](https://ethereum.org/en/developers/docs/apis/json-rpc/) * [OP Stack Transaction Cost Estimation](/app-developers/tutorials/transactions/sdk-estimate-costs) ## Running a Node with RPC Access To run your own `op-reth` node with full RPC access: ```sh theme={null} op-reth node \ --chain /config/genesis.json \ --datadir /data \ --http \ --http.addr 0.0.0.0 \ --http.port 8545 \ --http.api eth,net,web3,debug,txpool,trace \ --ws \ --ws.addr 0.0.0.0 \ --ws.port 8546 \ --ws.api eth,net,web3 \ --authrpc.addr 0.0.0.0 \ --authrpc.port 9551 \ --authrpc.jwtsecret /config/jwt.hex \ --rollup.sequencer-http https:// \ --rollup.disable-tx-pool-gossip ``` Be cautious when exposing RPC endpoints publicly. Use authentication, rate limiting, and firewall rules to prevent abuse. The `debug` and `trace` namespaces should only be enabled for trusted clients. ### Test environment The samples above were generated by running each curl/websocat command against an `op-reth v2.2.3` (`reth/v2.2.0-88505c7`) node in our `u19-beta-v223` devnet (chain ID `0x190a85e3` / `420120035`), HTTP port `8555`, WS port `8556`. All listed methods returned successful (or expected-error) responses. # op-supernode configuration options Source: https://docs.optimism.io/node-operators/reference/op-supernode-config Complete reference for all op-supernode command-line flags and environment variables. op-supernode is in active development. This page tracks the [op-supernode/v0.2.2-rc.8](https://github.com/ethereum-optimism/optimism/releases/tag/op-supernode%2Fv0.2.2-rc.8) release candidate and the flag list may evolve before the stable release. This page catalogues all configuration options for op-supernode, organized by functionality. The following options are from the `--help` in [op-supernode/v0.2.2-rc.8](https://github.com/ethereum-optimism/optimism/releases/tag/op-supernode%2Fv0.2.2-rc.8). For recommended settings, deployment topologies, and a starter configuration, see the [supernode configuration guide](/node-operators/guides/configuration/supernode). For what op-supernode is and why it exists, see the [supernode explainer](/op-stack/interop/supernode). Environment-variable names don't always derive mechanically from the CLI flag name. Some env-var suffixes keep op-node's source-level spelling even when the CLI flag was renamed (for example, `--vn..l2` is set by `OP_SUPERNODE_VN__L2_ENGINE_RPC`, not `OP_SUPERNODE_VN__L2`). The per-flag entries below show the correct env-var name alongside the CLI form. When in doubt, run `op-supernode --chains= --help` for the authoritative name of any flag. ## Dependency set and storage ### chains The list of chain IDs that this supernode hosts. Required. Accepts a comma-separated list or a repeatable flag. Each chain ID must have a matching set of per-chain `--vn..*` flags that configure the chain's network identity and execution-client connection. `--chains=` `--chains=11155420,1301` `OP_SUPERNODE_CHAINS=` ### data-dir Data directory for op-supernode. Each chain's SafeDB and P2P state is stored in a `chain-` subdirectory under this path so the chains cannot collide. The default value is `./datadir`. `--data-dir=` `--data-dir=/var/lib/op-supernode` `OP_SUPERNODE_DATA_DIR=` ## Shared L1 access The supernode shares one L1 client and one beacon client across every chain in the dependency set. These are the supernode's own in-process clients (caching layers in front of remote endpoints), not the remote L1 node and beacon node themselves — the supernode connects to existing endpoints rather than running its own. Configure these flags at the top level only — the per-chain namespace also includes `--vn..l1` and `--vn..l1.beacon` (because the supernode mechanically clones every op-node flag into the namespace), but the supernode discards them at startup. ### l1 Address of the L1 user JSON-RPC endpoint. Required. The `eth` namespace must be enabled on the endpoint. `--l1=` `--l1=https://ethereum-rpc-endpoint.example.com` `OP_SUPERNODE_L1_ETH_RPC=` ### l1.beacon Address of the L1 beacon-node HTTP endpoint. Required for any chain that depends on blob-derived L1 data, which covers every post-Ecotone OP Stack chain. `--l1.beacon=` `--l1.beacon=https://ethereum-beacon-endpoint.example.com` `OP_SUPERNODE_L1_BEACON=` ### l1.beacon-fallbacks Addresses of L1 beacon-API-compatible HTTP fallback endpoints. Used to fetch blob sidecars not available at the primary `--l1.beacon` endpoint, including blobs that have aged past a regular beacon node's prune window. The `--l1.beacon-archiver` alias points at the same flag. Accepts a comma-separated list or a repeatable flag. `--l1.beacon-fallbacks=` `--l1.beacon-fallbacks=https://archiver-1.example.com,https://archiver-2.example.com` `OP_SUPERNODE_L1_BEACON_FALLBACKS=` ### l1.http-poll-interval Polling interval for the shared L1 HTTP RPC subscription. The default value is `12s`. This flag controls the supernode's own L1 client. Per-chain `--vn..l1.http-poll-interval` settings are ignored because the shared client owns the resource. `--l1.http-poll-interval=` `--l1.http-poll-interval=12s` `OP_SUPERNODE_L1_HTTP_POLL_INTERVAL=` ## Per-chain virtual-node configuration Every chain in `--chains` runs as a virtual node inside the supernode. The supernode reproduces the full op-node flag set under two prefixes so you can configure each chain. * **`--vn..`** sets `` for one specific chain. * **`--vn.all.`** sets `` for every chain in the dependency set. The environment-variable form follows the same prefix rule: `OP_SUPERNODE_VN__` for one chain and `OP_SUPERNODE_VN_ALL_` for every chain. The `` is the op-node flag's source-level environment-variable name (see the note at the top of this page for why it doesn't always match the CLI flag). A few flags are owned by the supernode rather than by individual virtual nodes. Setting them under `--vn..*` or `--vn.all.*` has no effect. * `--l1` and `--l1.beacon`: the shared L1 plumbing replaces any per-chain L1 setting at startup. * `--l1.http-poll-interval`: the shared L1 client owns the polling cadence; the supernode logs a warning if a per-chain value is set. * `--log.*`: the supernode and every virtual node share one logger; top-level `--log.*` configures it. Per-chain `--vn.*.log.*` flags appear in the namespace but are silently ignored. (`--metrics.*` is different: top-level configures the supernode's own metrics service, but per-chain `--vn.*.metrics.*` configures each virtual node's own metrics, which are fanned into the same endpoint with per-chain Prometheus labels.) * P2P listen ports: see the [P2P](#p2p) section. The flags most operators need to set per chain are listed below. For the full set of op-node flags available under the `--vn.*` namespace, see the [op-node configuration reference](/node-operators/reference/op-node-config) and the [consensus client configuration page](/node-operators/guides/configuration/consensus-clients). ### vn.\.network Names the chain's known network configuration so the supernode can load the matching rollup config from op-node's built-in registry. Use this for any chain registered with op-node (`op-mainnet`, `op-sepolia`, `unichain-sepolia`, etc.). `--vn..network=` `--vn.11155420.network=op-sepolia` `OP_SUPERNODE_VN__NETWORK=` ### vn.\.rollup.config Path to a rollup configuration JSON file for chains that are not in op-node's built-in network registry. Use this instead of `--vn..network` for custom devnets or any chain you have a rollup config file for. `--vn..rollup.config=` `--vn.420120037.rollup.config=/etc/op/rollup-config.json` `OP_SUPERNODE_VN__ROLLUP_CONFIG=` ### vn.\.l2 Address of the engine-API endpoint for the chain's execution client. Each chain needs its own execution client; one execution client cannot back two chains. `--vn..l2=` `--vn.11155420.l2=http://op-sepolia-geth:8551` `OP_SUPERNODE_VN__L2_ENGINE_RPC=` ### vn.all.l2.jwt-secret Path to the JWT secret used to authenticate every virtual node's engine connection to its execution client. Set this at the `vn.all.*` level when every execution client in the dependency set shares one secret. Use the per-chain `--vn..l2.jwt-secret` form only when a chain's execution client requires its own secret. `--vn.all.l2.jwt-secret=` `--vn.all.l2.jwt-secret=/etc/op/jwt-secret.txt` `OP_SUPERNODE_VN_ALL_L2_ENGINE_AUTH=` ### vn.\.l2.enginekind Selects the engine-client variant so the supernode can apply engine-API behavior tailored to each. Set to `reth` when the chain's execution client is op-reth; leave at the default for op-geth. Supported values are `geth` and `reth`. The default value is `geth`. `--vn..l2.enginekind=` `--vn.11155420.l2.enginekind=reth` `OP_SUPERNODE_VN__L2_ENGINE_KIND=` ## P2P P2P is enabled at the supernode level for every chain, or disabled for every chain. Per-chain enable/disable is not supported. ### disable-p2p Disables P2P for every chain. The default value is `false`. Use this in topologies where unsafe-head P2P gossip is handled by other nodes in the fleet (for example, a Light CL fleet) and the supernode only needs to derive from L1. `--disable-p2p=` `--disable-p2p=true` `OP_SUPERNODE_DISABLE_P2P=` ### Per-chain listen ports When P2P is enabled, each virtual node's P2P listen port defaults to `0` (dynamic) to prevent port collisions across chains. Setting `--vn.all.p2p.listen.tcp` or `--vn.all.p2p.listen.udp` to a non-zero value is rejected because the same port cannot be reused across virtual nodes. To pin static ports per chain, set both the TCP (RLPx) and UDP (discovery v5) ports with the per-chain form: ```bash theme={null} --vn.11155420.p2p.listen.tcp=9222 \ --vn.11155420.p2p.listen.udp=9222 \ --vn.1301.p2p.listen.tcp=9223 \ --vn.1301.p2p.listen.udp=9223 ``` ## Interop verification The interop activity is the part of op-supernode that decides when a chain's blocks have satisfied their cross-chain dependencies. For background on how the activity decides between *wait*, *advance*, *invalidate*, and *rewind*, see the [supernode explainer](/op-stack/interop/supernode#cross-chain-message-safety). ### interop.activation-timestamp Overrides the interop activation timestamp derived from the loaded rollup configs. The default value is `0` (use the value from the rollup config). Set this only when activating interop on a custom devnet whose rollup config does not yet carry the activation timestamp. `--interop.activation-timestamp=` `--interop.activation-timestamp=1735689600` `OP_SUPERNODE_INTEROP_ACTIVATION_TIMESTAMP=` ### interop.log-backfill-depth Extends initiating-message log ingestion backward from the L2 tip by this duration, clamped to the interop activation timestamp. Validation still starts only beyond the local safe head; the backfill pre-ingests logs so they are available when validation needs them. Requires the interop activation timestamp to be known, either from the rollup config or via `--interop.activation-timestamp`. The default value is `0s` (no backfill). `--interop.log-backfill-depth=` `--interop.log-backfill-depth=168h` `OP_SUPERNODE_INTEROP_LOG_BACKFILL_DEPTH=` ## JSON-RPC server The supernode exposes a single JSON-RPC server that multiplexes activity methods and every chain's op-node RPC under one HTTP endpoint. Per-chain RPC namespaces are mounted under a `//` path prefix on the same server. For example, `POST /11155420/` reaches the OP Sepolia op-node RPC surface. Activity RPC methods (`superroot_atTimestamp`, `supernode_syncStatus`, `heartbeat_check`) are exposed at the root. For example, `POST /` with method `superroot_atTimestamp` reaches the SuperRoot activity. ### rpc.addr Address the JSON-RPC server binds to. The default value is `0.0.0.0`. `--rpc.addr=` `--rpc.addr=0.0.0.0` `OP_SUPERNODE_RPC_ADDR=` ### rpc.port Port the JSON-RPC server listens on. The default value is `8545`. `--rpc.port=` `--rpc.port=8545` `OP_SUPERNODE_RPC_PORT=` ### rpc.enable-admin Enables admin-namespace RPC methods. The default value is `false`. Enable this only on endpoints that are not exposed to untrusted networks. `--rpc.enable-admin=` `--rpc.enable-admin=true` `OP_SUPERNODE_RPC_ENABLE_ADMIN=` ## Logging Logging is configured at the top level. The supernode and every virtual node share one logger; per-chain `--vn.*.log.*` flags appear in the namespace but are silently ignored. ### log.level Minimum log severity to emit. Valid values are `trace`, `debug`, `info`, `warn`, `error`, `crit`. The default value is `info`. `--log.level=` `--log.level=info` `OP_SUPERNODE_LOG_LEVEL=` ### log.format Log output format. Valid values are `text`, `terminal`, `logfmt`, `logfmtms`, `json`, `jsonms` (the `*ms` variants append millisecond timestamps). The default value is `text`. Set `logfmt` or `json` when ingesting logs into a structured-log pipeline; the default `text` is for hand-reading. `--log.format=` `--log.format=json` `OP_SUPERNODE_LOG_FORMAT=` ### log.color Forces ANSI color codes in `text` log output regardless of whether the stream is a terminal. The default value is `false`. `--log.color=` `--log.color=true` `OP_SUPERNODE_LOG_COLOR=` ## Metrics and profiling Metrics and profiling endpoints are configured at the top level. The metrics server fans in counters from every chain container and exposes them on one endpoint with per-chain Prometheus labels. ### metrics.enabled Enables the Prometheus metrics server. The default value is `false`. `--metrics.enabled=` `--metrics.enabled=true` `OP_SUPERNODE_METRICS_ENABLED=` ### metrics.addr Address the metrics server binds to. The default value is `0.0.0.0`. `--metrics.addr=` `--metrics.addr=0.0.0.0` `OP_SUPERNODE_METRICS_ADDR=` ### metrics.port Port the metrics server listens on. The default value is `7300`. `--metrics.port=` `--metrics.port=7300` `OP_SUPERNODE_METRICS_PORT=` ### pprof.enabled Enables the pprof profiling endpoint. The default value is `false`. `--pprof.enabled=` `--pprof.enabled=true` `OP_SUPERNODE_PPROF_ENABLED=` ### pprof.addr Address the pprof server binds to. The default value is `0.0.0.0`. `--pprof.addr=` `--pprof.addr=0.0.0.0` `OP_SUPERNODE_PPROF_ADDR=` ### pprof.port Port the pprof server listens on. The default value is `6060`. `--pprof.port=` `--pprof.port=6060` `OP_SUPERNODE_PPROF_PORT=` ## Where to go next * Follow the [supernode configuration guide](/node-operators/guides/configuration/supernode) for recommended settings and a starter configuration. * Read the [supernode explainer](/op-stack/interop/supernode) for what op-supernode is and why it exists. * Read the [op-node configuration reference](/node-operators/reference/op-node-config) for the full set of flags available under the `--vn.*` namespace. * See the [op-supernode source](https://github.com/ethereum-optimism/optimism/tree/develop/op-supernode) in the monorepo for implementation detail. # Running a Node With Docker Source: https://docs.optimism.io/node-operators/tutorials/node-from-docker Run an OP Stack node (op-reth + op-node) using the official Docker images and docker-compose. **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. **Learn the OP Stack — stop 13 of 13.** You've learned the stack from concepts to cross-layer flows. In this capstone you run an OP Stack node on a live network with the official Docker images. When it syncs, you've finished the track: head back to [Learn the OP Stack](/op-stack/learn/index) for where to go next. This tutorial runs an OP Stack node using the **official op-reth and op-node Docker images** in a single `docker-compose.yml`. No source build required. To run the Rust consensus client instead of op-node, see the [kona-node Docker guide](/node-operators/kona-node/run/docker), which ships its own docker-compose recipe for a kona-node + op-reth stack. **OP Mainnet requires a one-time pre-Bedrock state import.** OP Sepolia does not. If you point this tutorial at OP Mainnet on a fresh datadir, op-reth will fail at startup with `Op-mainnet has been launched without importing the pre-Bedrock state`. Before running OP Mainnet, follow the [op-reth sync-op-mainnet guide](https://reth.rs/run/sync-op-mainnet.html) to either restore from a [pre-synced snapshot](https://datadirs.optimism.io/) or run the minimal-bootstrap import. OP Sepolia bootstraps via snap sync with no extra steps — start there if you're just testing the setup. ## Dependencies * [Docker](https://docs.docker.com/engine/install/) * [Docker Compose](https://docs.docker.com/compose/install/) (v2) * **An L1 execution RPC endpoint** (Ethereum mainnet for OP Mainnet, or Ethereum Sepolia for OP Sepolia). * **An L1 Beacon API endpoint** for the same L1 chain. Needed by op-node to fetch blob data post-Ecotone. ## Quick start ```bash theme={null} mkdir op-stack-node && cd op-stack-node ``` Both containers share a JWT secret over a bind mount: ```bash theme={null} openssl rand -hex 32 > jwt.txt ``` Configure your network and L1 endpoints. Pick **one** network block (Sepolia or Mainnet) and fill in your L1 RPC + Beacon URLs: ```bash theme={null} cat > .env <<'EOF' # --- Network: OP Sepolia (default) --- OP_RETH_CHAIN=optimism_sepolia OP_NODE_NETWORK=op-sepolia OP_RETH_SEQUENCER=https://sepolia-sequencer.optimism.io # --- Network: OP Mainnet (uncomment to use instead) --- # OP_RETH_CHAIN=optimism # OP_NODE_NETWORK=op-mainnet # OP_RETH_SEQUENCER=https://mainnet-sequencer.optimism.io # --- L1 endpoints (required) --- L1_RPC_URL=https://your-l1-rpc-endpoint L1_RPC_KIND=basic L1_BEACON_URL=https://your-l1-beacon-endpoint EOF ``` `L1_RPC_KIND` valid values: `alchemy`, `quicknode`, `infura`, `parity`, `nethermind`, `debug_geth`, `erigon`, `basic`, `any`. Use `basic` if unsure. `OP_RETH_CHAIN` and `OP_NODE_NETWORK` accept any [superchain-registry](https://github.com/ethereum-optimism/superchain-registry) chain (e.g. `unichain` / `unichain-mainnet`, `soneium` / `soneium-mainnet`). For each chain, point `L1_RPC_URL` / `L1_BEACON_URL` at the corresponding L1 (Ethereum Mainnet or Sepolia) and update `OP_RETH_SEQUENCER` to that chain's sequencer endpoint. ```yaml theme={null} services: op-reth: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-reth:v2.2.5 container_name: op-reth ports: - "8545:8545" # JSON-RPC HTTP - "8546:8546" # JSON-RPC WebSocket - "9001:9001" # Prometheus metrics - "30303:30303" # P2P TCP - "30303:30303/udp" # P2P UDP volumes: - ./reth-data:/data - ./jwt.txt:/jwt.txt:ro command: - node - --chain=${OP_RETH_CHAIN} - --datadir=/data - --http - --http.addr=0.0.0.0 - --http.port=8545 - --ws - --ws.addr=0.0.0.0 - --ws.port=8546 - --authrpc.addr=0.0.0.0 - --authrpc.port=8551 - --authrpc.jwtsecret=/jwt.txt - --rollup.sequencer=${OP_RETH_SEQUENCER} - --metrics=0.0.0.0:9001 restart: unless-stopped op-node: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-node:v1.18.2 container_name: op-node depends_on: - op-reth ports: - "9545:7000" # JSON-RPC HTTP (host 9545 → container 7000; macOS uses 7000 for AirPlay) - "7300:7300" # Prometheus metrics - "9222:9222" # P2P TCP - "9222:9222/udp" # P2P UDP volumes: - ./jwt.txt:/jwt.txt:ro command: - op-node - --l1=${L1_RPC_URL} - --l1.rpckind=${L1_RPC_KIND} - --l1.beacon=${L1_BEACON_URL} - --l2=ws://op-reth:8551 - --l2.jwt-secret=/jwt.txt - --network=${OP_NODE_NETWORK} - --syncmode=execution-layer - --l2.enginekind=reth - --rpc.addr=0.0.0.0 - --rpc.port=7000 - --metrics.enabled - --metrics.addr=0.0.0.0 - --metrics.port=7300 restart: unless-stopped ``` The op-reth datadir is bind-mounted from `./reth-data` on the host so you can inspect / restore from a snapshot directly (see [Bootstrap from a snapshot](#bootstrap-from-a-snapshot) below). Image tags shown are the latest as of writing. For the current tags, see the [op-reth releases](https://github.com/ethereum-optimism/optimism/releases?q=op-reth) and [op-node releases](https://github.com/ethereum-optimism/optimism/releases?q=op-node). ```bash theme={null} docker compose up -d ``` Follow logs with: ```bash theme={null} docker compose logs -f ``` ## Verification Check the node is alive and advancing: ```bash theme={null} curl -s -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ http://localhost:8545 ``` Expected: `{"jsonrpc":"2.0","id":1,"result":"0x..."}` with the current block in hex. Run again after a minute — the number should increase as sync progresses. For op-node sync status (unsafe, safe, and finalized heads in one call): ```bash theme={null} curl -s -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"optimism_syncStatus","params":[],"id":1}' \ http://localhost:9545 | jq . ``` During the initial EL-driven sync (`--syncmode=execution-layer`), `unsafe_l2` tracks the tip via libp2p gossip while `safe_l2` and `finalized_l2` stay at 0. This is expected — op-node defers L1 derivation until op-reth finishes its staged sync. Once the EL catches up, derivation begins and the safe/finalized heads start advancing. You can also tail op-node logs directly: ```bash theme={null} docker compose logs op-node | grep -E "Sync progress|Finished EL sync" ``` ## Bootstrap from a snapshot Syncing from scratch is fine for OP Sepolia (\~30–50 GB, hours) but slow for OP Mainnet (\~700 GB, days). For Mainnet — or anytime you'd rather skip the initial sync — bootstrap op-reth from a pre-synced snapshot. For OP Mainnet, a snapshot also handles the pre-Bedrock state requirement (see the warning at the top of this page) in one step. ```bash theme={null} docker compose down rm -rf reth-data # only if you previously synced and want to start clean ``` Browse [datadirs.optimism.io](https://datadirs.optimism.io/) for the snapshot matching your network and pick a recent file. Then download and verify the SHA256: ```bash theme={null} curl -fLO https://datadirs.optimism.io/.tar.zst # Verify checksum against the value on the index page sha256sum .tar.zst # Linux shasum -a 256 .tar.zst # macOS ``` The bind-mounted directory is `./reth-data` (relative to your `docker-compose.yml`): ```bash theme={null} mkdir -p reth-data tar -I zstd -xvf .tar.zst -C reth-data --strip-components=1 ``` `--strip-components=1` removes the top-level wrapping directory inside the tarball. Run `tar -tf .tar.zst | head -3` first to confirm — if files are already at the archive root, omit `--strip-components`. ```bash theme={null} docker compose up -d docker compose logs -f op-reth ``` op-reth will recognize the existing datadir on startup and pick up from the snapshot's tip — `latest_block` should be the snapshot's height, not 0. It will then catch up from that tip to current (minutes for Sepolia, hours for Mainnet, depending on snapshot age). ## Next steps * [Node Metrics and Monitoring Guide](/node-operators/guides/monitoring/metrics) — wire up Prometheus/Grafana against the metrics port. * [Node Troubleshooting Guide](/node-operators/guides/troubleshooting) — if you run into problems. * [Building and running an OP Stack node from source](/node-operators/tutorials/run-node-from-source) — if you need a custom build or want to inspect the source. # Running op-reth with Historical Proofs Source: https://docs.optimism.io/node-operators/tutorials/reth-historical-proofs Configure op-reth's proofs-history (v2) store to serve efficient historical eth_getProof responses for permissionless withdrawal proving. This tutorial layers the **proofs-history** historical proof store (storage format **v2**) on top of a working op-reth node. Follow [Building and running an OP Stack node from source](/node-operators/tutorials/run-node-from-source) first to build op-reth and op-node, then return here to enable proofs-history. **Do you need this tutorial?** Withdrawal proving on op-reth uses `eth_getProof` against historical L2 state, so both permissioned and permissionless chains need historical state exposed — but the required lookback differs sharply: * **Permissioned chains** only need a few hours of lookback (covering your dispute-game publishing cadence with margin). The lighter `--rpc.eth-proof-window ` flag is sufficient on its own — no separate proofs database is needed, and **this tutorial does not apply**. See the [op-reth configuration reference](/node-operators/op-reth/cli/op-reth/node) for that flag. * **Permissionless chains** need \~28 days of lookback. `--rpc.eth-proof-window` becomes too slow and memory-hungry at that range, so follow this tutorial to set up `--proofs-history` (v2). Use historical proofs storage format v2 by setting `--proofs-history.storage-version=v2` when running `op-reth node`. ## How it works reth's default `eth_getProof` reverts in-memory state diffs backward from the tip, which becomes prohibitive at multi-day lookbacks. The **proofs-history** subsystem maintains a separate MDBX database that tracks intermediate Merkle Patricia Trie nodes versioned by block, enabling O(1) lookups of proofs at any block within a configurable retention window. A background pruner removes data outside the window. The subsystem processes blocks asynchronously via reth's ExEx (Execution Extension) hook, so it adds zero overhead to sync speed and negligible tip latency. See the [historical proof configuration reference](/node-operators/reference/op-reth-historical-proof-config) for storage tables, RPC overrides, and tunable parameters. ## Prerequisites * A built `op-reth` binary at v2.2.3 or later (required for `--proofs-history.storage-version=v2`). See [Build op-node and the execution client](/node-operators/tutorials/run-node-from-source#build-op-node-and-the-execution-client). * An op-reth datadir, either initialized from genesis or restored from a [snapshot](https://datadirs.optimism.io/) (covered below). * Sufficient disk: estimate `chain_size + 20% buffer` for the proofs database (e.g., \~1 TB for 4 weeks on Base at 2s block time). * NVMe SSD recommended. ## Initialization Running `op-reth` with historical proofs requires a two-step initialization: ### 1. Initialize op-reth Initialize the core database with the genesis file for your chain (e.g., `optimism`). ```bash theme={null} ./target/release/op-reth init \ --datadir="/path/to/datadir" \ --chain="optimism" ``` #### Option: Start from a Snapshot If you prefer to start from a pre-synchronized database snapshot instead of syncing from genesis: 1. Download and extract an `op-reth` snapshot from [datadirs.optimism.io](https://datadirs.optimism.io/) into your `datadir`. 2. Skip the `op-reth init` command above. 3. Proceed to **Initialize Proofs Storage** below. The `proofs init` command initializes the proofs database at the snapshot's chain tip — it does not retroactively populate proofs for blocks already in the snapshot. ### 2. Initialize Proofs Storage Initialize the separate storage used by the historical proof store. This is **required** before starting the node with `--proofs-history`, even when reusing an existing op-reth datadir or restoring from a snapshot. ```bash theme={null} ./target/release/op-reth proofs init \ --datadir="/path/to/datadir" \ --chain="optimism" \ --proofs-history.storage-path="/path/to/proofs-db" \ --proofs-history.storage-version=v2 ``` The first time `proofs init` runs, it takes minutes to hours. Subsequent invocations should only take seconds. It does **not** backfill historical proofs — it marks the current chain tip as the starting point of the proofs database. Once the node is running with `--proofs-history`, the proofs database fills forward as new blocks are committed. To serve proofs across the full retention window (e.g., 30 days for permissionless fault proofs at default settings), the node must run continuously for at least that long after initialization. For that reason it is recommended to start from a snapshot whose tip is old enough to cover the required time window. ## Running op-reth with proofs-history Add the `--proofs-history.*` flags below to your standard op-reth start command from [Start the execution client](/node-operators/tutorials/run-node-from-source#start-the-execution-client). The proofs-history additions are: ```bash theme={null} ./target/release/op-reth node \ # ... your standard flags from Tutorial A ... --proofs-history \ --proofs-history.storage-path="/path/to/proofs-db" \ --proofs-history.storage-version=v2 ``` The default `--proofs-history.window` is **1,296,000 blocks**, corresponding to \~30 days at 2s block times. For chains with a different block time, set `--proofs-history.window=` explicitly using `target_retention_seconds / block_time_seconds`. For the full set of `--proofs-history.*` flags (window, prune-interval, metrics, etc.), see the [historical proof configuration reference](/node-operators/reference/op-reth-historical-proof-config). ## Running op-node Start `op-node` as documented in [Start op-node](/node-operators/tutorials/run-node-from-source#start-op-node). No proofs-history-specific changes are needed on the consensus client. ## Verification After starting both clients, query the sync status of the proofs store via the `debug_proofsSyncStatus` RPC method: ```bash theme={null} curl -s -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"debug_proofsSyncStatus","params":[],"id":1}' \ http://localhost:8545 ``` The response has the shape: ```json theme={null} {"jsonrpc":"2.0","id":1,"result":{"earliest":,"latest":}} ``` Immediately after `proofs init`, both `earliest` and `latest` sit at the chain tip; the window then fills forward as new blocks are committed. `eth_getProof` calls for every block within `[earliest, latest]` will be served from the versioned store. Requests for blocks older than `earliest` will fail or fall back to the default reth implementation. You can also check the op-reth startup logs for messages confirming the proofs-history ExEx is wired up: ```text theme={null} INFO reth::cli: Using on-disk storage for proofs history INFO reth::cli: Installing proofs-history RPC overrides (eth_getProof, debug_executePayload) INFO reth::cli eth_replaced=true debug_replaced=true: Proofs-history RPC overrides installed ``` ## Monitoring When op-reth is run with the `--metrics=:` flag, the proofs-history ExEx exposes Prometheus metrics covering proofs-DB sync state (`optimism_trie_block_*`), the background pruner (`optimism_trie_pruner_*`), and `eth_getProof` RPC traffic (`optimism_rpc_eth_api_ext_*`). See the [historical proof configuration reference](/node-operators/reference/op-reth-historical-proof-config#metrics) for the full list. ## Operational Commands ### Manual prune Pruning runs automatically in the background, driven by the engine task as new blocks are committed, and removes data outside the retention window. You should not need to invoke `op-reth proofs prune` under normal operation. A manual prune is only required in one situation: at startup, if the proofs database contains more than **1000 blocks** of history beyond the configured `--proofs-history.window`, the node refuses to start rather than stalling on a large prune operation. This typically happens after the node has been offline long enough that the configured window has shifted significantly, or after reducing `--proofs-history.window` to a smaller value than was previously in use. When this happens, op-reth exits with an error indicating the number of blocks to prune. Run the prune command once to bring the database back within the safety threshold, then restart the node: ```bash theme={null} op-reth proofs prune \ --datadir /path/to/reth-datadir \ --proofs-history.storage-path /path/to/proofs-db \ --proofs-history.storage-version v2 \ --proofs-history.window 1296000 ``` ### Unwind Recover from corruption by reverting the proofs database to a specific block: ```bash theme={null} op-reth proofs unwind \ --datadir /path/to/reth-datadir \ --proofs-history.storage-path /path/to/proofs-db \ --proofs-history.storage-version v2 \ --target ``` You can only unwind to a block after the earliest block number in the database. Unwinding to a block before the earliest will fail. ## Performance Benchmarked on Base Sepolia (\~700k block window, WETH contract): | Metric | Value | | ------------- | ------------------------------------- | | Avg latency | \~15 ms per `eth_getProof` | | Throughput | \~5,000 req/s (10 concurrent workers) | | Sync overhead | Zero (ExEx processes asynchronously) | | Memory | Bounded by window size — no OOM risk | ## Next steps * [op-reth v2.2.3 release notes](https://github.com/ethereum-optimism/optimism/releases/tag/op-reth%2Fv2.2.3) — the release that introduced the historical proof store v2. * [op-reth historical proof configuration reference](/node-operators/reference/op-reth-historical-proof-config) — full `--proofs-history.*` flag set, RPC endpoints, and Prometheus metrics. * [op-reth configuration reference](/node-operators/reference/op-reth-config) — all standard op-reth flags. # Building and running an OP Stack node from source Source: https://docs.optimism.io/node-operators/tutorials/run-node-from-source Build and run an OP Stack node (op-reth + op-node) from source code for full nodes and archive nodes. **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. This tutorial walks through the full process of building and running an OP Stack node from source — op-node plus an execution client. Building from source is a flexible alternative to using pre-built Docker images and is useful if you need a specific architecture or want to inspect what you're running. It builds and runs op-reth and Nethermind; op-geth instructions are retained in a legacy section at the bottom for operators mid-migration. For permissionless chains setting up historical proofs for withdrawal proving, follow this tutorial first to get a working node, then continue with [Running op-reth with Historical Proofs](/node-operators/tutorials/reth-historical-proofs). ## Hardware requirements Hardware requirements for OP Mainnet nodes can vary depending on the type of node you plan to run. Archive nodes generally require significantly more resources than full nodes. Below are suggested minimum hardware requirements for each type of node. * 16GB RAM * Reasonably modern CPU ### SSD capacity requirements Given the growing size of the blockchain state, choosing the right SSD size is important. Below are the storage needs as of June 2025: * **Full Node:** The snapshot size for a full node is approximately 700GB, with the data directory's capacity increasing by about 100GB every six months. * **Archive Node:** The snapshot size for an archive node is approximately 14TB, with the data directory's capacity increasing by about 3.5TB every six months. A local SSD with a NVME interface is recommended for archive nodes. Plan for future storage needs and choose SSDs that can handle these increasing requirements. ## Software dependencies The build environment is managed through [mise](https://mise.jdx.dev/), which installs and manages the toolchains (Rust, Go) needed to build the monorepo. The mise configuration lives in [`mise.toml`](https://github.com/ethereum-optimism/optimism/blob/develop/mise.toml) at the monorepo root. ## Build op-node and the execution client The Optimism Monorepo does **coordinated releases** — each release commit is tagged simultaneously across components (op-node, op-reth, kona-node, etc.). Pinning to one release tag gives you a known-good combination of all of them built from the same source state. Look up the latest tags on the [Optimism releases page](https://github.com/ethereum-optimism/optimism/releases). The monorepo contains the source for both `op-node` and `op-reth`. ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism.git cd optimism ``` Check out a recent op-node release tag — the same commit carries the matching op-reth tag. For example, `op-node/v1.18.2` is co-tagged with `op-reth/v2.2.4`: ```bash theme={null} git checkout op-node/v1.18.2 ``` `op-reth/v2.2.3` or later is required to enable the historical proof store v2 (`--proofs-history.storage-version=v2`). The op-node/v1.18.x release line carries op-reth ≥ v2.2.3, so any of those tags satisfies that requirement. ```bash theme={null} cd op-node && just && cd .. ``` Binary: `op-node/bin/op-node` (relative to the monorepo root). op-reth lives inside the monorepo at `rust/op-reth/` — no second `git clone` needed. ```bash theme={null} cd rust/op-reth && cargo build --release --bin op-reth && cd ../.. ``` Binary: `rust/target/release/op-reth` (relative to the monorepo root). `rust/` is a Cargo workspace, so the `target/` directory lives at the workspace root, not inside the individual crate. Build outputs are gitignored, so they persist across any future `git checkout`. `Nethermind` is an alternative execution client written in .NET. **Prerequisites:** [.NET SDK](https://aka.ms/dotnet/download) 9 or later. ```bash theme={null} git clone --recursive https://github.com/nethermindeth/nethermind.git dotnet build nethermind/src/Nethermind/Nethermind.sln -c release ``` Build artifacts: `nethermind/src/Nethermind/artifacts/bin/Nethermind.Runner/release/`. See the [Nethermind documentation](https://docs.nethermind.io/get-started/running-node/) for more. ## Assess blob archiver Assess if you need to configure a blob archiver service by reading [Configure a Blob Archiver](/node-operators/guides/management/blobs#configure-a-blob-archiver). ## Create a JWT secret The execution client and `op-node` communicate over the engine API authrpc, secured with a shared 32-byte hex secret. Both binaries must read the **same** secret file. The commands below use a relative path (`./jwt.txt`) for each binary, so the same content must exist at both launch directories. From the monorepo root: ```bash theme={null} openssl rand -hex 32 > jwt.txt ``` This creates `optimism/jwt.txt`. ```bash theme={null} cp jwt.txt op-node/jwt.txt ``` The op-reth binary lives at `rust/target/release/op-reth` and the tutorial launches it from `rust/`, so place the JWT there: ```bash theme={null} cp jwt.txt rust/jwt.txt ``` The two copies must remain identical — if you regenerate one side, copy it over to the other before restarting. ## Start the execution client It's generally easier to start the execution client before `op-node`. The EL will simply not receive any blocks until `op-node` is started. op-reth is built into the workspace target dir, so launch from `optimism/rust/`: ```bash theme={null} cd /path/to/optimism/rust ``` The binary is then at `./target/release/op-reth`. ```bash theme={null} export DATADIR_PATH=... # Path to the desired data directory for op-reth ``` For archive-node configuration (historical state for withdrawal proving), see the [OP Mainnet archive nodes](#op-mainnet-archive-nodes) section. The JSON-RPC API will become available on port 8545. See the [op-reth configuration reference](/node-operators/reference/op-reth-config) for the full flag set. ```bash theme={null} ./target/release/op-reth node \ --chain=optimism_sepolia \ --datadir=$DATADIR_PATH \ --http \ --ws \ --authrpc.jwtsecret=./jwt.txt \ --rollup.sequencer=https://sepolia-sequencer.optimism.io ``` For OP Mainnet, set `--chain=optimism` and `--rollup.sequencer=https://mainnet-sequencer.optimism.io`. Find the directory where you built the `Nethermind` binary. For an archive node, use the `op-sepolia_archive` configuration instead of `op-sepolia`. For OP Mainnet, use `op-mainnet` or `op-mainnet_archive` respectively. The JSON-RPC API will become available on port 8545. See the [execution clients configuration guide](/node-operators/guides/configuration/execution-clients) for more options. ```bash theme={null} ./Nethermind.Runner \ -c op-sepolia \ --data-dir path/to/data/dir \ --JsonRpc.JwtSecretFile=./jwt.txt ``` This uses the built-in `op-sepolia` configuration which includes JSON-RPC endpoints, network ports, sequencer URL, and other OP Stack-specific settings. ## Start op-node Once your execution client is running, start `op-node`. It will connect to the EL and begin synchronizing the chain. op-node is built into its own crate directory, so launch from `optimism/op-node/`: ```bash theme={null} cd /path/to/optimism/op-node ``` The binary is then at `./bin/op-node`. ```bash theme={null} export L1_RPC_URL=... # URL for the L1 node. Local default: http://127.0.0.1:8545 export L1_RPC_KIND=... # alchemy, quicknode, infura, parity, nethermind, debug_geth, erigon, basic, any export L1_BEACON_URL=... # URL for the L1 Beacon HTTP endpoint. Local default: http://127.0.0.1:3500 ``` The `op-node` RPC should not be exposed publicly. If left exposed, it could accidentally expose admin controls to the public internet. `--syncmode=execution-layer` enables [snap sync](/node-operators/reference/consensus-layer-sync), which works for both `op-reth` and `Nethermind` and removes the need to initialize the node with a data directory. `--l2.enginekind` tells op-node which kind of execution client it is driving. The binary defaults to `reth`, so this flag is shown for clarity and can be omitted when pairing with op-reth. ```bash theme={null} ./bin/op-node \ --l1=$L1_RPC_URL \ --l1.rpckind=$L1_RPC_KIND \ --l1.beacon=$L1_BEACON_URL \ --l2=ws://localhost:8551 \ --l2.jwt-secret=./jwt.txt \ --network=op-sepolia \ --syncmode=execution-layer \ --l2.enginekind=reth ``` Some L1 nodes (e.g. Erigon) do not support `eth_getProof`. Add `--l1.trustrpc` if your L1 doesn't support it — this means op-node trusts the L1 node to provide correct data. ## Synchronization verification Once the EL and op-node are running, you should see them begin to communicate and synchronize. ### Snap sync (default) Initial synchronization can take several hours. At the start of snap sync, `op-node` will log: ```text theme={null} INFO [03-06|10:56:55.602] Starting EL sync INFO [03-06|10:56:55.615] Sync progress reason="unsafe payload from sequencer while in EL sync" l2_finalized=000000..000000:0 l2_safe=000000..000000:0 l2_pending_safe=000000..000000:0 l2_unsafe=4284ab..7e7e84:117076319 l2_time=1,709,751,415 l1_derived=000000..000000:0 INFO [03-06|10:56:57.567] Optimistically inserting unsafe L2 execution payload to drive EL sync id=4ac160..df4d12:117076320 ``` `Starting EL sync` is shown once and the sync-progress / inserting logs repeat until done. `op-node` will log the following when finished: ```text theme={null} lvl=info msg="Finished EL sync" sync_duration=23h25m0.370558429s finalized_block=0x4f69e83ff1407f2e2882f2526ee8a154ac326590799889cede3af04a7742f18d:116817417 ``` The execution client logs its own header- and state-download progress in parallel: `op-reth` logs sync stages (headers, bodies, execution, state root) with periodic progress lines. Monitor the op-reth logs to confirm it is advancing through stages alongside the op-node `Sync progress` lines. Snap sync in `Nethermind` works by: 1. Downloading only the leaf nodes of the state tree 2. Generating intermediate nodes locally 3. Verifying the state root matches This approach is up to 10 times faster than traditional full sync. ### Full sync Full sync rebuilds the chain from genesis and can take days to weeks on mature networks. Most operators should use snap sync (above) or [bootstrap from a pre-synced snapshot](https://datadirs.optimism.io/). Full-sync configuration is client-specific: op-reth's snap sync is the recommended initialization path. For alternative sync configurations, see the [op-reth configuration reference](/node-operators/reference/op-reth-config). To use full sync with `Nethermind`, set: ```bash theme={null} ./Nethermind.Runner \ -c op-sepolia \ --Sync.SnapSync=false \ --Sync.FastSync=false \ --data-dir path/to/data/dir \ --JsonRpc.JwtSecretFile=./jwt.txt ``` Full sync will download and verify every block from genesis, which takes significantly longer than snap sync but provides the strongest security guarantees. After the initial sync, `op-node` derives L1 batches into L2 blocks and feeds them to the execution client. You'll see logs like: ```text theme={null} INFO [06-26|13:31:20.389] Advancing bq origin origin=17171d..1bc69b:8300332 originBehind=false INFO [06-26|14:00:59.460] Sync progress reason="processed safe block derived from L1" l2_safe=7fe3f6..900127:4068014 l2_unsafe=7fe3f6..900127:4068014 l1_derived=6079cd..be4231:8301091 INFO [06-26|14:00:59.461] generated attributes in payload queue txs=1 timestamp=1,673,564,098 INFO [06-26|14:00:59.463] inserted block hash=e80dc4..72a759 number=4,068,015 update_safe=true ``` The execution client logs its own block-import progress in parallel; refer to its documentation for log specifics. ## OP Mainnet archive nodes You only need an archive node if you need historical state. Most node operators should default to full nodes. For op-reth, historical state for withdrawal proving is configured via either `--rpc.eth-proof-window` (no separate proofs database; size to your dispute-game cadence) or `--proofs-history` (bounded memory, larger storage). See: * [Running op-reth with Historical Proofs](/node-operators/tutorials/reth-historical-proofs) — full setup for `--proofs-history` (v2) on op-reth v2.2.3+. * [Archive node guide](/node-operators/guides/management/archive-node) — flag overview for both paths. * [OP Mainnet snapshots](https://datadirs.optimism.io/) — pre-synced op-reth datadirs to bootstrap from. ### Legacy Geth (pre-Bedrock, optional) Blocks and transactions included in OP Mainnet before the Bedrock Upgrade cannot be executed by modern OP Mainnet nodes. Modern nodes serve these blocks but cannot run stateful queries like `eth_call` against them. For complete archive coverage of pre-Bedrock OP Mainnet state, run a Legacy Geth (`l2geth`) node alongside your modern node. This is **only** relevant to OP Mainnet archive nodes; skip if running a full node or OP Sepolia. ```bash theme={null} git clone https://github.com/ethereum-optimism/optimism-legacy.git cd optimism-legacy/l2geth make ``` Download the snapshot from [Legacy Geth Data Directory (2.9TB)](/node-operators/guides/management/snapshots#op-mainnet-legacy) and verify: ```bash theme={null} sha256sum mainnet-legacy-archival.tar.zst # Expected: 4adedb61125b81b55f9bdccc2e85092050c65ef2253c86e2b79569732b772829 ``` Then extract: ```bash theme={null} tar xvf mainnet-legacy-archival.tar.zst ``` ```bash theme={null} USING_OVM=true \ ETH1_SYNC_SERVICE_ENABLE=false \ RPC_API=eth,rollup,net,web3,debug \ RPC_ENABLE=true \ RPC_PORT=8546 \ ./build/bin/geth --datadir /path/to/l2geth-datadir ``` ## op-geth (legacy, end of support 2026-05-31) **op-geth has reached end-of-support (2026-05-31) and does not support the now-active Karst hardfork, so op-geth nodes can no longer follow the canonical chain.** Migrate to op-reth, the primary supported execution client. See the [op-geth deprecation notice](/notices/archive/op-geth-deprecation) for the full migration plan. Pair op-geth with op-node by setting `--l2.enginekind=geth` instead of `reth` in the op-node command above. ### Build op-geth ```bash theme={null} git clone https://github.com/ethereum-optimism/op-geth.git cd op-geth ``` Check the [op-geth releases page](https://github.com/ethereum-optimism/op-geth/releases) for the correct branch. ```bash theme={null} git checkout ``` ```bash theme={null} make geth ``` ### Start op-geth For an archive node, also set `--gcmode=archive`. ```bash theme={null} ./build/bin/geth \ --http \ --http.port=8545 \ --http.addr=localhost \ --authrpc.addr=localhost \ --authrpc.jwtsecret=./jwt.txt \ --verbosity=3 \ --rollup.sequencerhttp=https://sepolia-sequencer.optimism.io/ \ --op-network=op-sepolia \ --datadir=$DATADIR_PATH ``` The op-geth configuration reference has been retired; see the [op-reth configuration reference](/node-operators/reference/op-reth-config) for the equivalent op-reth flags. ### op-geth snap-sync stages op-geth's snap sync runs in two stages — header download then state download: ```text theme={null} lvl=info msg="Syncing beacon headers" downloaded=116775778 left=1162878 eta=53.182s ``` ```text theme={null} lvl=info msg="Syncing: state download in progress" synced=99.75% state="191.33 GiB" accounts=124,983,227@25.62GiB slots=806,829,266@165.16GiB codes=78965@566.74MiB eta=-2m7.602s ``` ```text theme={null} msg="Syncing: chain download in progress" synced=100.00% chain="176.01 GiB" headers=116,817,399@45.82GiB bodies=116,817,286@52.87GiB receipts=116,817,286@77.32GiB eta=77.430ms ``` Once synced, op-geth logs block imports as op-node feeds payloads: ```text theme={null} INFO [06-26|14:02:12.974] Imported new potential chain segment number=4,068,194 hash=a334a0..609a83 blocks=1 txs=1 INFO [06-26|14:02:12.976] Chain head was updated number=4,068,194 hash=a334a0..609a83 ``` ## Next steps * If your node is up and running, check the [Node Metrics and Monitoring Guide](/node-operators/guides/monitoring/metrics) to keep tabs on it. * If you run into problems, see the [Node Troubleshooting Guide](/node-operators/guides/troubleshooting). * For permissionless chains setting up withdrawal proving, continue with [Running op-reth with Historical Proofs](/node-operators/tutorials/reth-historical-proofs). # Notice archive Source: https://docs.optimism.io/notices/archive/index Completed network notices for OP Stack operators, newest first, with the date each change took effect. Every notice on this page is finished: the upgrade activated, the deprecation took effect, or the exercise completed. They are kept because live pages link into them and because they record what operators were asked to do at the time. Their URLs are permanent. For notices that still need action, see [Notices](/notices). For the permanent record of a network upgrade (activation timestamps, governing specification, and minimum component versions), see the [hardfork registry](/op-stack/protocol/network-upgrades); contract-only upgrades are in the registry's [contract upgrades table](/op-stack/protocol/network-upgrades#contract-upgrades). ## Archived notices The **Effective** column is the date the change took effect: mainnet hardfork activation, the end-of-support date, the mainnet execution date of a contract upgrade, or the start of a time-boxed experiment. A few notices never recorded one. Those rows say so and are placed at their nearest known point in the sequence rather than given a date they cannot support. | Effective | Notice | What it covered | | ---------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 2026-07-08 | [Upgrade 19: Karst hard fork](/notices/archive/upgrade-19) | Karst: the L2 Contract Manager (L2CM), `CANNON_KONA` promoted to the respected game type, a subset of Osaka EIPs on L2, and a preemptive BN256 pairing input-size reduction. | | 2026-06-26 | [Deprecation of Req/Res CL P2P sync](/notices/archive/req-resp-cl-sync-deprecation) | Retirement of the `op-node` request-response consensus-layer P2P sync client in favor of syncing through the execution client. Removed in `op-node/v1.19.1`. | | 2026-05-31 | [End of Support for op-geth and op-program](/notices/archive/op-geth-deprecation) | End of support for op-geth and op-program, neither of which supports Karst. Migrate execution to op-reth and fault proofs to kona-client. | | 2026-05-26 | [Stake-based priority ordering on OP Mainnet](/notices/archive/stake-based-priority-ordering) | A time-boxed OP Mainnet experiment giving stakers in the `PolicyEngineStaking` contract priority in transaction ordering, capped at four weeks. | | Not dated | [Deprecation of op-deployer upgrade and manage commands](/notices/archive/op-deployer-upgrade-deprecation) | `op-deployer manage` retired, and `op-deployer upgrade` capped at `op-contracts/v5.0.0`. L1 contract upgrades beyond that use superchain-ops or OPCM directly. Postdates `op-contracts/v6.0.0`. | | Not dated | [Upgrade 18: Cannon + Kona and Custom Gas Token v2](/notices/archive/upgrade-18) | Contract-only upgrade adding the `CANNON_KONA` (8) game type alongside `CANNON` (0), Custom Gas Token v2, and the creator-pattern dispute game refactor. Shipped in [`op-contracts/v6.0.0`](/releases/op-contracts) (released 2026-03-16). | | 2025-12-03 | [Fusaka upgrade notice](/notices/archive/fusaka-notice) | Readiness work so OP Stack chains keep deriving from an L1 that has activated Fusaka and its blob parameter-only forks. Not Fusaka adoption on L2. | | 2025-12-02 | [Upgrade 17: Jovian hard fork](/notices/archive/upgrade-17) | Jovian: a configurable minimum base fee, the data-availability footprint block limit, and Cannon support for Go 1.24. | | 2025-10-02 | [Upgrade 16a](/notices/archive/upgrade-16a) | Maintenance contract upgrade superseding Upgrade 16: removes the unused interop withdrawal-proving code and adds `SystemConfig` feature toggles. | | 2025-07-24 | [Upgrade 16: preparing for interop](/notices/archive/upgrade-16) | Contract upgrade making `OptimismPortal` interop-ready, meeting updated Stage 1 requirements, adding Go 1.23 support in Cannon, and raising `MAX_GAS_LIMIT` to 500M. Invalidated existing withdrawal proofs. | | 2025-05-14 | [Superchain withdrawal pause test](/notices/archive/superchain-withdrawal-pause-test) | A scheduled exercise of the Superchain-wide `pause` and `unpause` incident-response path. No user or operator action was required. | | 2025-05-09 | [Upgrade 15: Isthmus hard fork](/notices/archive/upgrade-15) | Isthmus: Prague features on the OP Stack, the L2 withdrawals root in the block header, and the operator fee. | | Not dated | [Upgrade 14: MT-Cannon and Isthmus L1 contracts](/notices/archive/upgrade-14) | Contract upgrade shipping multithreaded 64-bit Cannon (MT-Cannon) and the Isthmus L1 contracts. Shipped in [`op-contracts/v3.0.0`](/releases/op-contracts) (released 2025-05-08); the notice's own mainnet date was an estimate. | | Not dated | [L1 Pectra user fees and chain profitability](/notices/archive/pectra-fees) | How the [EIP-7623](https://eips.ethereum.org/EIPS/eip-7623) gas repricing at L1 Pectra affected chains still posting data as calldata rather than blobs, and which Ecotone scalars to check. | | 2025-04-02 | [Upgrade 13: OPCM and incident response](/notices/archive/upgrade-13) | Contract upgrade introducing the OP Contracts Manager (OPCM), fault-proof incident response improvements, and the `DeputyPauseModule`. | | 2025-03-20 | [Superchain testnets' blob fee bug](/notices/archive/blob-fee-bug) | A testnet-only blob base fee miscalculation that overcharged L1 fees, and the hardfork activation that fixed it. Mainnet chains were never affected. | | Not dated | [Preparing for Pectra breaking changes](/notices/archive/pectra-changes) | Breaking changes for chain and node operators when Pectra activated on L1. The page carries only tentative L1 slot times that were later superseded; it was last revised 2025-03-11. | | 2025-01-09 | [Preparing for Holocene breaking changes](/notices/archive/holocene-changes) | Holocene: stricter block derivation, EIP-1559 parameters made configurable through `SystemConfig`, and the MIPS contract upgrade. | # Network Notices Source: https://docs.optimism.io/notices/index Active upgrade notices, deprecations, and network change announcements for OP Stack operators. Notices are time-bound action items for application developers, node operators, and chain operators: upcoming network upgrades, deprecations, and operational changes. Each hardfork also has a permanent entry in the [hardfork registry](/op-stack/protocol/network-upgrades) recording its activation times, governing spec, and minimum component versions, and contract-only upgrades are listed in the registry's [contract upgrades table](/op-stack/protocol/network-upgrades#contract-upgrades) — notices are archived after activation, registry pages are forever. ## Network upgrades Prepare Fault Proof services for Super Root Dispute Games and other maintenance smart contract upgrades OP Sepolia and Unichain Sepolia interop activation preparation ## Operations Guidance for Supernode and Light CL node topology A 200 ms subblock interval and four zeroed stream payload fields on OP Sepolia and OP Mainnet # Prepare for interop on OP Sepolia and Unichain Sepolia Source: https://docs.optimism.io/notices/interop-prep Node operator action checklist for the OP Sepolia and Unichain Sepolia interop activation, targeted in July of 2026. OP Stack interop is expected to activate on **OP Sepolia** (chain ID `11155420`) and **Unichain Sepolia** (chain ID `1301`) in **July of 2026**, forming a two-chain interop dependency set on testnet. Node operators on either chain must change their topology before the activation timestamp: each operator runs one or more [op-supernode](/op-stack/interop/supernode) instances that derive both chains and validate the cross-chain messages between them, and the rest of the fleet runs as [Light CLs](/notices/specialized-node-topology) that follow the supernode. **A node that has not been migrated to the [supernode-plus-Light-CL topology](/notices/specialized-node-topology) by the activation timestamp cannot verify cross-chain dependencies.** Every op-node in the fleet must run with `--l2.follow.source` (env: `OP_NODE_L2_FOLLOW_SOURCE`) pointed at an op-supernode that derives both chains. Without that wiring — flag unset, or pointed at a non-supernode source — the op-node's safe head advances past the activation block without cross-chain validation, so the node cannot serve as a verifier or RPC source for the interop chain. The [Specialized op-node topology notice](/notices/specialized-node-topology) describes the pattern in detail. Start with that notice if your fleet hasn't moved off the homogeneous topology yet. The activation timestamps for OP Sepolia and Unichain Sepolia are planned for in **July of 2026** but have not yet been finalized. Final timestamps will be published in the [superchain-registry](https://github.com/ethereum-optimism/superchain-registry) once governance approves the rollup-config update. This page will be updated with the exact timestamps once they are pinned. Interop on mainnet OP Stack chains is planned as a follow-up rollout after this testnet activation; mainnet activation timestamps will be announced separately. ## What's changing At the activation timestamp, OP Sepolia and Unichain Sepolia form a two-chain dependency set. Every block on either chain can contain executing messages that reference initiating messages on the other; a block is only [safe](/op-stack/interop/explainer#block-safety-levels) once every initiating message it depends on has itself reached the same safety level. The work of tracking both chains and proving those dependencies moves to a new component, [op-supernode](/op-stack/interop/supernode), that runs every chain in the dependency set together as virtual nodes inside one process. The rest of the operator's fleet stops deriving locally and follows the supernode's safe view through op-node's [Light CL mode](/notices/specialized-node-topology). For how cross-chain messages and block safety work under interop, see the [interop explainer](/op-stack/interop/explainer). ## Who this affects This notice applies to anyone running OP Sepolia or Unichain Sepolia nodes after the activation timestamp. Every op-node in the fleet — replicas, RPC nodes, or any other op-node deployment — must run as a Light CL pointed at an op-supernode that derives both chains. Each operator stands up at least one op-supernode for the dependency set and reconfigures every op-node in their fleet to follow it. This rollout is scoped to OP Sepolia and Unichain Sepolia. Other OP Stack chains will activate the same Lagoon hardfork. With an empty dependency set there's nothing to cross-validate, so those operators can keep running plain op-node. Interop on OP Mainnet and Unichain follows in late July 2026, and other OP Stack chains move to the supernode topology only when they join an interop set. ## Required components Update or install the following components before the activation timestamp. Versions marked `TBD` will be pinned in this notice once the activation release candidates are finalized. | Component | Version | Role | | -------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `op-supernode` | `TBD` | Runs OP Sepolia and Unichain Sepolia as virtual nodes inside one binary and verifies cross-chain messages. Required component. See the [supernode explainer](/op-stack/interop/supernode) and [configuration guide](/node-operators/guides/configuration/supernode). | | `op-node` | `TBD` | Runs as a [Light CL](/notices/specialized-node-topology) on every node in the fleet; safe and finalized views are inherited from the supernode. | | `op-reth` | `TBD` | Execution client. Run one per chain in the dependency set — an execution client cannot back two chains (op-node rejects a mismatched chain ID at startup), so a host serving both chains runs at least two execution-client processes. | **op-reth is the required execution client.** op-geth end-of-support is **May 31, 2026** — see [End of Support for op-geth and op-program](/notices/archive/op-geth-deprecation). Interop activation lands after that date, so plan your fleet on op-reth. op-supernode does not yet have a stable release. Pull the latest candidate from the [op-supernode releases page](https://github.com/ethereum-optimism/optimism/releases?q=op-supernode). op-node and op-reth ship stable releases — track their respective release pages until this notice pins the exact activation versions. ## Action checklist The migration has four phases. Complete each one and verify it on testnet before the activation timestamp. Start the execution clients first, then the supernode — the supernode drives the ELs through their sync, because an EL has no way to know what chain head to target on its own. Light CLs come last, since they follow the supernode. Full per-flag reference for the supernode is in the [op-supernode configuration reference](/node-operators/reference/op-supernode-config); this notice walks through the testnet-specific setup. The command examples in the steps are minimum viable configurations; they cover the flags required for the interop topology and nothing else. Layer your usual production flags (monitoring, logging, P2P tuning, RPC modules, resource limits) on top as your environment requires. Run at least one op-reth process for OP Sepolia and at least one for Unichain Sepolia. Execution clients are not shared across chains. For each chain, plan one EL per consensus client connecting to it — one per supernode virtual node, plus one per Light CL in your fleet. Each execution client needs its own JWT secret file (a single shared file across both ELs is fine — see the note at the end of this step) and its own engine-API listen address. ELs can start unsynced; they wait until the supernode connects before they know what chain head to sync to. The supernode then drives each EL through its initial sync via the engine API, and tolerates the common case where one chain's EL is already synced and the other isn't. Configure each EL's history retention so the supernode can backfill initiating-message logs after restarts or downtime; the [EL retention recommendation](/node-operators/guides/configuration/supernode#configure-el-retention-for-supernode-backfill) in the supernode guide covers the retention window, the relevant op-reth pruning flags, and the extra requirements that apply if you also run op-challenger. ```bash theme={null} # OP Sepolia execution client op-reth node \ --chain=optimism-sepolia \ --datadir=/var/lib/op-reth-op-sepolia \ --authrpc.addr=127.0.0.1 \ --authrpc.port=8551 \ --authrpc.jwtsecret=/etc/op/jwt-secret.txt # Unichain Sepolia execution client op-reth node \ --chain=unichain-sepolia \ --datadir=/var/lib/op-reth-unichain-sepolia \ --authrpc.addr=127.0.0.1 \ --authrpc.port=8561 \ --authrpc.jwtsecret=/etc/op/jwt-secret.txt ``` The example binds the engine RPC to `127.0.0.1`. If op-reth runs in a Docker container, or on a different host from the supernode, set `--authrpc.addr=0.0.0.0` (or a specific interface IP reachable from the supernode) and restrict access at the network layer. Each EL in the fleet has exactly one consensus client connected to it. The supernode drives its ELs via per-chain virtual nodes; each Light CL also gets its own EL. The supernode can share one JWT secret path across all of its virtual nodes, with per-chain overrides if an EL needs its own secret; the [shared JWT secret recommendation](/node-operators/guides/configuration/supernode) in the supernode guide covers the flags. Each Light CL connects to its EL with its own `--l2.jwt-secret` flag. Run op-supernode with both chains in `--chains` (`11155420,1301`), a shared L1 RPC, and a shared beacon endpoint. The [example configuration](/node-operators/guides/configuration/supernode#example-configuration) in the supernode guide is written for exactly this dependency set (OP Sepolia plus Unichain Sepolia); use it as your starting point, and keep the engine kind set to `reth` for both chains since the fleet runs op-reth. Follow the guide's recommendation to configure a beacon archiver fallback from the start, so a supernode that has been offline for an extended period can still recover pruned blobs. For the full flag reference, see the [op-supernode configuration reference](/node-operators/reference/op-supernode-config); for recommendations, see the [supernode configuration guide](/node-operators/guides/configuration/supernode). On every op-node, set `--l2.follow.source` to your op-supernode's per-chain RPC endpoint (the `/` path prefix). This disables local derivation; the op-node becomes a Light CL and inherits its safe and finalized view from the supernode. ```bash theme={null} # OP Sepolia verifier / RPC op-node op-node \ --network=op-sepolia \ --l1= \ --l1.beacon= \ --l2=http://op-sepolia-reth:8551 \ --l2.jwt-secret=/etc/op/jwt-secret.txt \ --l2.follow.source=http://op-supernode:8545/11155420 \ --rpc.addr=0.0.0.0 \ --rpc.port=9545 # Unichain Sepolia verifier / RPC op-node op-node \ --network=unichain-sepolia \ --l1= \ --l1.beacon= \ --l2=http://unichain-sepolia-reth:8561 \ --l2.jwt-secret=/etc/op/jwt-secret.txt \ --l2.follow.source=http://op-supernode:8545/1301 \ --rpc.addr=0.0.0.0 \ --rpc.port=9546 ``` `--l1` and `--l1.beacon` are still required at startup even in Light CL mode — op-node rejects the configuration without them. The Light CL stops issuing L1 RPC calls for derivation work itself; it still keeps L1 references open for runtime config updates and engine-API book-keeping. Unsafe-head progression over P2P is unchanged. For background on the topology and why it scales, see the [specialized op-node topology notice](/notices/specialized-node-topology). For production fleets, run several supernodes as a highly available pool behind a consensus-aware proxyd and point the Light CLs at the pool rather than at a single supernode; a lone supernode is fine for evaluating the setup, but it is a single point of failure for safe-head progression on both chains. Put this in place before the activation timestamp: the [HA pool recommendation](/node-operators/guides/configuration/supernode#run-an-ha-pool-of-supernodes-behind-a-consensus-aware-proxyd) in the supernode guide covers the pool size, routing strategy, and failure behavior. ## Verify your setup before activation Run these checks against your topology before the activation timestamp. None of them require interop to be active on either chain; they exercise the supernode-plus-Light-CL plumbing on its own so the activation block does not surface configuration errors for the first time. ### Confirm the supernode is hosting both chains Watch the supernode's logs using whatever you already use (`docker logs -f op-supernode`, `journalctl -fu op-supernode`, `kubectl logs -f op-supernode`, etc.). Each chain container tags its log lines with its `chain_id`, so a healthy supernode produces interleaved derivation lines for both chains. The most common line during catch-up is `"Advancing bq origin"` (the batch-queue is walking forward through L1): ```text theme={null} t=2026-06-20T12:00:00+0000 lvl=info msg="Advancing bq origin" chain_id=11155420 vn_id=7754 origin=0x...:4071413 originBehind=false t=2026-06-20T12:00:00+0000 lvl=info msg="Advancing bq origin" chain_id=1301 vn_id=d5ca origin=0x...:6728414 originBehind=false ``` Both `chain_id=11155420` and `chain_id=1301` should appear regularly. If you only see one chain, the other's container failed to start or its execution client is unreachable — error-level lines tagged with the missing chain explain why. Once the supernode catches up and starts promoting heads, you will also see `msg="Sync progress"` lines with `l2_safe`, `l2_unsafe`, and `l2_finalized` fields tagged with the same `chain_id`. If you have Prometheus scraping the supernode, the gauge `op_node_supernode_refs_number{layer="l2",type="l2_safe"}` carries the per-chain safe head on the `virtual_node_chain_id` label — a single Grafana panel makes the per-chain progression continuously visible. ### Confirm a Light CL is following the supernode Watch a Light CL's logs the same way and look for `"Follow Source: Process external refs"` and `"Follow Upstream"` lines. A working Light CL produces these continuously while it polls the supernode's `optimism_syncStatus`: ```text theme={null} t=2026-06-20T12:00:00+0000 lvl=info msg="Safety levels" unsafe=enabled safe=http://op-supernode:8545/11155420 t=2026-06-20T12:00:00+0000 lvl=info msg="Follow Upstream" eSafe=0x...:12345678 eLocalSafe=0x...:12345678 eFinalized=0x...:12345670 eCurrentL1=0x...:4071600 t=2026-06-20T12:00:00+0000 lvl=info msg="Follow Source: Process external refs" externalSafe=0x...:12345678 externalLocalSafe=0x...:12345678 externalFinalized=0x...:12345670 ``` The first `"Safety levels"` line is the smoke test: if `safe=` shows your supernode URL and per-chain prefix, the wiring is right. Once the supernode is past initial sync and starts promoting safe heads, `eSafe` and `externalSafe` carry climbing block numbers. If the Light CL never advances past genesis (`eSafe=...:0`) for many minutes, `--l2.follow.source` is pointed at the wrong URL or namespace — recheck the per-chain prefix (`/11155420` for OP Sepolia, `/1301` for Unichain Sepolia). If you scrape Prometheus, the equivalent gauge on a Light CL is `op_node_default_refs_number{layer="l2",type="l2_safe"}` — one Grafana panel per Light CL plus one panel per supernode chain, side by side, makes any divergence obvious. ## Troubleshooting * **Safe head advances but RPC consumers report invalid blocks.** The op-node isn't following an op-supernode — either `--l2.follow.source` is unset, or it points at a non-supernode source — so safe-head promotion skips cross-chain validation. Point `--l2.follow.source` at a supernode that derives both chains. * **Blobs missing for L1 blocks older than \~18 days.** The primary beacon node has pruned them. Configure `--l1.beacon-fallbacks` against a non-pruning beacon or an archiver service. See the [blob archiver guide](/node-operators/guides/management/blobs#configure-a-blob-archiver) for options. * **Light CL safe head lags the supernode by more than a few blocks.** Check the network path between Light CL and supernode (or supernode `proxyd`). The Light CL polls `optimism_syncStatus` over RPC; a high-latency or rate-limited path here directly delays safe-head propagation. ## Resources * [Interop explainer](/op-stack/interop/explainer) — how cross-chain messages and block safety work under interop. * [op-supernode explainer](/op-stack/interop/supernode) — what op-supernode is, why it exists, and how it pairs with Light CL. * [Supernode configuration guide](/node-operators/guides/configuration/supernode) — recommended settings and starter configuration. * [op-supernode configuration reference](/node-operators/reference/op-supernode-config) — full flag and environment-variable catalogue. * [Specialized op-node topology notice](/notices/specialized-node-topology) — operator-facing pattern for running Light CL fleets behind a safe source. * [Interop reorg awareness](/op-stack/interop/reorg) — how the safety model handles equivocation and L1 reorgs. * [Cross-chain security measures](/op-stack/security/interop-security) — how the safety level for inbound cross-chain messages is configured at the chain level. * [Running op-reth with Historical Proofs](/node-operators/tutorials/reth-historical-proofs) — only relevant if you also run op-challenger; configures the supernode's ELs to serve historical proofs. # Specialized op-node topology with light nodes Source: https://docs.optimism.io/notices/specialized-node-topology OP Labs highly recommends migrating from homogeneous op-node fleets to a specialized topology where only designated source nodes derive from L1 and the rest run as light nodes via --l2.follow.source. Historically, every `op-node` in a fleet has independently derived the [safe chain](https://docs.optimism.io/op-stack/reference/glossary#safe-l2-block) from L1 while also consolidating [unsafe blocks](https://docs.optimism.io/op-stack/reference/glossary#unsafe-l2-block) received over gossip. As fleets grow and upcoming features like interop raise the cost of derivation, we **highly recommend** migrating to a **specialized topology** in which a small number of `op-node` instances are dedicated to L1 derivation and the rest defer to those sources. In the specialized topology, **light nodes** are started with `--l2.follow.source` pointing at a derivation source. The source is an `op-node` for chains without interop activation, or an [`op-supernode`](/op-stack/interop/supernode) for chains in an interop dependency set (one supernode derives every chain in the set together and adds cross-chain message verification). Light nodes disable their own independent derivation and instead receive the safe chain from the source, while continuing to track the unsafe tip via gossip and the engine API. **Required for upcoming interop activation.** This topology is required for node operators on **OP Sepolia** and **Unichain Sepolia** once interop activates on those chains in late June 2026 — see [Prepare for interop on OP Sepolia and Unichain Sepolia](/notices/interop-prep) for the action checklist. The corresponding mainnet activation will carry the same requirement. ## What this means * **Source nodes** derive the full chain from L1. For chains without interop, this is a traditional `op-node`. For chains in an interop dependency set, it is an `op-supernode`, which derives every chain in the set together and verifies cross-chain messages. * **Light nodes** are `op-node` instances started with `--l2.follow.source=`. They stop deriving from L1 themselves and receive the safe chain from the designated source — an op-node RPC for non-interop chains, an op-supernode RPC (with the chain's `/` path prefix) for interop chains. * `op-node` is **not** being deprecated, and the homogeneous topology is **not** being removed. For chains where interop has not activated, this is a recommended operational upgrade rather than a required migration. For OP Sepolia and Unichain Sepolia, it becomes required at interop activation (see the Warning above). * Only the derivation role changes. Light nodes continue to serve RPC, participate in gossip, and drive their connected execution client as before. ## Why this matters ### L1 utilization reduction Only the source nodes ingest L1 data for derivation. Light nodes no longer issue L1 RPC calls for the derivation pipeline, which meaningfully reduces L1 API load and provider costs for operators running many nodes. ### Performance specialization Light nodes shed the L1 derivation workload and can focus on advancing the unsafe chain and serving RPC, while source nodes focus exclusively on derivation. ### Asymmetric scaling RPC-serving capacity and derivation capacity can now be scaled independently. Operators can add or remove light nodes to match read traffic without changing L1 load, and can size the source tier separately based on derivation requirements and redundancy targets. ### Lower cost for future rollouts Future upgrades — including interop — will require more sophisticated derivation logic. Centralizing derivation behind a small, well-defined source tier minimizes the operational surface area affected by those upgrades and reduces the per-node cost of adopting them. ## How to migrate ### Node operators Plan a migration from a homogeneous fleet of derivation-enabled `op-node` instances to a specialized topology: 1. Stand up the **source tier**. For chains without interop, designate one or more `op-node` instances as sources, configured with full L1 derivation. For chains in an interop dependency set, the source tier is one or more `op-supernode` instances covering every chain in the set. Either way, size and monitor the source tier with redundancy for failover. 2. Provision the remaining `op-node` instances as **light nodes** by setting `--l2.follow.source=` (env: `OP_NODE_L2_FOLLOW_SOURCE`). Ensure light nodes can reach the source endpoint over a reliable, low-latency network path. 3. Validate that light nodes track the safe chain correctly against the source before shifting production traffic. 4. Update dashboards and alerting so the source tier's health is treated as a dependency of the light-node tier. #### Highly available topology with consensus-aware proxyd For production deployments, we recommend placing the derivation tier behind a [consensus-aware `proxyd`](/chain-operators/tools/proxyd#consensus-awareness) and exposing light nodes to users through a separate RPC-serving tier: Specialized op-node topology: three source op-nodes with EL (Reth) feed a consensus-aware proxyd via CL API, which fans out to two light op-nodes via --l2.follow.source * **Deriver tier** — a small, redundant set of source instances (`op-node` for non-interop chains, `op-supernode` for interop chains). These sit behind a `proxyd` configured with routing strategy: `consensus_aware_consensus_layer`, which aggregates the multiple sources into a single highly available endpoint and hides individual failures or reorgs from downstream consumers. * **Light-node tier** — a horizontally scalable pool of light `op-node` instances started with `--l2.follow.source` pointed at the deriver-tier `proxyd` endpoint. This tier can be scaled up and down independently based on read traffic. * **Edge tier** — an API gateway or user-facing `proxyd` that fronts the light-node tier and handles external RPC traffic, rate limiting, and routing. In all cases, consider your existing topology and apply node specialization in a way that works best with your deployment stack. The goal is to have a minimal, well defined source tier (op-node or op-supernode, per chain) and a scalable collection of light nodes pointed at it. ### Chain operators All guidance for Node Operators is applicable to Chain Operators. For `op-node` instances serving as Sequencers, we suggest those nodes use `--l2.follow.source` to offload the work of derivation. Benchmarking indicates removing derivation eliminates some bottlenecks when producing blocks, and the role of the Sequencer is to maintain and extend the Unsafe Chain. On chains where interop has not activated, the specialized topology is a recommendation, not a hard requirement. Existing homogeneous deployments on those chains continue to work, and migration can be done incrementally, one light node at a time. `op-node` is not sufficient as a derivation source for chains in an interop dependency set — those chains use [`op-supernode`](/op-stack/interop/supernode), which derives every chain in the set together and verifies cross-chain messages. Future protocol features may impose similar requirements on other chains. Operators who keep running large fleets of derivation-enabled `op-node` instances on chains where the source role is changing should expect a higher operational burden: more L1 API cost today, and a per-node cost to upgrade every derivation-enabled instance as new derivation requirements land. Specializing the topology now minimizes the number of nodes affected by those changes. ## Resources * [Interop prep notice](/notices/interop-prep) — node-operator action checklist for the OP Sepolia and Unichain Sepolia interop activation, where this topology is required rather than recommended. * `--l2.follow.source` flag (env: `OP_NODE_L2_FOLLOW_SOURCE`) — configures an `op-node` as a light node pointed at a source `op-node` RPC endpoint. * `--l2.follow.source.rpc-timeout` flag (env: `OP_NODE_L2_FOLLOW_SOURCE_RPC_TIMEOUT`) — tunes the RPC call timeout used when talking to the source (default `10s`). # Subblocks: 200 ms interval and stream payload changes Source: https://docs.optimism.io/notices/subblocks Subblocks (formerly Flashblocks) move to a 200 ms interval on OP Sepolia and OP Mainnet, and zero four fields in the stream payload. Subblocks (formerly Flashblocks) stream pre-confirmations on OP Stack chains. Two changes are rolling out to OP Sepolia and OP Mainnet: the subblock interval drops from 250 ms to 200 ms, and four fields in the stream payload are set to their zero value. The stream keeps its existing wire format, and the payload type is still named `ExecutionPayloadFlashblockDeltaV1`. The subblock stream sets `state_root`, `block_hash`, `withdrawals_root`, and `withdrawals` to their zero value. The stream remains wire compatible, so reads return a zero value rather than raising an error. Audit stream integrations before **August 17, 2026**. ## What this means * **The interval drops from 250 ms to 200 ms.** This brings OP Sepolia and OP Mainnet to `FLASHBLOCKS_TIME = 200ms`, the default in the [Flashblocks specification](https://specs.optimism.io/protocol/flashblocks.html). * **Four payload fields are set to their zero value.** All four remain present in `ExecutionPayloadFlashblockDeltaV1`. Nothing is removed from the wire format. * **Every other field, including `receipts_root` and `logs_bloom`, continues to carry a real value.** | Field | Zero value on the stream | | ------------------ | ------------------------ | | `state_root` | `0x0000...0000` | | `block_hash` | `0x0000...0000` | | `withdrawals_root` | `0x0000...0000` | | `withdrawals` | `[]` | An integration that reads any of these fields receives a zero value and continues, rather than failing loudly at the parse boundary. We recommend you audit your application or integration for these reads directly ahead of the migration. ## The rollout is gradual This is a rolling change rather than a single switch, so you may see both the previous and the new behavior for a period. ## Action required For teams consuming the subblock stream directly: * Audit integrations for reads of `state_root`, `block_hash`, `withdrawals_root`, and `withdrawals`. * Confirm that a zero value in any of them cannot propagate into downstream state, balances, or proofs. * RPC providers that forward stream payloads to their own consumers should pass this notice on to those consumers. ## Timeline | Network | Target rollout | | ---------- | --------------- | | OP Sepolia | August 17, 2026 | | OP Mainnet | August 31, 2026 | Both dates are targets and may move. ## Key links | Resource | Link | | ------------------------- | -------------------------------------------------------------------------------------------- | | Flashblocks specification | [specs.optimism.io](https://specs.optimism.io/protocol/flashblocks.html) | | Subblocks explainer | [How Subblocks work](/op-stack/features/subblocks) | | App integration guide | [Integrate Subblocks in your app](/app-developers/guides/transactions/integrating-subblocks) | # Upgrade 20 Source: https://docs.optimism.io/notices/upgrade-20 Prepare Fault Proof services and contract integrations for the Upgrade 20 move to Super Root Dispute Games. Upgrade 20 is an L1 smart contract upgrade for OP Stack chains. It moves Fault Proofs from Output Root Dispute Games to Super Root Dispute Games and includes `SystemConfig` and OP Contracts Manager (OPCM) maintenance changes. ## Why Upgrade 20 Output Root Dispute Games commit to one chain's state at an L2 block number. Interop requires a dispute game format that can commit to the state of multiple chains at the same timestamp. Super Root Dispute Games provide that format. Upgrade 20 moves each chain to Super Root Dispute Games before shared cross-chain dispute infrastructure is enabled. Each game created after this upgrade still contains one chain's Output Root. The upgrade does not enable Interop, call `OPCM.migrate()`, or move a chain to a shared Dispute Game setup. Super Root Dispute Games use a timestamp as the `l2SequenceNumber` and validate an incorrect proposal timestamp through the Fault Proof state transition. This removes the separate L2 block number challenge used by Output Root Dispute Games. The `OptimismPortal` continues to support both formats, so games and withdrawal proofs created before the upgrade remain valid. ## What's included ### Super Root Dispute Games Upgrade 20 adds the following Super Root Dispute Game types: * `SUPER_PERMISSIONED` (game type `5`) for chains that use permissioned Fault Proofs. * `SUPER_CANNON_KONA` (game type `9`) for chains that use permissionless Fault Proofs. A permissioned chain remains permissioned. A permissionless chain runs both Super Root Dispute Game types and uses `SUPER_CANNON_KONA` as its respected game type. Existing Dispute Games continue to resolve through their original game types. The upgrade keeps each chain's existing `AnchorStateRegistry` and `DisputeGameFactory`. It uses an `OPCM.upgrade()` transaction rather than migrating the chain to a shared Dispute Game setup. ### SystemConfig Interface Cleanup Upgrade 19 recomputed the onchain `SystemConfig` batch inbox address for chains deployed before OPCM. The change did not affect derivation because OP Stack clients read the batch inbox address from the chain's rollup configuration, but it left the redundant onchain value out of sync. Upgrade 20 removes `batchInbox()` and clears its legacy storage slot. It also removes the deprecated `setGasConfig(uint256,uint256)` function, which could leave `scalar()` out of sync with the fee scalar values that OPCM preserves during an upgrade. The updated `SystemConfig` has contract version `4.0.0`. The deprecated `overhead()` getter remains available for compatibility with existing integrations, but the upgrade sets the stored value to zero. Because `setGasConfig(uint256,uint256)` was its only writer, the value stays zero after the upgrade. To preserve the two-word `FEE_SCALARS` event payload without requiring a hardfork, calls to `setGasConfigEcotone(uint32,uint32)` encode zero in the first word. ## Breaking Changes ### Chain Operators Chain operators must coordinate the L1 contract cutover with the services that propose, challenge, and monitor Fault Proofs. * Switch `op-proposer` to the new Super Root RPC and game type at the contract cutover. * Configure `op-challenger` and `op-dispute-mon` to support Super Root Dispute Games while retaining the configuration needed to finish games already in progress. * For permissionless Fault Proofs, stage the reviewed `kona-client` Interop variant prestate before the cutover. * Update operational tooling that calls the removed `SystemConfig` functions. The [OP Stack component changes](#prepare-op-stack-components), [`SystemConfig` integration changes](#update-systemconfig-integrations), and [prestate workflow](#locate-or-build-the-absolute-prestate) are described below. ### Node Operators Upgrade 20 has no L2 hardfork, and it does not require an `op-node` or `op-reth` configuration change. If the node also provides a Super Root RPC to Fault Proof services, keep that endpoint reachable during and after the cutover. ### App Developers and Infrastructure Integrators Ordinary L2 contracts and transactions are not affected. Update an integration if it does any of the following: * Calls `SystemConfig.batchInbox()` or `SystemConfig.setGasConfig(uint256,uint256)`. * Decodes the first word of a `FEE_SCALARS` `ConfigUpdate` event as the current `overhead()` value. * Reads `SystemConfig.overhead()` and expects the legacy value to remain unchanged. * Reads Dispute Game root claims directly and assumes the claim is an Output Root. * Uses an OP Stack SDK to check, prove, or finalize L2-to-L1 withdrawals. For Super Root Dispute Games, direct Dispute Game integrations must recognize game types `5` and `9` and use `rootClaimByChainId(uint256)` to obtain the chain's Output Root. The `overhead()` getter remains available for compatibility but is deprecated, and it returns zero after Upgrade 20. Applications that use `viem/op-stack` for withdrawal proving must upgrade to `viem` `2.51.0` or later and follow the [withdrawal tooling changes](#update-withdrawal-tooling). Bridge operators and developers of withdrawal tooling that read Dispute Game contracts directly must follow the same guidance. Tooling that delegates the withdrawal flow to an SDK must use a version that supports Super Root Dispute Games. ### Users No action is required. Withdrawal proofs submitted before Upgrade 20 remain valid. Users do not need to re-prove them. Existing Output Root Dispute Games continue to resolve, and the `OptimismPortal` supports withdrawal proofs from both Output Root and Super Root Dispute Games. ## Prepare OP Stack components Use the following configuration changes when staging the Upgrade 20 component releases: | Component | Required change | | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `op-challenger` | Add `--superroot-rpc` (`OP_CHALLENGER_SUPERROOT_RPC`) and keep the existing game types so the challenger can finish games already in progress. On a permissionless chain, append `super-cannon-kona` to `--game-types` (`OP_CHALLENGER_GAME_TYPES`) and configure the reviewed Kona Interop prestate. On a permissioned chain, do not add `super-permissioned`; the simplified game does not require a trace type, and `op-challenger` handles its lifecycle automatically. | | `op-dispute-mon` | Add `--superroot-rpc` (`OP_DISPUTE_MON_SUPERROOT_RPC`). Keep `--rollup-rpc` while Output Root Dispute Games remain in progress. | | `op-proposer` | Switch at the contract upgrade cutover. Replace `--rollup-rpc` with `--superroot-rpcs` (`OP_PROPOSER_SUPERROOT_RPCS`) and set `OP_PROPOSER_GAME_TYPE=5` for a permissioned chain or `OP_PROPOSER_GAME_TYPE=9` for a permissionless chain. | | `op-node`, `op-reth`, and `op-batcher` | No configuration change is required. Upgrade 20 has no hardfork activation. | The Super Root RPC must return a root for the chain or dependency set that the Dispute Game covers. For a single-chain upgrade, use the chain's `op-node` RPC endpoint or the chain-specific endpoint exposed by an `op-supernode`. ## Update `SystemConfig` integrations Calls to `SystemConfig.batchInbox()` and `SystemConfig.setGasConfig(uint256,uint256)` revert after Upgrade 20. If your tooling reads or writes `SystemConfig` directly: * Read the batch inbox address from the chain's rollup configuration or its entry in the [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry). * Replace `setGasConfig(uint256,uint256)` calls with [`setGasConfigEcotone(uint32,uint32)`](/chain-operators/reference/fee-parameters) for the base fee and blob base fee scalars. * If you decode `FEE_SCALARS` `ConfigUpdate` events, treat the first word as zero rather than the current value returned by `overhead()`. * If you read `overhead()`, expect zero. The upgrade clears any legacy value. ## Update withdrawal tooling Super Root Dispute Games anchor withdrawals by L2 timestamp instead of L2 block number, and their root claim contains a Super Root instead of the chain's Output Root. Application tooling that discovers a Dispute Game or builds a withdrawal proof must support both changes. | Tooling | Required change | | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`viem/op-stack`](https://viem.sh/op-stack) | Use `viem` `2.51.0` or later. For prove-readiness calls, pass the initiating withdrawal block timestamp as `l2Timestamp`. Pass the `game` returned by `waitToProve` to `buildProveWithdrawal`; do not pass the legacy `output` value. | | `ethers`, wagmi, and other general EVM libraries | No library update is required for ordinary contract reads, writes, or L2 transactions. Update only custom withdrawal or Dispute Game code that makes the Output Root assumptions described above. | After the Upgrade 20 cutover, a `viem` withdrawal prove flow must read the timestamp of the L2 block that contains the initiating transaction: ```js theme={null} const receipt = await publicClientL2.getTransactionReceipt({ hash: withdrawalHash }); const withdrawalBlock = await publicClientL2.getBlock({ blockNumber: receipt.blockNumber }); const { game, withdrawal } = await publicClientL1.waitToProve({ receipt, l2Timestamp: withdrawalBlock.timestamp, targetChain: publicClientL2.chain }); const proveArgs = await publicClientL2.buildProveWithdrawal({ game, withdrawal }); ``` Pass the same `l2Timestamp` when calling `getTimeToProve` or `getWithdrawalStatus` for a Super Root withdrawal. `waitToFinalize` and the finalization transaction do not require the timestamp. See the [`viem` Super Root withdrawal support release](https://github.com/wevm/viem/releases/tag/viem%402.51.0) for the upstream compatibility change. ## Locate or build the absolute prestate Permissionless chains need the Upgrade 20 `kona-client` Interop variant absolute prestate for `SUPER_CANNON_KONA`. Use the `kona-client-int` artifact even when Interop is not scheduled for the chain. Use the `cannon64-kona-interop` hash published for the Upgrade 20 release in [`standard-prestates.toml`](https://github.com/ethereum-optimism/superchain-registry/blob/main/validation/standard/standard-prestates.toml). Check out the Kona release tag associated with the published Upgrade 20 prestate hash, reproduce both Kona prestates, and read the interop hash: ```bash theme={null} just reproducible-prestate-kona jq -r .pre rust/kona/prestate-artifacts-cannon-interop/prestate-proof.json ``` Confirm the output matches the published hash. Host the generated hash-named `.bin.gz` file on the prestate server used by `op-challenger`. First, stage the chain data described in [Generating a custom kona-client absolute prestate](/chain-operators/tutorials/kona-custom-prestate). Check out the Kona release tag associated with the reviewed Upgrade 20 prestate and build the interop variant with the same custom configuration: ```bash theme={null} cd rust KONA_CUSTOM_CONFIGS_DIR=/absolute/path/to/custom-configs \ just build-kona-reproducible-prestate-variant \ kona-client-int prestate-artifacts-cannon-interop jq -r .pre kona/prestate-artifacts-cannon-interop/prestate-proof.json ``` Rebuild from a clean checkout with the same inputs and confirm the hash is identical. Host the generated hash-named `.bin.gz` file at a URL reachable by every challenger that participates on the chain. A custom prestate hash is specific to its embedded chain configuration and does not appear in `standard-prestates.toml`. ## Upgrade timing Upgrade 20 is applied as an L1 contract upgrade and has no L2 hardfork activation timestamp. Pending governance approval, we expect the upgrade to be executed in September. The [Output Root to Super Root upgrade runbook](/chain-operators/tutorials/upgrade-chain-to-super-roots) describes the onchain upgrade and cutover checks. ## Verify readiness Before the cutover: * Confirm `op-proposer`, `op-challenger`, and `op-dispute-mon` start with the staged Super Root configuration and can reach the configured Super Root RPC. * On a permissionless chain, reproduce the `kona-client` Interop variant prestate and confirm its hash matches the reviewed Upgrade 20 value. * Run integration tests that cover every direct `SystemConfig` call and every withdrawal or Dispute Game code path listed in this notice. If you have questions or need support, contact your Optimism point of contact. # OP Mainnet Source: https://docs.optimism.io/op-mainnet/index Routes builders deploying on OP Mainnet to the network information, contract addresses, finality reference, and chain history they need. You are building on OP Mainnet. If you are early in your journey, you do not need to run your own chain: deploy your app directly on OP Mainnet and use this section as your reference for the network itself. Go from zero to a working app on OP Mainnet with the app developer quickstart. Get RPC endpoints, chain IDs, currency symbols, and block explorers for OP Mainnet and OP Sepolia. Find the L1 and L2 contract addresses for OP Mainnet and OP Sepolia. See how quickly your transactions reach soft and hard finality on OP Mainnet. Understand OP Mainnet's regenesis events and where pre-Bedrock data lives today. Route by role from the documentation home: chain operators, node operators, and protocol learners each have their own section. # Connecting to OP Mainnet Source: https://docs.optimism.io/op-mainnet/network-information/connecting-to-op Documentation for OP Mainnet and OP Sepolia. This page covers network information including network names, chain IDs, RPC endpoints, currency symbols, block explorers, and contract addresses. This page provides network information for OP Mainnet and OP Sepolia, including RPC endpoints, chain IDs, and block explorers. The public RPC URLs provided below are rate limited and do not support websocket connections. If you are experiencing rate limiting issues or need websocket functionality, consider [running your own node](/node-operators/overview) or signing up for a [third-party RPC provider](/app-developers/reference/rpc-providers). ## OP Mainnet | Parameter | Value | | ------------------------------------ | ----------------------------------------------------------------------------------------------- | | Network Name | `OP Mainnet` | | Chain ID | `10` | | Currency Symbol1 | ETH | | Explorer | [https://explorer.optimism.io](https://explorer.optimism.io) | | Public RPC URL | [https://mainnet.optimism.io](https://mainnet.optimism.io) | | Sequencer URL2 | [https://mainnet-sequencer.optimism.io](https://mainnet-sequencer.optimism.io) | | Subblocks websocket URL 3 | [wss://op-mainnet-fb-ws-pub.optimism.io/ws](wss://op-mainnet-fb-ws-pub.optimism.io/ws) | | Contract Addresses | Refer to the [Contract Addresses page](/op-mainnet/network-information/op-addresses#op-mainnet) | | Connect Wallet | [Click here to connect your wallet to OP Mainnet](https://chainid.link?network=optimism) | 1. The "currency symbol" is required by some wallets like MetaMask. 2. The sequencer URL is write only. 3. Strictly rate-limited public URL. Please rely on Ethereum JSON RPC or reach out to the Optimism team for a more relaxed private endpoint. ## OP Sepolia | Parameter | Value | | ------------------------------------ | ----------------------------------------------------------------------------------------------- | | Network Name | `OP Sepolia` | | Chain ID | `11155420` | | Currency Symbol1 | ETH | | Explorer | [https://testnet-explorer.optimism.io](https://testnet-explorer.optimism.io) | | Public RPC URL | [https://sepolia.optimism.io](https://sepolia.optimism.io) | | Subblocks websocket URL 3 | [wss://op-sepolia-fb-ws.optimism.io/ws](wss://op-sepolia-fb-ws.optimism.io/ws) | | Sequencer URL2 | [https://sepolia-sequencer.optimism.io](https://sepolia-sequencer.optimism.io) | | Contract Addresses | Refer to the [Contract Addresses page](/op-mainnet/network-information/op-addresses#op-sepolia) | | Connect Wallet | [Click here to connect your wallet to OP Sepolia](https://chainid.link?network=op-sepolia) | 1. The "currency symbol" is required by some wallets like MetaMask. 2. The sequencer URL is write only. 3. Strictly rate-limited public URL. Please rely on Ethereum JSON RPC or reach out to the Optimism team for a more relaxed private endpoint. # OP Mainnet Contract Addresses Source: https://docs.optimism.io/op-mainnet/network-information/op-addresses A comprehensive list of L1 and L2 contract addresses for OP Mainnet and OP Sepolia. This page lists all contract addresses for OP Mainnet and OP Sepolia. For high-level details and source code, see the [Smart Contracts Overview](/op-stack/protocol/smart-contracts). Contract addresses are automatically synced from the [superchain-registry](https://github.com/ethereum-optimism/superchain-registry/tree/main). ## L2 Contract Addresses ### OP Mainnet ### OP Sepolia ## L1 Contract Addresses ### Ethereum Mainnet ### Ethereum Testnet (Sepolia) ## Shared Contracts ### Ethereum Mainnet ### Ethereum Testnet (Sepolia) ## Legacy Contracts Legacy contracts are from previous versions of the OP Stack and are maintained for backwards compatibility. ### OP Mainnet Legacy (L2) ### Ethereum Mainnet Legacy (L1) # Snapshots Source: https://docs.optimism.io/op-mainnet/network-information/snapshots Find download links for data directories and database snapshots for running your own node. # Node snapshots This page contains download links for data directories and node snapshots. State snapshots are pre-synced node data that let you start an OP Stack execution client from a recent chain state instead of replaying from genesis. You download the snapshot and run your node from it, which dramatically cuts initial sync time. For step-by-step instructions on downloading, verifying, and extracting a snapshot, follow the [Restore a node from a snapshot guide](/node-operators/guides/management/restore-from-snapshot). Data directories and node snapshots are **not required** in the following cases: * When using [snap sync](/node-operators/reference/consensus-layer-sync) with op-geth * When using [Nethermind](https://docs.nethermind.io/get-started/running-node/l2-networks#op-stack) (automatically handles snapshots) They are still required for archive nodes and in instances when you need to trace the entire chain with `op-reth` or `op-geth`. OP Mainnet underwent a large [database migration](https://web.archive.org/web/20240110231645/https://blog.oplabs.co/reproduce-bedrock-migration/) as part of the [Bedrock Upgrade](https://web.archive.org/web/20230608050602/https://blog.oplabs.co/introducing-optimism-bedrock/) in 2023. Node operators using `op-reth` or `op-geth` must have a migrated OP Mainnet database to run an archival node. Migrated OP Mainnet databases can be generated manually or pre-migrated databases can be downloaded from the links below. ## Available OP Mainnet Snapshots Using [aria2](https://aria2.github.io/) to download snapshots can significantly speed up the download process. All snapshots for OP Mainnet can be found at the OP Labs managed [Data Directories](https://datadirs.optimism.io/) website. All geth snapshots are configured for pebbleDB and the hash state scheme. ### Nethermind [Nethermind](https://docs.nethermind.io/get-started/running-node/l2-networks#op-stack) automatically handles downloading and applying the necessary snapshots when you start the node. No manual snapshot download is required. The node will: 1. Start with an empty database 2. Automatically download the required ancient data 3. Apply the data and continue syncing This process is fully automated and requires no additional configuration. When you run `Nethermind` with the `-c op-mainnet` flag, it uses this configuration automatically. ## 3rd Party Snapshots [Allnodes](https://www.allnodes.com) provides full node snapshots for OP Mainnet and Testnet. You can find them [here](https://www.publicnode.com/snapshots#optimism). **Please note:** Allnodes is a 3rd party provider, and the Optimism Foundation hasn't verified the snapshots. # Transaction finality on OP Mainnet Source: https://docs.optimism.io/op-mainnet/network-information/transaction-finality How long transactions take to reach each finality stage on OP Mainnet. OP Mainnet follows the standard OP Stack finality model. A transaction reaches soft finality as soon as the Sequencer processes it (sub-second preconfirmation with Subblocks) and reaches hard finality, guaranteed by Ethereum, once the batch containing it is included in an Ethereum block and that block is finalized, typically 15 to 30 minutes after submission. For the full explanation of the journey from soft finality to hard finality, including the trust assumptions at each stage, see [Transaction finality](/op-stack/transactions/transaction-finality). A common misconception is that transactions on OP Mainnet take 7 days to finalize. **This is incorrect.** Only *withdrawals* to Ethereum through the Standard Bridge wait 7 days; transaction finality itself typically takes about 15 to 30 minutes. ## Typical timings on OP Mainnet | Stage | What has happened | Typical time after submission | | ---------------------------------- | ------------------------------------------------------------------------------------ | ----------------------------- | | Subblock preconfirmation | The Sequencer includes the transaction in a [subblock](/op-stack/features/subblocks) | \~200 milliseconds | | Soft finality (L2 block inclusion) | The transaction is in an L2 block distributed over the peer-to-peer network | \~2 seconds | | Data on Ethereum | A batch containing the transaction lands in an Ethereum block | A few minutes | | Hard finality (finalized) | Ethereum finalizes the block containing the batch | \~15 to 30 minutes | These timings depend on Ethereum network conditions. The inclusion on Ethereum's blockchain depends on the batcher's submission cadence: OP Mainnet produces enough data to post batches every few minutes. The finalized stage then adds Ethereum's own time to finality, normally about two to three epochs (roughly 13 to 19 minutes) after the batch lands on Ethereum. ## Withdrawals to Ethereum Withdrawals of ETH and ERC-20 tokens through the Standard Bridge wait a 7-day challenge period before the funds can be claimed on Ethereum. This is a property of the bridge's Fault Proof protection, not of transaction finality: the OP Mainnet chain itself does not take 7 days to finalize, and a successful challenge never reorgs the L2 chain. See [Withdrawal flow](/op-stack/bridging/withdrawal-flow) for how the challenge period works. # Lost pre-regenesis data Source: https://docs.optimism.io/op-mainnet/pre-bedrock-history/lost-pre-regenesis-data Understand why some OP Mainnet transaction data from January to July 2021 cannot be fully recovered. This page explains why part of OP Mainnet's earliest transaction history is permanently incomplete. For how to look up the pre-regenesis history that *is* available, see [accessing pre-regenesis history](/op-mainnet/pre-bedrock-history/regenesis-history). Because of the final regenesis on 11 November 2021, transactions from before that date are not part of the current blockchain and do not appear on [Etherscan](https://explorer.optimism.io/?utm_source=op-docs\&utm_medium=docs). Most of that history remains queryable through external tools, but one early slice of it was lost. ## Lost data directories Three data directories that were used by legacy L2Geth Sequencer instances during the period of January 2021 to July 2021 had been errantly deleted during an infra cleanup in August 2023. These data directories contained information about the effects of transactions, once executed. This information can only be obtained by properly executing the transaction chain. The most valuable data within these directories was (1) events emitted by smart contracts during each transaction and (2) the success state of the transaction (whether or not the transaction executed or reverted). This information is valuable for tracking things like ETH transfers or ERC-20 token transfers. Without this we can still know the final set of balances but the intermediate balances become opaque. The transaction data for this period of time was published to a smart contract on Ethereum called the [CanonicalTransactionChain](https://etherscan.io/address/0x5e4e65926ba27467555eb562121fac00d24e9dd2). While it is theoretically possible to recover the data by downloading and re-executing this chain of transactions from Ethereum, this is a labor intensive and costly task that may not fully recover the data. The OP Labs team did attempt data recovery efforts, including reaching out to several partners. ## Impact No state, balances, or user assets were lost. Most of the impact is felt by data providers who want complete data sets for analysis purposes and by individuals who may want this information for tax purposes. Since this was very early during the history of OP Mainnet there are relatively few transactions in this period and this data is infrequently requested. Most requests for this data came from individuals who needed access to this information for the 2021 tax season though this is mostly no longer relevant today (many people who needed this data already retrieved it). ## Going forward We recognize the inconvenience this has caused some of our community and their users and we're sorry for the frustrations. In an effort to prevent similar situations from happening again in the future, we are evaluating and updating existing processes and frameworks. # Accessing pre-regenesis history Source: https://docs.optimism.io/op-mainnet/pre-bedrock-history/regenesis-history Learn how to access pre-regenesis history using the Etherscan CSV exporting tool. This guide explains how to access transaction history between 23 June 2021 and the final regenesis. Because of our final regenesis on 11 November 2021, older transactions are not part of the current blockchain and do not appear on [Etherscan](https://explorer.optimism.io/?utm_source=op-docs\&utm_medium=docs). Event and transaction-status data from January to July 2021 was partially lost and cannot be fully recovered. See [lost pre-regenesis data](/op-mainnet/pre-bedrock-history/lost-pre-regenesis-data) for what is missing, why, and the impact. ## Dune access You can use a query on [Dune Analytics](https://dune.com), similar to [this query](https://dune.com/queries/354886?addr=%5Cx25E1c58040f27ECF20BBd4ca83a09290326896B3). You have to log on with a Dune account, but their free tier is sufficient. Alternatively, to run custom queries in Dune, you can use the `optimism_legacy_ovm1` schema defined in [Dune Docs here](https://dune.com/docs/data-tables/?h=ovm#optimism). # Cross-Domain Overview Source: https://docs.optimism.io/op-stack/bridging/cross-domain An overview of the lifecycle of an OP Stack cross-chain transaction, linking the detailed explainers for deposits, transaction flow, and withdrawals. Cross-domain communication in the OP Stack involves moving assets and messages between L1 and L2. Key components, such as the Standard Bridge, the cross-domain messenger contracts, and the `OptimismPortal`, ensure these transactions are executed securely and transparently. This page summarizes the lifecycle of a cross-chain transaction in three flows and links the detailed explainer for each: deposit flow, transaction flow, and withdrawal flow. ## Deposit flow A *deposit* is any L2 transaction triggered by a transaction or event on L1. An L1 account or contract (often the L1 Standard Bridge) sends a message through the `L1CrossDomainMessenger`, which passes it to the `OptimismPortal` contract on L1. The portal emits a `TransactionDeposited` event, `op-node` derives a deposit transaction from that event, and the `L2CrossDomainMessenger` relays the call to its target on L2. For the step-by-step walkthrough, see [Deposit flow](/op-stack/bridging/deposit-flow). ## Transaction flow Every L2 transaction has two requirements: its data must be written to L1 (done in compressed batches by `op-batcher`), and it must be executed by the execution client to update the L2 state, after which `op-proposer` posts a commitment to the resulting state to L1. For the step-by-step walkthrough, see [Transaction flow](/op-stack/transactions/transaction-flow); for when a transaction can be relied on as irreversible, see [Transaction finality](/op-stack/transactions/transaction-finality). ## Withdrawal flow A *withdrawal* is a transaction sent from L2 back to L1. It requires three user transactions: a withdrawal initiating transaction on L2, recorded by the `L2ToL1MessagePasser`; a withdrawal proving transaction on L1, which proves the withdrawal against an output root; and, once the fault challenge period (7 days on mainnet, shorter on test networks) has passed, a withdrawal finalizing transaction on L1 that executes the withdrawal. For the step-by-step walkthrough, see [Withdrawal flow](/op-stack/bridging/withdrawal-flow). # Deposit flow Source: https://docs.optimism.io/op-stack/bridging/deposit-flow Learn the deposit flow process for L2 deposit transactions, triggered by events on L1. **Learn the OP Stack — stop 8 of 13.** You've followed a transaction that starts and ends on L2. This page adds the first cross-layer direction: how a transaction triggered on L1 becomes an L2 transaction. When you're done, continue to [Withdrawal flow](/op-stack/bridging/withdrawal-flow). This page explains the deposit flow process for L2 deposit transactions, triggered by transactions or events on L1. In Optimism terminology, "*deposit transaction*" refers to any L2 transaction that is triggered by a transaction or event on L1. The process is somewhat similar to the way [most networking stacks work](https://en.wikipedia.org/wiki/Encapsulation_\(networking\)). Information is encapsulated in lower layer packets on the sending side and then retrieved and used by those layers on the receiving side while going up the stack to the receiving application. Deposit Flow Diagram. ## L1 processing 1. An L1 entity, either a smart contract or an externally owned account (EOA), sends a deposit transaction to [`L1CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol), using [`sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol#L191-L211). This function accepts three parameters: * `_target`, target address on L2. * `_message`, the L2 transaction's calldata, formatted as per the [ABI](https://docs.soliditylang.org/en/v0.8.19/abi-spec.html) of the target account. * `_minGasLimit`, the minimum gas limit allowed for the transaction on L2. Note that this is a *minimum* and the actual amount provided on L2 may be higher (but never lower) than the specified gas limit. The actual amount provided on L2 is often higher because the portal contract on L2 performs some processing before submitting the call to `_target`. 2. The L1 cross domain messenger calls [its own `_sendMessage` function](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol#L83-L91). It uses these parameters: * `_to`, the destination address, is the messenger on the other side. In the case of deposits, this is always [`0x4200000000000000000000000000000000000007`](https://testnet-explorer.optimism.io/address/0x4200000000000000000000000000000000000007). * `_gasLimit`, the gas limit. This value is calculated using [the `baseGas` function](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol#L357-L396). * `_value`, the ETH that is sent with the message. This amount is taken from the transaction value. * `_data`, the calldata for the call on L2 that is needed to relay the message. This is an [ABI encoded](https://docs.soliditylang.org/en/v0.8.19/abi-spec.html) call to [`relayMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol#L222-L320). 3. [`_sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol#L83-L91) calls the portal's [`depositTransaction` function](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L684-L738). Note that other contracts can also call [`depositTransaction`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L684-L738) directly. However, doing so bypasses certain safeguards, so in most cases it's a bad idea. 4. [The `depositTransaction` function](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L684-L738) runs a few sanity checks, and then emits a [`TransactionDeposited`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L149-L155) event. ## L2 processing 1. The `op-node` component [looks for `TransactionDeposited` events on L1](https://github.com/ethereum-optimism/optimism/blob/develop/op-node/rollup/derive/deposits.go#L15-L34). If it sees any such events, it [parses](https://github.com/ethereum-optimism/optimism/blob/develop/op-node/rollup/derive/deposit_log.go) them. 2. Next, `op-node` [converts](https://github.com/ethereum-optimism/optimism/blob/develop/op-node/rollup/derive/deposits.go#L36-L52) those `TransactionDeposited` events into [deposit transactions](https://specs.optimism.io/protocol/deposits.html?utm_source=op-docs\&utm_medium=docs#user-deposited-transactions). 3. In most cases, user deposit transactions call the [`relayMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol#L222-L320) function of [`L2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol#L22). 4. `relayMessage` runs a few sanity checks and then, if everything is good, [calls the real target contract with the relayed calldata](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol#L298). ## Denial of service (DoS) prevention As with all other L1 transactions, the L1 costs of a deposit are borne by the transaction's originator. However, the L2 processing of the transaction is performed by the Optimism nodes. If there were no cost attached, an attacker could submit a transaction that had high execution costs on L2, and that way perform a denial of service attack. To avoid this DoS vector, [`depositTransaction`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L684-L738), and the functions that call it, require a gas limit parameter. [This gas limit is encoded into the `TransactionDeposited` event](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L733-L737), and used as the gas limit for the user deposit transaction on L2. This L2 gas is paid for by burning L1 gas [here](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/ResourceMetering.sol#L149). ## Replaying failed deposits Deposit transactions can fail on L2 — usually because not enough gas was provided, or the L2 state did not allow the transaction to succeed. When that happens the message is not lost: `L2CrossDomainMessenger` records it as a failed message, and you can replay it later, optionally with more gas. To walk through triggering a failed deposit and replaying it end to end, follow the tutorial [Replaying a failed deposit](/app-developers/tutorials/bridging/replay-failed-deposit). # Withdrawal flow Source: https://docs.optimism.io/op-stack/bridging/withdrawal-flow Learn the withdrawal flow process for transactions sent from L2 to L1. **Learn the OP Stack — stop 9 of 13.** You know how transactions enter L2 from L1. This page adds the return direction: the initiate, prove, and finalize steps a withdrawal takes back to L1. When you're done, continue to [Submitting transactions from L1](/app-developers/tutorials/bridging/cross-dom-bridge-eth). In Optimism terminology, a *withdrawal* is a transaction sent from L2 (OP Mainnet, OP Sepolia etc.) to L1 (Ethereum mainnet, Sepolia, etc.). Withdrawals require the user to submit three transactions: 1. **Withdrawal initiating transaction**, which the user submits on L2. 2. **Withdrawal proving transaction**, which the user submits on L1 to prove that the withdrawal is legitimate (based on a Merkle-Patricia trie root that commits to the state of the `L2ToL1MessagePasser`'s storage on L2) 3. **Withdrawal finalizing transaction**, which the user submits on L1 after the fault challenge period has passed, to actually run the transaction on L1. You can read the full [withdrawal specifications here](https://specs.optimism.io/protocol/withdrawals.html?utm_source=op-docs\&utm_medium=docs). You can see an example of how to implement this process [in the bridging tutorials](/app-developers/tutorials/bridging/cross-dom-bridge-erc20). ## Withdrawal initiating transaction 1. On L2, a user, either an externally owned account (EOA) directly or a contract acting on behalf of an EOA, calls the [`sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol#L191) function of the [`L2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol#L22) contract. This function accepts three parameters: * `_target`, target address on L1. * `_message`, the L1 transaction's calldata, formatted as per the [ABI](https://docs.soliditylang.org/en/v0.8.19/abi-spec.html) of the target address. * `_minGasLimit`, The minimum amount of gas that the withdrawal finalizing transaction can provide to the withdrawal transaction. This is enforced by the `SafeCall` library, and if the minimum amount of gas cannot be met at the time of the external call from the `OptimismPortal` -> `L1CrossDomainMessenger`, the finalization transaction will revert to allow for re-attempting with a higher gas limit. In order to account for the gas consumed in the `L1CrossDomainMessenger.relayMessage` function's execution, extra gas will be added on top of the `_minGasLimit` value by the `CrossDomainMessenger.baseGas` function when `sendMessage` is called on L2. 2. `sendMessage` is a generic function that is used in both cross domain messengers. It calls [`_sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol#L47), which is specific to [`L2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol#L22). 3. `_sendMessage` calls [`initiateWithdrawal`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol#L78) on [`L2ToL1MessagePasser`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol#L19). This function calculates the hash of the raw withdrawal fields. It then marks that hash as a sent message in [`sentMessages`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol#L27) and emits the fields with the hash in a [`MessagePassed`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol#L40) event. The raw withdrawal fields are: * `nonce` - A single use value to prevent two otherwise identical withdrawals from hashing to the same value * `sender` - The L2 address that initiated the transfer, typically [`L2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol#L22) * `target` - The L1 target address * `value` - The amount of WEI transferred by this transaction * `gasLimit` - Gas limit for the transaction, the system guarantees that at least this amount of gas will be available to the transaction on L1. Note that if the gas limit is not enough, or if the L1 finalizing transaction does not have enough gas to provide that gas limit, the finalizing transaction returns a failure, it does not revert. * `data` - The calldata for the withdrawal transaction 4. When `op-proposer`proposes a new `output`, the output proposal includes the [output root](https://specs.optimism.io/glossary.html?utm_source=op-docs\&utm_medium=docs#l2-output-root), provided as part of the block by `op-node`. This new output root commits to the state of the `sentMessages` mapping in the `L2ToL1MessagePasser` contract's storage on L2, and it can be used to prove the presence of a pending withdrawal within it. ## Withdrawal proving transaction Once an output root that includes the `MessagePassed` event is published to L1, the next step is to prove that the message hash really is in L2. Typically this is done by viem. ### Offchain processing 1. A user calls viem's `proveWithdrawal()` function with the withdrawal transaction receipt. This function internally handles the preparation of the proving transaction parameters. 2. To get the withdrawal details from the L2 transaction, viem uses the `getWithdrawals()` function which extracts the raw withdrawal fields from the `MessagePassed` event in the transaction receipt. 3. To get the proof, viem uses the withdrawal proving functionality to generate the necessary Merkle proof. 4. Finally, viem calls [`OptimismPortal.proveWithdrawalTransaction()`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L375) on L1. ### Onchain processing [`OptimismPortal.proveWithdrawalTransaction()`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L375) runs a few sanity checks. Then it verifies that in `L2ToL1MessagePasser.sentMessages` on L2 the hash for the withdrawal is turned on, using a Merkle proof against the output root claimed by a fault dispute game. If everything checks out, it writes the dispute game and the timestamp of the proof in `provenWithdrawals` and emits an event. A withdrawal can be proven more than once (for example, against a different dispute game if the original game turns out to be invalid), and re-proving resets the proof timer. The next step is to wait the fault challenge period (7 days on mainnet, shorter on test networks), to ensure that the L2 output root used in the proof is legitimate, and that the proof itself is legitimate and not a hack. ## Withdrawal finalizing transaction Finally, once the fault challenge period passes, the withdrawal can be finalized and executed on L1. To do so, a user, either an externally owned account (EOA) directly or a contract acting on behalf of an EOA, calls the [`finalizeWithdrawalTransaction`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L481) function of the [`OptimismPortal`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L37) contract. ## Expected internal reverts in withdrawal transactions During the withdrawal process, users may observe internal reverts when viewing the transaction on **Etherscan**. This is a common point of confusion but is expected behavior. These internal reverts often show up in yellow on the Etherscan UI and may cause concern that something went wrong with the transaction. However, these reverts occur due to the non-standard proxy used in Optimism, specifically the **Chugsplash Proxy**. The Chugsplash Proxy sometimes triggers internal calls that revert as part of the designed flow of the withdrawal process. ### Why do these reverts happen? The Chugsplash Proxy operates differently than standard proxies. During a withdrawal transaction, it may trigger internal contract calls that result in reverts, but these reverts do not indicate that the withdrawal has failed. Instead, they are part of the internal logic of the system and are expected in certain scenarios. ### Key takeaways: * **Internal Reverts Are Expected**: These reverts are part of the normal operation of the Chugsplash Proxy during withdrawal transactions and do not represent an error. * **No Cause for Concern**: Although Etherscan highlights these reverts, they do not affect the final success of the transaction. * **User Assurance**: If you encounter these reverts during a withdrawal transaction, rest assured that the withdrawal will still finalize as expected. ### Offchain processing 1. A user calls viem's `finalizeWithdrawal()` function with the withdrawal transaction receipt. This function internally handles the preparation of the finalization transaction parameters. 2. To get the withdrawal details from the L2 transaction, viem uses the `getWithdrawals()` function which extracts the raw withdrawal fields from the `MessagePassed` event in the transaction receipt. 3. Finally, viem calls [`OptimismPortal.finalizeWithdrawalTransaction()`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L481-L483) on L1. ### Onchain processing 1. [`OptimismPortal.finalizeWithdrawalTransaction()`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L481-L483) runs several checks. The interesting ones are: * [Verify that the withdrawal has already been proven](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L647-L652). * [Verify that the proof was submitted long enough ago that the proof maturity delay has already passed](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L662-L665). * [Verify that the dispute game the withdrawal was proven against resolved in favor of the proposed output root, and that its claim has not since been invalidated](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L667-L670). * [Verify that the withdrawal has not been finalized before to prevent replay attacks](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L642-L645). If any of these checks fail, the transaction reverts. 2. Mark the withdrawal as finalized in `finalizedWithdrawals`. 3. Run the actual withdrawal transaction (call the `target` contract with the calldata in `data`). 4. Emit a [`WithdrawalFinalized`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L173) event. # cannon Source: https://docs.optimism.io/op-stack/components/cannon Canonical hub for cannon, the OP Stack fault proof virtual machine — what it does, who runs it, and where its guides, releases, source, and spec live. cannon is the OP Stack's fault proof virtual machine (FPVM): an onchain MIPS instruction emulator that lets a disputed L2 state transition be re-executed, one instruction at a time, on L1. ## Overview cannon has two halves that must behave identically: * **Onchain `MIPS64.sol`** — a Solidity implementation of big-endian 64-bit MIPS (MIPS64r1) instruction execution, used to verify a single disputed instruction on L1. * **Offchain `mipsevm`** — an instrumented emulator of the same instruction set that runs the full program and produces the witness data needed to repeat any one step onchain. The program cannon executes is the fault proof program, [kona-client](/releases/kona-client), compiled to a MIPS ELF binary; the [kona-host](/releases/kona-host) binary runs alongside as the preimage server that supplies chain data during execution. Together they make fault disputes resolvable: participants bisect an execution trace down to a single MIPS instruction, and that one instruction is proven onchain. **Who runs it:** dispute game participants, not everyday node operators. [op-challenger](/op-stack/fault-proofs/challenger) invokes the cannon binary automatically when a fault dispute reaches the execution-trace stage, and chain operators build cannon prestates when configuring permissionless fault proofs. For how cannon fits into the dispute game, see the [fault proofs explainer](/op-stack/fault-proofs/explainer) and the [Cannon](/op-stack/fault-proofs/cannon) and [MIPS](/op-stack/fault-proofs/mips) deep-dive pages. ## Get started * [Cannon usage](https://github.com/ethereum-optimism/optimism/tree/develop/cannon#usage) — the in-repo README walks through building cannon, loading a kona-client ELF into an initial VM state, and running the emulator. ## How-tos * [Generating absolute prestate and preimage files](/chain-operators/tutorials/absolute-prestate) — build and verify the cannon prestate of kona-client that op-challenger runs at dispute time. * [Generating a custom kona-client absolute prestate](/chain-operators/tutorials/kona-custom-prestate) — the same, for chains not yet in the public Superchain Registry. ## Configuration & flags reference * cannon has no configuration reference page on this site yet; it is configured entirely through CLI flags, documented by `cannon --help` and the [in-repo README](https://github.com/ethereum-optimism/optimism/tree/develop/cannon#usage). ## Releases * [cannon release tags on GitHub](https://github.com/ethereum-optimism/optimism/releases?q=cannon%2Fv\&expanded=false) — cannon does not have a page under [Releases](/releases) yet. ## Source & spec links * [Source: `cannon/`](https://github.com/ethereum-optimism/optimism/tree/develop/cannon) in the Optimism monorepo; the onchain contracts live in [`packages/contracts-bedrock/src/cannon`](https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/cannon). * [Cannon overview docs](https://github.com/ethereum-optimism/optimism/blob/develop/cannon/docs/README.md) — in-repo documentation of the onchain/offchain split and the witness data (packed state, memory proofs, preimage data). * [Cannon fault proof VM specification](https://specs.optimism.io/fault-proof/cannon-fault-proof-vm.html) — the normative definition of the VM. # Stack Components Source: https://docs.optimism.io/op-stack/components/index One canonical hub page per OP Stack component, grouped by protocol role. This section gives every OP Stack component exactly one identity page — its **hub** — so "where do I find docs for component X" always has the same answer. Each hub follows the same [skeleton](/op-stack/contribute/component-hub-template): what the component is, who runs it, where to start, and where its guides, configuration reference, releases, source, and spec live. Components are grouped by their role in the protocol. For how these roles fit together conceptually — data availability, sequencing, derivation, execution, settlement — see the [OP Stack components](/op-stack/protocol/components) explanation. For release history across all components, see [Releases](/releases). Hubs are shipping in reviewed batches. Components without a hub yet are listed with their release history; their hub pages follow. ## Sequencing Producing L2 blocks and making their data available. | Component | What it does | Hub | Releases | | ------------ | ----------------------------------------------------------- | ---------------------------------------- | ---------------------------------- | | op-batcher | Posts L2 transaction batches to the data availability layer | [Hub](/op-stack/components/op-batcher) | [Releases](/releases/op-batcher) | | op-conductor | High-availability sequencer coordination service | [Hub](/op-stack/components/op-conductor) | [Releases](/releases/op-conductor) | ## Derivation & execution Deriving the canonical L2 chain from the data availability layer and executing its blocks. | Component | What it does | Hub | Releases | | --------- | ---------------------------------------------------- | ------------------------------------- | ------------------------------- | | op-node | OP Stack consensus-layer (rollup node) client, in Go | [Hub](/op-stack/components/op-node) | [Releases](/releases/op-node) | | kona-node | Rust implementation of the OP Stack rollup node | [Hub](/op-stack/components/kona-node) | [Releases](/releases/kona-node) | | op-reth | OP Stack execution-layer client built on Reth | [Hub](/op-stack/components/op-reth) | [Releases](/releases/op-reth) | ## Settlement & proofs Proposing L2 state to L1 and proving its validity. | Component | What it does | Hub | Releases | | ------------- | ------------------------------------------------------------------------ | ----------------------------------------- | --------------------------------------------------------------------------------------------------- | | op-proposer | Proposes L2 output roots to L1 | [Hub](/op-stack/components/op-proposer) | [Releases](/releases/op-proposer) | | op-challenger | Dispute game challenge agent | [Hub](/op-stack/components/op-challenger) | [Releases](/releases/op-challenger) | | cannon | Onchain MIPS instruction emulator — the fault proof VM | [Hub](/op-stack/components/cannon) | [Release tags](https://github.com/ethereum-optimism/optimism/releases?q=cannon%2Fv\&expanded=false) | | kona-client | Fault proof program (client) that executes the OP Stack state transition | [Hub](/op-stack/components/kona-client) | [Releases](/releases/kona-client) | | kona-host | Fault proof host that serves preimage data to kona-client | [Hub](/op-stack/components/kona-host) | [Releases](/releases/kona-host) | | op-contracts | OP Stack L1 and L2 smart contracts | [Hub](/op-stack/components/op-contracts) | [Releases](/releases/op-contracts) | ## Deployment & infrastructure Deploying chains and operating the infrastructure around them. | Component | What it does | Hub | Releases | | ----------- | ------------------------------------------ | --------------------------------------- | --------------------------------- | | op-deployer | OP Stack chain deployment and upgrade tool | [Hub](/op-stack/components/op-deployer) | [Releases](/releases/op-deployer) | | proxyd | RPC request router and proxy | [Hub](/op-stack/components/proxyd) | [Releases](/releases/proxyd) | # kona-client Source: https://docs.optimism.io/op-stack/components/kona-client Canonical hub for kona-client, the OP Stack fault proof program, covering what it does, who runs it, and where its guides, releases, source, and spec live. kona-client is the OP Stack's fault proof program: a Rust program, built as part of the [Kona](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona) project, that executes the L2 state transition so a disputed output root can be verified inside a fault proof VM. ## Overview kona-client derives the disputed span of the L2 chain from L1 data, re-executes its blocks, and checks the result against the claimed L2 output root. It runs sandboxed, with no network access: every piece of chain data it consumes (L1 headers, transactions, receipts, blobs, L2 state) arrives through the preimage oracle ABI, served by its companion host process, [kona-host](/op-stack/components/kona-host). It is built so that the same inputs produce not only the same outputs but the same execution trace. That determinism is what makes fault disputes resolvable. For dispute games, kona-client is compiled to a big-endian 64-bit MIPS (MIPS64) ELF binary and run inside the [cannon](/op-stack/components/cannon) FPVM; this pairing backs the `CANNON_KONA` dispute game (game type 8), the respected game type for permissionless fault proofs since [Upgrade 19](/notices/archive/upgrade-19). Because every honest participant computes the identical execution trace, a dispute can be bisected down to a single MIPS instruction and that one instruction proven on L1. kona-client succeeded op-program, the Go fault proof program behind the legacy `CANNON` (game type 0) and `PERMISSIONED_CANNON` (game type 1) games; op-program has reached end of support (see [End of Support for op-geth and op-program](/notices/archive/op-geth-deprecation)), and the kona binaries are the maintained fault proof program today. **Who runs it:** nobody invokes it by hand in production. [op-challenger](/op-stack/fault-proofs/challenger) runs cannon when a fault dispute reaches the execution-trace stage, and cannon executes the kona-client ELF committed to by the chain's absolute prestate. Chain operators pin that prestate when configuring fault proofs; developers can also run kona-client natively through kona-host for testing. ## Get started * [Generating absolute prestate and preimage files](/chain-operators/tutorials/absolute-prestate): build and verify the absolute prestate, the onchain commitment to a specific kona-client build, whose preimage op-challenger runs at dispute time. ## How-tos * [Generating a custom kona-client absolute prestate](/chain-operators/tutorials/kona-custom-prestate): build a kona-client that embeds a chain configuration not yet in the public Superchain Registry. * [Switch to Kona Proofs](/chain-operators/guides/features/switching-to-kona-proofs): move an existing chain's respected game type to the Kona-based fault proofs. * [Run a fault-proof challenger](/use-cases/run-a-fault-proof-challenger): stand up the op-challenger deployment that exercises kona-client, from prestate selection through configuration and monitoring. ## Configuration & flags reference * kona-client has no configuration reference page and no operator-facing flags. Its inputs (the L1 head, the disputed output roots, the chain configuration) arrive as bootstrap data over the preimage oracle, as defined in the [fault proof program specification](https://specs.optimism.io/fault-proof/index.html#fault-proof-program). ## Releases * [kona-client release history](/releases/kona-client) ## Source & spec links * [Source: `rust/kona/bin/client`](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/bin/client) in the Optimism monorepo. * [Fault proof program development](/op-stack/fault-proofs/kona/fpp-dev/intro): how fault proof programs like kona-client are structured (prologue, execution, epilogue) and built on the Kona SDK. * [Fault proof program specification](https://specs.optimism.io/fault-proof/index.html#fault-proof-program): the normative definition of the program's prologue, main content, and epilogue. # kona-host Source: https://docs.optimism.io/op-stack/components/kona-host Canonical hub for kona-host, the fault proof host that serves preimage data to kona-client, covering what it does, who runs it, and where its guides, releases, source, and spec live. kona-host is the OP Stack's fault proof host program: a native Rust binary, built as part of the [Kona](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona) project, that runs the preimage server supplying chain data to [kona-client](/op-stack/components/kona-client) while it executes. ## Overview kona-client runs with no network access, so it cannot fetch chain data itself: everything it reads arrives as a preimage requested by key over the preimage oracle ABI. kona-host is the other end of that channel. It fetches the requested data (L1 headers, transactions, receipts, blobs, L2 state) from its configured L1, L1 beacon, and L2 endpoints, responds to the client's hints so the right preimages are ready when asked for, and serves them back. Without it, the fault proof program would have no way to learn the chain state it is asked to verify. kona-host runs in `single` mode (one pre-interop chain) or `super` mode (an interop superchain cluster), and its preimage server starts in one of two ways: `server` mode, where it only serves preimages to a client program run by an FPVM (when [cannon](/op-stack/components/cannon) executes kona-client, it launches kona-host as a subprocess, passing the host command after a `--` separator on `cannon run`), and `native` mode, where kona-host runs kona-client itself in a native process, useful for witness generation and testing. **Who runs it:** dispute game participants, indirectly: [op-challenger](/op-stack/fault-proofs/challenger)'s `--cannon-kona-server` flag points at a kona-host binary, which cannon launches when a fault dispute reaches the execution-trace stage. Developers also run it directly in native mode to execute kona-client without an FPVM. ## Get started * [kona-host usage](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/bin/host#usage): the in-repo README documents the host modes, the preimage server modes, and the CLI surface. ## How-tos * [Run a fault-proof challenger](/use-cases/run-a-fault-proof-challenger): stand up an op-challenger deployment, including pointing `--cannon-kona-server` at a kona-host build that matches the configured prestate. * [Spin up challenger](/chain-operators/tutorials/create-l2-rollup/op-challenger-setup): configure op-challenger for a new chain, including where to get the kona-host binary it needs. ## Configuration & flags reference * kona-host has no configuration reference page on this site yet; it is configured entirely through CLI flags, documented by `kona-host --help` and the [in-repo README](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/bin/host#usage). ## Releases * [kona-host release history](/releases/kona-host) ## Source & spec links * [Source: `rust/kona/bin/host`](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/bin/host) in the Optimism monorepo. * [Pre-image oracle specification](https://specs.optimism.io/fault-proof/index.html#pre-image-oracle): the normative definition of the ABI kona-host implements, including the preimage key types, hinting, and bootstrapping. # kona-node Source: https://docs.optimism.io/op-stack/components/kona-node Canonical hub for kona-node, the Rust implementation of the OP Stack rollup node, with links to its guides, reference, releases, source, and spec. kona-node is the Rust implementation of the OP Stack consensus-layer (rollup node) client, built as part of the [Kona](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona) project. ## Overview kona-node performs the same protocol role as [op-node](/op-stack/protocol/components): it reads batch data and deposits from the data availability layer, derives the canonical L2 chain, and drives an execution-layer client (such as [op-reth](/node-operators/guides/configuration/execution-clients)) through the Engine API. It also participates in the unsafe-block gossip network and can run in sequencer mode. It exists to bring client diversity to the OP Stack: with independent rollup node implementations, a bug in one client cannot take down every node on a chain. Kona is in active development and kona-node should be considered experimental. **Who runs it:** node operators, as the consensus-layer half of a node stack, paired with an execution client. Chain operators can also run it in sequencer mode. ## Get started * [Install kona-node](/node-operators/kona-node/install/overview): pre-built binaries, Docker images, or building from source. Check the [system requirements](/node-operators/kona-node/requirements) first. ## How-tos * [Run a node](/node-operators/kona-node/run/overview): using the [binary](/node-operators/kona-node/run/binary) or the [Docker recipe](/node-operators/kona-node/run/docker), including [how sync works](/node-operators/kona-node/run/mechanics) and [RPC trust considerations](/node-operators/kona-node/run/rpc-trust). * [Run a sequencer node](/node-operators/kona-node/run/sequencer): flags, key management, and example configurations for sequencer mode. * [Monitoring](/node-operators/kona-node/monitoring): logging, Prometheus metrics, and Grafana dashboards. ## Configuration & flags reference * [kona-node CLI reference](/node-operators/kona-node/configuration): every CLI flag and environment variable for the `node` subcommand, plus default ports and default runtime behavior. * [`kona-node` subcommands](/node-operators/kona-node/subcommands): the other subcommands the binary ships. * [JSON-RPC reference](/node-operators/kona-node/rpc/overview): the P2P, rollup, and admin RPC namespaces. ## Releases * [kona-node release history](/releases/kona-node) ## Source & spec links * [Source: `rust/kona/bin/node`](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona/bin/node) in the Optimism monorepo. * [Kona source and README](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona): the Kona project in the Optimism monorepo; the node's [design internals](/node-operators/kona-node/design/intro) are documented beside the operator guides. * [Rollup node specification](https://specs.optimism.io/protocol/rollup-node.html): the normative definition of the rollup node's role. # op-batcher Source: https://docs.optimism.io/op-stack/components/op-batcher Canonical hub for op-batcher, the OP Stack batch submitter — what it does, who runs it, and where its guides, reference, releases, source, and spec live. op-batcher is the OP Stack's batch submitter: the service that makes an L2 chain's transaction data available by posting it to the data availability layer. ## Overview op-batcher reads unsafe blocks from the sequencer, compresses them into channels, splits the channels into frames, and submits those frames to the data availability layer — as Ethereum calldata or blob transactions, or via an [Alt-DA](/op-stack/features/experimental/alt-da-mode) layer. It can also select between calldata and blobs automatically based on current L1 prices. It exists because an OP Stack chain is *derived* from the data availability layer: until op-batcher posts a block's data, verifier nodes cannot derive it and the chain's safe head does not advance. Batches must also land within the chain's sequencing window — see the [batcher guide](/chain-operators/guides/configuration/batcher) for the policy constraints. **Who runs it:** the chain operator, as part of the sequencer's infrastructure, submitting from the chain's batch submitter address. During data availability backlogs, op-batcher can also instruct the block builder to throttle how much DA-consuming data new L2 blocks include. ## Get started * [Spin up batcher](/chain-operators/tutorials/create-l2-rollup/op-batcher-setup) — set up and configure op-batcher as part of standing up an OP Stack chain. ## How-tos * [Configure the batcher](/chain-operators/guides/configuration/batcher): batcher policy, cost tuning, multi-blob transactions, and sequencer throttling. * [Post batch data as blobs](/chain-operators/guides/features/blobs): switch the chain's data availability type to blobs. * [Enable span batches](/chain-operators/guides/features/enable-span-batches): configure the batch type on op-batcher. * [How to run an Alt-DA mode chain](/chain-operators/guides/features/alt-da-mode-guide): post data to an Alt-DA layer instead of Ethereum. ## Configuration & flags reference * [Batcher configuration reference](/chain-operators/reference/batcher-configuration) — every CLI flag and environment variable, with defaults. The reference page states the release it was written against. ## Releases * [op-batcher release history](/releases/op-batcher) ## Source & spec links * [Source: `op-batcher/`](https://github.com/ethereum-optimism/optimism/tree/develop/op-batcher) in the Optimism monorepo — its [README](https://github.com/ethereum-optimism/optimism/blob/develop/op-batcher/readme.md) documents the internal architecture and design principles. * [DA throttling deep-dive](https://github.com/ethereum-optimism/optimism/blob/develop/op-batcher/throttling.md) — in-repo documentation of the throttling controllers (step, linear, quadratic, and PID), their configuration, and runtime management over RPC. * [Batch submitter specification](https://specs.optimism.io/protocol/batcher.html) — the normative definition of the batcher's role. # op-challenger Source: https://docs.optimism.io/op-stack/components/op-challenger Canonical hub for op-challenger, the OP Stack dispute game challenge service, covering what it does, who runs it, and where its guides, releases, source, and spec live. op-challenger is the OP Stack's dispute game challenge service that monitors fault dispute games on L1, defends valid output proposals, and challenges invalid ones. ## Overview op-challenger watches the games created through the `DisputeGameFactory` (on a fault proof chain, every output proposal is a dispute game). Checking each claim against a trusted, synced rollup node, it defends proposals it agrees with, posts counterclaims against those it does not, resolves claims and games once the game clocks expire, and claims the bonds paid out to it. When a dispute is bisected down to a single VM instruction, op-challenger runs the fault proof VM, [cannon](/op-stack/components/cannon), executing kona-client with kona-host serving preimage data, to prove that instruction onchain. For a deeper walkthrough of this behavior, see the [OP-Challenger explainer](/op-stack/fault-proofs/challenger). It exists because fault proofs only secure withdrawals if someone actually responds to invalid claims before the game clocks run out. op-challenger is the implementation of the dispute protocol's *honest actor*: it defends the chain by ensuring games resolve to the correct state, which is what the `OptimismPortal` ultimately trusts for withdrawals. **Who runs it:** chain operators run at least one challenger to defend their chain, and on a permissionless fault proof chain anyone can run one. A challenger needs a synced, trusted rollup node to verify claims against, and a funded account to post bonds from. ## Get started * [Spin up challenger](/chain-operators/tutorials/create-l2-rollup/op-challenger-setup): set up and configure op-challenger as part of standing up an OP Stack chain. ## How-tos * [How to configure challenger for your chain](/chain-operators/guides/configuration/op-challenger-config-guide): the configuration options that matter in production. * [Run a fault-proof challenger](/use-cases/run-a-fault-proof-challenger): the whole operational path in one pass: bond budgeting, prestate selection, infrastructure, configuration, and monitoring. * [Generating absolute prestate and preimage files](/chain-operators/tutorials/absolute-prestate): build and verify the prestate op-challenger runs at dispute time. * [Migrating to permissionless fault proofs](/chain-operators/tutorials/migrating-permissionless): upgrade and test op-challenger as part of the migration. ## Configuration & flags reference * [Challenger configuration reference](/chain-operators/reference/challenger-configuration): every CLI flag and environment variable, with flag tables generated from the op-challenger release named on the page. The [configuration guide](/chain-operators/guides/configuration/op-challenger-config-guide) above covers the production-relevant options. ## Releases * [op-challenger release history](/releases/op-challenger) ## Source & spec links * [Source: `op-challenger/`](https://github.com/ethereum-optimism/optimism/tree/develop/op-challenger) in the Optimism monorepo; its [README](https://github.com/ethereum-optimism/optimism/blob/develop/op-challenger/README.md) documents the quickstart and the manual-testing subcommands (`create-game`, `move`, `resolve`, `list-games`, `run-trace`, and more). * [Honest challenger specification](https://specs.optimism.io/fault-proof/stage-one/honest-challenger-fdg.html): the normative behavior op-challenger implements. * [Fault dispute game specification](https://specs.optimism.io/fault-proof/stage-one/fault-dispute-game.html): the game it plays. # op-conductor Source: https://docs.optimism.io/op-stack/components/op-conductor Canonical hub for op-conductor, the high-availability sequencer coordination service, covering what it does, who runs it, and where its guides, reference, releases, and source live. op-conductor is the OP Stack's high-availability sequencer coordination service: it manages a cluster of sequencers so that exactly one leads the chain at a time and block production survives single-node failures. ## Overview op-conductor runs alongside each sequencer in a multi-node cluster, typically three nodes spread across regions or availability zones. It participates in a Raft consensus layer to elect the leader and to store the latest unsafe block, monitors its sequencer's health, starts or stops sequencing based on leadership and health, and serves admin RPCs for manual recovery scenarios. The design provides three guarantees: no unsafe reorgs, no unsafe head stall during a network partition, and continued uptime with no more than one node failure in a standard three-node setup. For how this works in detail, see the [OP Conductor explainer](/chain-operators/tools/op-conductor). It exists because a single sequencer is a single point of failure: without coordination, a crashed sequencer halts block production, and a naive failover can produce two active sequencers or reorg unsafe blocks. op-conductor is not Byzantine fault tolerant: it assumes all participating nodes are honest, performs no authentication or authorization of RPC requests, and is intended to run inside a private network. **Who runs it:** chain operators running a high-availability sequencer setup, with one conductor instance per sequencer node. The rollup node's sequencer mode integrates with it on both op-node (`--conductor.enabled` and `--conductor.rpc`) and kona-node (`--conductor.rpc`). Chains running a single sequencer do not need it. ## Get started * [Setup](/chain-operators/tools/op-conductor/setup): add op-conductor to an existing multi-sequencer OP Stack network without downtime. ## How-tos * [Launch a chain with fault proofs and HA sequencing](/use-cases/launch-a-chain-with-fault-proofs-and-ha-sequencing): the whole production path in one pass, from contract deployment through conductor cluster setup and failover drills. * [Network architecture](/chain-operators/guides/management/network-architecture): where op-conductor sits in a production topology, including its use as a leader-aware RPC proxy for op-batcher. ## Configuration & flags reference * [Configuration and RPCs](/chain-operators/tools/op-conductor/reference): every CLI flag and environment variable, with flag tables generated from the op-conductor release named on the page, plus the `conductor` namespace RPC methods for cluster management. ## Releases * [op-conductor release history](/releases/op-conductor) ## Source & spec links * [Source: `op-conductor/`](https://github.com/ethereum-optimism/optimism/tree/develop/op-conductor) in the Optimism monorepo; its [README](https://github.com/ethereum-optimism/optimism/blob/develop/op-conductor/README.md) documents the architecture, the conductor state transitions, and walkthroughs of each failure scenario. * op-conductor is operational tooling and has no section of its own in the OP Stack specifications; the sequencing role it coordinates is specified in the [rollup node specification](https://specs.optimism.io/protocol/rollup-node.html). # op-contracts Source: https://docs.optimism.io/op-stack/components/op-contracts Canonical hub for op-contracts, the OP Stack L1 and L2 smart contracts, covering what they do, how they are deployed and upgraded, and where their reference, releases, source, and specs live. op-contracts is the OP Stack's smart contract layer: the L1 contracts that anchor an OP Stack chain to Ethereum and the L2 predeploy contracts that every OP Stack chain ships in its genesis state. Both live in `packages/contracts-bedrock` in the Optimism monorepo and release together as `op-contracts/vX.Y.Z`. ## Overview The L1 contracts, deployed on Ethereum, facilitate cross-domain message passing and maintain the valid state root of the L2: deposits enter the chain through them, withdrawals are proven and finalized against dispute game results, and the chain's onchain configuration lives in them. The L2 predeploys sit at predetermined addresses in the genesis state and provide the chain's built-in functionality, from the cross-domain messengers and bridges to the fee vaults and the gas price oracle. For a contract-by-contract tour of both layers, see the [smart contract overview](/op-stack/protocol/smart-contracts). It exists because an OP Stack chain's security anchors on Ethereum: the bridge, the state proposals that dispute games check, and the withdrawal path that [op-challenger](/op-stack/components/op-challenger) defends are all enforced by these contracts. **Who runs it:** nobody operates op-contracts as a service; the contracts run onchain. Chain operators deploy a chain's L1 contracts with [op-deployer](/op-stack/components/op-deployer) and upgrade them through the [OP Contracts Manager](/chain-operators/reference/opcm), which deploys and upgrades the contracts for a chain in a single transaction. ## Get started * [Deploy L1 contracts with op-deployer](/chain-operators/tutorials/create-l2-rollup/op-deployer-setup): install op-deployer, prepare your environment, and deploy the L1 contracts for a new OP Stack chain. ## How-tos * [Upgrade using superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide): upgrade a chain's L1 contracts with the superchain-ops task workflow, the path for chains that require security council signing or a more secure upgrade process. * [Upgrade L1 contracts using op-deployer](/chain-operators/tutorials/l1-contract-upgrades/op-deployer-upgrade): version availability and migration paths for op-deployer's deprecated `upgrade` command, which supports upgrades only up to `op-contracts/v5.0.0`. ## Configuration & flags reference op-contracts has no CLI; its configuration surface is the deployment configuration the contracts are deployed with. * [Rollup deployment configuration](/chain-operators/reference/rollup-deployment-configuration): every deploy config field, generated from source and keyed to the finalized op-deployer release named on the page. * [What is a standard chain?](/op-stack/protocol/superchain-registry#what-is-a-standard-chain): the standard configuration values a chain must adhere to. ## Releases * [op-contracts release history](/releases/op-contracts). Production contract releases are always tagged `op-contracts/vX.Y.Z`; releases tagged `v` without a component name contain no smart contracts. * [Smart contract versioning policy](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/book/src/policies/versioning.md): the in-repo definition of the release process. ## Source & spec links * [Source: `packages/contracts-bedrock/`](https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock) in the Optimism monorepo. * [Contracts book](https://devdocs.optimism.io/contracts-bedrock): the in-repo developer book, covering interface documentation, architecture, and contract policies. * [Deposits specification](https://specs.optimism.io/protocol/deposits.html): the normative definition of the deposit path the L1 contracts implement. * [Withdrawals specification](https://specs.optimism.io/protocol/withdrawals.html): the normative definition of the withdrawal path. * [Predeploys specification](https://specs.optimism.io/protocol/predeploys.html): the normative definition of the L2 predeploy contracts. # op-deployer Source: https://docs.optimism.io/op-stack/components/op-deployer Canonical hub for op-deployer, the OP Stack chain deployment tool, covering what it does, who runs it, and where its guides, reference, releases, and source live. op-deployer is the OP Stack's chain deployment tool: a CLI that deploys the L1 smart contracts for new OP Stack chains, driven by a declarative configuration file. ## Overview op-deployer reads an *intent* file describing a chain's desired configuration and makes the minimum set of smart contract calls required to make the deployment match it. It is distributed as a standalone binary with no additional dependencies, its configuration is optimized for deploying Standard OP Chains, and it exposes lower-level primitives and Go libraries for more complex setups. Its `upgrade` and `manage` commands are deprecated; see the [deprecation notice](/notices/archive/op-deployer-upgrade-deprecation) for the supported upgrade paths and alternatives. It exists because deploying an OP Stack chain means deploying a large, interdependent set of L1 contracts at specific supported versions. op-deployer turns that into a declarative, repeatable process, and each of its releases maps to the contract releases it supports. **Who runs it:** chain operators and developers deploying chains. It runs on demand, from a workstation, in CI pipelines, or inside local development environments; it is not a long-running service. Unlike most components, op-deployer already has a full documentation set on this site, under [OP Deployer](/chain-operators/tools/op-deployer/overview) in the Chain Operators tab; this hub routes into it. ## Get started * [Deploy L1 contracts with op-deployer](/chain-operators/tutorials/create-l2-rollup/op-deployer-setup): install op-deployer, prepare your environment, and deploy a chain's L1 contracts as the first step of standing up an OP Stack chain. To install the binary on its own, see [Install op-deployer](/chain-operators/tools/op-deployer/installation). ## How-tos * [Custom deployments](/chain-operators/tools/op-deployer/usage/custom-deployments): manage deployments that depart from the standard configuration. * [Release workflows](/chain-operators/tools/op-deployer/usage/release-workflows): backport fixes onto earlier op-deployer versions and add support for new contract versions. * [Upgrade L1 contracts using op-deployer](/chain-operators/tutorials/l1-contract-upgrades/op-deployer-upgrade): version availability and migration paths for the deprecated `upgrade` command, which supports upgrades only up to `op-contracts/v5.0.0`. For later upgrades, see the [deprecation notice](/notices/archive/op-deployer-upgrade-deprecation). ## Configuration & flags reference * Command reference: [init](/chain-operators/tools/op-deployer/usage/init), [apply](/chain-operators/tools/op-deployer/usage/apply), [bootstrap](/chain-operators/tools/op-deployer/usage/bootstrap), and [verify](/chain-operators/tools/op-deployer/usage/verify) document each command's flags and the intent file settings. * [Artifacts locators](/chain-operators/tools/op-deployer/reference/artifacts-locators): how op-deployer points at contract artifacts. * [Known limitations](/chain-operators/tools/op-deployer/known-limitations): current limitations and their workarounds. ## Releases * [op-deployer release history](/releases/op-deployer) * [OP Deployer releases reference](/chain-operators/tools/op-deployer/reference/releases): which op-deployer version supports which contract release. ## Source & spec links * [Source: `op-deployer/`](https://github.com/ethereum-optimism/optimism/tree/develop/op-deployer) in the Optimism monorepo; its [README](https://github.com/ethereum-optimism/optimism/blob/develop/op-deployer/README.md) declares this documentation set as its source of truth. * [Architecture reference](/chain-operators/tools/op-deployer/reference/architecture/overview): op-deployer's internals, including its deployment pipeline and execution engine. * op-deployer is deployment tooling and has no section of its own in the OP Stack specifications; the standard chain configuration it deploys is specified in [OP Stack Configurability](https://specs.optimism.io/protocol/configurability.html). # op-node Source: https://docs.optimism.io/op-stack/components/op-node Canonical hub for op-node, the OP Stack rollup node in Go, covering what it does, who runs it, and where its guides, reference, releases, source, and spec live. op-node is the OP Stack's consensus-layer client, written in Go: the rollup node that derives the canonical L2 chain from L1 data and drives an execution client to process the resulting blocks. ## Overview op-node builds, relays, and verifies the canonical chain of L2 blocks. As a sequencer it builds new blocks; as a verifier it derives blocks from the data the chain posted to L1 and accepts only blocks that can be reproduced from that data. The blocks themselves are executed by an execution client, such as op-reth, which op-node controls through the Engine API; the two run in a one-to-one pairing. op-node also relays the sequencer's new (unsafe) blocks over a P2P network for low-latency access to the latest state; the relay is optional and never affects the ability to verify. It exists because an OP Stack chain is *derived*: the canonical chain is defined by data available on L1, and the rollup node is the component that turns that data into verified L2 blocks. It plays the role a beacon node plays on L1, and it implements the rollup node specification. **Who runs it:** every node operator. Each OP Stack node pairs a rollup node, op-node or [kona-node](/releases/kona-node) (the Rust implementation of the same role), with an execution client. Chain operators additionally run op-node in sequencer mode to build new blocks. ## Get started * [Running a Node With Docker](/node-operators/tutorials/node-from-docker): run op-node and op-reth from the official Docker images. To build and run from source instead, see [Building and running an OP Stack node from source](/node-operators/tutorials/run-node-from-source). ## How-tos * [Consensus client configuration](/node-operators/guides/configuration/consensus-clients): configure op-node (or kona-node) and connect it to your execution client. * [Fetch blob data for your node](/node-operators/guides/management/blobs): give op-node the L1 beacon endpoint it needs to fetch blob batch data, including blobs older than the beacon retention window. * [Node troubleshooting](/node-operators/guides/troubleshooting): solutions to common node problems, many of them surfaced in op-node logs. ## Configuration & flags reference * [op-node configuration options](/node-operators/reference/op-node-config): every CLI flag and environment variable, with flag tables generated from the op-node release named on the page. * [op-node JSON-RPC API](/node-operators/reference/op-node-json-rpc): the rollup-specific RPC methods op-node serves. ## Releases * [op-node release history](/releases/op-node) ## Source & spec links * [Source: `op-node/`](https://github.com/ethereum-optimism/optimism/tree/develop/op-node) in the Optimism monorepo; its [README](https://github.com/ethereum-optimism/optimism/blob/develop/op-node/README.md) documents the quickstart, design principles, and failure modes (L1 downtime, L1 reorgs, sequencer window expiry, and more). * [Rollup node specification](https://specs.optimism.io/protocol/rollup-node.html): the normative definition of the rollup node's role. * [L2 chain derivation specification](https://specs.optimism.io/protocol/derivation.html): the normative definition of how the canonical L2 chain is derived from L1 data. # op-proposer Source: https://docs.optimism.io/op-stack/components/op-proposer Canonical hub for op-proposer, the OP Stack output proposer, covering what it does, who runs it, and where its guides, reference, releases, source, and spec live. op-proposer is the OP Stack's output proposer: the service that submits output roots, claims about the L2 chain's state, to L1 so that withdrawals can be proven against them. ## Overview op-proposer queries its rollup node for an output root (a commitment to the L2 state at a given block) and submits it to L1 on a configured interval. On a chain running fault proofs, each proposal is a transaction to the `DisputeGameFactory` that creates a new dispute game: a claim that stands unless successfully challenged. By default op-proposer proposes only finalized L2 state, because a proposal of state that does not hold true later is an invalid claim that carries dispute game penalties. (A pre-fault-proof proposal path still exists in the code but is effectively unused.) It exists because proposals are how L1 learns about L2 state: withdrawals are authenticated against resolved proposals, so a user proves a withdrawal against a proposed output root and finalizes it once that proposal's dispute game resolves in its favor. Without op-proposer, no new output roots reach L1 and withdrawals cannot be proven. **Who runs it:** the chain operator, as one of the chain's core services. On chains with permissioned fault proofs, only the designated [proposer role](/op-stack/protocol/privileged-roles) can submit proposals; with [permissionless fault proofs](/op-stack/fault-proofs/explainer) anyone can propose, but the operator still runs op-proposer so proposals land regularly. ## Get started * [Spin up proposer](/chain-operators/tutorials/create-l2-rollup/op-proposer-setup): set up and configure op-proposer as part of standing up an OP Stack chain. ## How-tos * [Migrating to permissionless fault proofs](/chain-operators/tutorials/migrating-permissionless): configure the dispute components and switch the respected game type. * [Switch to Kona proofs](/chain-operators/guides/features/switching-to-kona-proofs): move a chain to Kona-based fault proofs, including updating the game type op-proposer creates. ## Configuration & flags reference * [Proposer configuration](/chain-operators/guides/configuration/proposer): every configuration option and environment variable, plus the proposer policy constraints that govern what gets proposed and when. ## Releases * [op-proposer release history](/releases/op-proposer) ## Source & spec links * [Source: `op-proposer/`](https://github.com/ethereum-optimism/optimism/tree/develop/op-proposer) in the Optimism monorepo; its [README](https://github.com/ethereum-optimism/optimism/blob/develop/op-proposer/README.md) documents the proposal flow (with a sequence diagram), design principles, and failure modes. * [L2 output root proposals specification](https://specs.optimism.io/protocol/proposals.html): the normative definition of output-root proposals. * [Withdrawals specification](https://specs.optimism.io/protocol/withdrawals.html): how withdrawals are proven against proposals. # op-reth Source: https://docs.optimism.io/op-stack/components/op-reth Canonical hub for op-reth, the OP Stack execution client built on reth, covering what it does, who runs it, and where its guides, reference, releases, source, and spec live. op-reth is the OP Stack's execution-layer client, written in Rust and built on [reth](https://github.com/paradigmxyz/reth): it executes the L2 blocks the rollup node derives and maintains the resulting chain state. ## Overview op-reth provides the EVM execution environment for OP Stack chains. A rollup node ([op-node](/op-stack/components/op-node) or [kona-node](/op-stack/components/kona-node)) derives the canonical chain from L1 data and drives op-reth through the Engine API; op-reth executes the payloads, maintains the chain state, and serves JSON-RPC. It extends upstream reth with the OP Stack protocol changes, such as the deposit transaction type and L2 fee handling, and bakes the [Superchain Registry](https://github.com/ethereum-optimism/superchain-registry)'s chain configurations into the binary, so registry chains work by name via the `--chain` flag. It exists because every OP Stack node splits into a consensus half and an execution half, mirroring post-merge Ethereum, and the execution client is the half that runs the EVM. op-reth is the primary supported execution client and the implementation maintained by Optimism: new OP Stack feature development, including hardfork support, happens on op-reth. See [Choose your node stack](/use-cases/choose-your-node-stack) for the selection reasoning. **Who runs it:** every node operator, paired one-to-one with a rollup node. Chain operators run it as the execution half of their sequencer, where it builds the new blocks the sequencing rollup node requests. ## Get started * [Running a Node With Docker](/node-operators/tutorials/node-from-docker): run op-reth and op-node from the official Docker images. To build and run from source instead, see [Building and running an OP Stack node from source](/node-operators/tutorials/run-node-from-source). ## How-tos * [Execution client configuration](/node-operators/guides/configuration/execution-clients): install op-reth, connect it to your consensus client, and set the OP Stack specific rollup flags. * [Sync OP Mainnet](/node-operators/op-reth/run/faq/sync-op-mainnet): import Bedrock state and sync OP Mainnet from scratch. * [Building an archive node](/node-operators/guides/management/archive-node): archive versus full nodes, and how to prune op-reth safely. * [Running op-reth with historical proofs](/node-operators/tutorials/reth-historical-proofs): provision the historical proof store that fault-proof infrastructure needs. ## Configuration & flags reference * [op-reth configuration options](/node-operators/reference/op-reth-config): routes to the imported op-reth CLI reference, versioned with the op-reth source tree. * [Understanding the op-reth CLI](/node-operators/op-reth/cli/overview): how the commands, chain selection, and configuration model fit together. * [op-reth JSON-RPC reference](/node-operators/reference/op-reth-json-rpc): the RPC namespaces op-reth serves. ## Releases * [op-reth release history](/releases/op-reth) ## Source & spec links * [Source: `rust/op-reth/`](https://github.com/ethereum-optimism/optimism/tree/develop/rust/op-reth) in the Optimism monorepo. * [Reth book, OP Stack chapter](https://reth.rs/run/opstack): the upstream reth project's operational documentation, maintained with reth releases. * [L2 execution engine specification](https://specs.optimism.io/protocol/exec-engine.html): the normative definition of the OP Stack's changes to the execution engine. * [Deposits specification](https://specs.optimism.io/protocol/deposits.html): the normative definition of the deposit transaction type op-reth implements. # proxyd Source: https://docs.optimism.io/op-stack/components/proxyd Canonical hub for proxyd, the RPC request router and proxy, covering what it does, who runs it, and where its guide, configuration, releases, and source live. proxyd is the OP Stack's RPC request router and proxy: a daemon that fronts a fleet of backend nodes and presents them to clients as one reliable RPC endpoint. ## Overview proxyd whitelists RPC methods, routes them to groups of backend services, automatically retries failed backend requests, load-balances across backends, caches immutable responses, and exposes metrics for request latency, error rates, and backend health. In consensus-aware mode it additionally tracks each backend's `latest`, `safe`, and `finalized` blocks, resolves a consensus group of healthy backends, and rewrites requests and responses to enforce that consensus, so clients see a consistent view of the chain and experience fewer reorgs. It exists because serving production RPC traffic from a single node is fragile: one crashed, forked, or lagging backend becomes user-visible downtime. proxyd turns a pool of replicas into a fault-tolerant serving layer. It is infrastructure around the chain, not a protocol component. **Who runs it:** chain operators and RPC providers serving public or internal RPC from a pool of replica nodes. It is also the recommended front for a high-availability pool of op-supernode instances. ## Get started * [Run proxyd](/chain-operators/tools/proxyd): build the binary, create a configuration file, and start the service. ## How-tos * [Network architecture](/chain-operators/guides/management/network-architecture): where proxyd sits in a production topology, including running public RPC behind proxyd in consensus-aware routing mode. * [Supernode configuration](/node-operators/guides/configuration/supernode): front a high-availability pool of op-supernode instances with a consensus-aware proxyd. ## Configuration & flags reference proxyd is configured through a TOML file rather than CLI flags, and no generated configuration reference exists on this site yet. * [example.config.toml](https://github.com/ethereum-optimism/infra/blob/main/proxyd/example.config.toml): the full list of options, with commentary, in the proxyd source. * The [proxyd guide](/chain-operators/tools/proxyd) documents the consensus-awareness, caching, and metrics settings. ## Releases * [proxyd release history](/releases/proxyd) ## Source & spec links * [Source: `proxyd/`](https://github.com/ethereum-optimism/infra/tree/main/proxyd) in the Optimism infra repository, the monorepo's extension repository for ecosystem infrastructure; its [README](https://github.com/ethereum-optimism/infra/blob/main/proxyd/README.md) documents the request lifecycle, WebSocket support, and consensus awareness. * proxyd is RPC infrastructure and has no section of its own in the OP Stack specifications. # Choose a content type Source: https://docs.optimism.io/op-stack/contribute/choose-a-content-type A maintainer-facing decision table for picking the right documentation type, composition, and operational metadata. This page is for docs maintainers and contributors, not readers. It settles the two questions that come up in almost every content pull request — "which kind of page am I writing?" and "which frontmatter does it carry?" — by decision table, so the answer is cited rather than re-argued per PR. The pattern follows Cloudflare's maintainer-facing content-type selection page in its [documentation content strategy](https://developers.cloudflare.com/style-guide/documentation-content-strategy/). Before choosing a type, check the [content guide](/op-stack/contribute/content-guide) that the content belongs on docs.optimism.io at all. ## The taxonomy: four quadrants, four compositions Documentation pages on docs.optimism.io carry a `diataxis:` frontmatter key with one of the four [Diátaxis](https://diataxis.fr/) quadrant values — `tutorial`, `how-to`, `reference`, or `explanation`. That taxonomy is complete and does not grow: the composed types below are **compositions of the quadrants, not new quadrants**, and they never appear as `diataxis:` values. A composed type is declared with a second, optional frontmatter key, `content-type:`, carried *alongside* `diataxis:`. It takes exactly four values, one per published spec: | Composed type | `content-type:` | `diataxis:` | What the composition is | | ----------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | [Solution guide](/op-stack/contribute/solution-guide) | `solution-guide` | `how-to` | A goal-scoped how-to at journey altitude: it sequences existing pages across quadrants and adds only the connective decision logic | | [Learning unit](/op-stack/contribute/learning-unit) | `learning-unit` | The underlying page's quadrant (usually `explanation`; `tutorial` for hands-on stops) | A thin sequencing layer over one existing page inside an ordered track | | [Curriculum hub](/op-stack/contribute/curriculum-hub) | `curriculum-hub` | `explanation` | An oriented index that composes all four quadrants for one feature under one sidebar node | | [Router/landing](/op-stack/contribute/router-landing) | `router-landing` | Omitted — see below | Pure navigation: the page only routes readers to pages in the quadrants | Rules that keep this an extension rather than a fork: * **`content-type:` never replaces `diataxis:`.** Every page that documents, instructs, or explains anything keeps its quadrant tag. The one sanctioned omission is `content-type: router-landing`: a pure router contains no documentation mode of its own to classify, so it carries `content-type:` and no `diataxis:` key. If a router grows explanatory or instructional content, it is no longer a router — reclassify it. * **Only these four `content-type:` values exist.** Proposing a fifth means amending this page and publishing a spec for it, through normal docs review. * **Pages of the four base types don't carry `content-type:` at all.** An ordinary how-to is just `diataxis: how-to`. * **`keywords.config.yaml` is not extended for composed types.** The composed types are declared only in page frontmatter, per the rows above. ### Notice metadata A [notice](/op-stack/contribute/notice) is time-bound operational content for an upgrade, deprecation, or other change that requires readers to prepare. Its dominant reader need is authoritative information about a specific change, so a notice carries `diataxis: reference`. The additional `content_type: notice` metadata key (with an underscore) marks the page's operational purpose and lifecycle for the notice index and site search. It does not create a fifth quadrant or composition. The `content-type:` key (with a hyphen) remains limited to the four composition values above. Use a notice when the page must answer all of these questions: * What is changing and why? * Which personas are affected, and what breaks or remains compatible for each one? * What must each affected reader do before the cutover? * When and how does the change take effect? After the change is complete, archive the notice and move durable facts into the relevant guide, reference, or [network upgrade registry](/op-stack/protocol/network-upgrades). ## How-to guide vs. tutorial vs. solution guide These three are confusable because all three are action-oriented. The distinctions are the starting state, the scope, and who owns the steps. | Question | How-to guide | Tutorial | Solution guide | | ------------------------------------ | ------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | | What state does the reader start in? | A working environment, already set up | A clean machine (or close to it) — setup is part of the page | A working system, plus a goal that spans components | | How wide is the scope? | One discrete task on one component | One end-to-end build, environment setup included | One goal across multiple components, often multiple documentation properties | | Who owns the steps? | The page owns its steps | The page owns its steps | The page **derives**: each stop links an existing page and states what to extract; the page adds only decision logic | | What does it end with? | Verification of the task | Verification of the whole working state, then cleanup | Verification of the outcome, then curated next steps | | Frontmatter | `diataxis: how-to` | `diataxis: tutorial` | `diataxis: how-to` + `content-type: solution-guide` | Quick tests: * If the page must install or configure the environment before the real work starts, it's a **tutorial**. * If the page's steps are its own — copy-pasteable commands the reader executes on one component — it's a **how-to guide**. * If the page's main job is sequencing *other* pages toward a goal and deciding between options along the way, it's a **solution guide**. A solution guide that starts restating the steps of the pages it links is violating the [dual-sourcing ban](/op-stack/contribute/content-guide#link-dont-restate-the-dual-sourcing-ban) — cut the restatement and link. Exemplars: [Configure the batcher](/chain-operators/guides/configuration/batcher) (how-to at configuration-guide depth); [Bridging your ERC-20 token](/app-developers/tutorials/bridging/cross-dom-bridge-erc20) (tutorial); the first solution guide ships with the Use Cases section — until it lands, the [solution guide spec](/op-stack/contribute/solution-guide) carries the template. ## Explanation vs. learning unit Both are understanding-oriented. The distinction is who the reader is and what the page may assume. | Question | Explanation | Learning unit | | --------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | Who arrives? | Anyone, in any order, usually from search or a cross-link | A learner progressing through an ordered track or curriculum hub | | What may it assume? | Only what it states in its own intro | Everything covered by the previous stops in its track | | Who owns the content? | The page owns its conceptual material | The unit **frames** existing material: it adds sequencing context (what you now know, what this stop adds, where to go next) and links, never forks | | Frontmatter | `diataxis: explanation` | The underlying page's quadrant + `content-type: learning-unit` | Quick tests: * If removing the page from its nav group would leave it fully comprehensible, it's an **explanation**. * If the page opens with "in the previous stop…" or only makes sense at position N of a sequence, it's a **learning unit**. * If you're about to *copy* an explanation into a track so you can reorder it — stop. Learning units link and frame; they never duplicate. Add a framing header to the existing page instead (see the [learning unit spec](/op-stack/contribute/learning-unit)). Exemplars: [The OP Stack](/op-stack/introduction/op-stack) and the [fault proofs explainer](/op-stack/fault-proofs/explainer) (explanations that would gain learning-unit framing inside a track without being rewritten). ## Next steps * Read the type spec before writing the page: [solution guide](/op-stack/contribute/solution-guide), [learning unit](/op-stack/contribute/learning-unit), [curriculum hub](/op-stack/contribute/curriculum-hub), [router/landing](/op-stack/contribute/router-landing), or [notice](/op-stack/contribute/notice). * For the four base quadrants, the [style guide's content types section](https://github.com/ethereum-optimism/optimism/blob/develop/docs/public-docs/STYLE_GUIDE.md#content-types) remains the reference. * For what belongs on the site at all, see the [content guide](/op-stack/contribute/content-guide). # Component hub template Source: https://docs.optimism.io/op-stack/contribute/component-hub-template The uniform skeleton every OP Stack component hub page follows, with guidance for each section. Every component listed in the [Stack Components](/op-stack/components/index) section gets exactly one identity page — its **hub** — and every hub follows the same skeleton. Structural uniformity is the point: a reader who has used one hub knows where to look on every other hub, and reviewers can check a new hub against this template mechanically, section by section. The pattern follows Cloudflare's [documentation content strategy](https://developers.cloudflare.com/style-guide/documentation-content-strategy/), which gives every product's documentation set the same shape and documents each product in a single canonical place. ## The skeleton A hub page contains these sections, in this order, using these exact H2 headings: ```mdx theme={null} --- title: description: diataxis: explanation --- ## Overview ## Get started ## How-tos ## Configuration & flags reference ## Releases ## Source & spec links ``` ## Section guidance Hubs are thin identity-and-links pages, not content pages. They follow the [content guide](/op-stack/contribute/content-guide)'s dual-sourcing ban: wherever a canonical source exists — a guide, a reference page, a spec section, an in-repo document — the hub links it and never restates it. ### Overview Answer three questions in at most a few short paragraphs: **what** the component does, **why** it exists (what breaks without it), and **who runs it** (chain operators, node operators, dispute participants, nobody directly). Volatile facts — versions, activation dates, flag defaults — do not belong here; they live in generated or source-linked pages. ### Get started Exactly one canonical starting point. If a tutorial exists on this site, link it. If the component's only setup documentation is its in-repo README, link that and say so. ### How-tos Link the task guides on this site that configure or operate the component. Do not summarize them — one line per link describing the task. ### Configuration & flags reference Link the component's configuration reference page. While these pages are hand-maintained, note the release they were written against (the reference page itself carries that provenance). When a generated reference exists, this slot points at the generated page instead — the hub does not change shape. If no reference page exists yet, link the component's `--help` surface via its README and say the docs reference is pending. ### Releases Link the component's page under [Releases](/releases) when it has one, otherwise the component's release tags on GitHub. ### Source & spec links Always in this order, when they exist: 1. The source directory in the monorepo (or the component's home repository). 2. In-repo deep documentation (design docs, runbooks) worth surfacing. 3. The component's section of the [OP Stack specifications](https://specs.optimism.io/) — deep-link the exact page, never the spec root. ## What hubs are not * **Not a second guide.** If you find yourself writing instructions, that content belongs in a how-to page the hub links. * **Not a reference.** No flag tables, no RPC methods, no version matrices. * **Not a news page.** Release announcements live on the releases pages. Questions about a hub that this template does not settle go through the [content guide](/op-stack/contribute/content-guide)'s canonical-home matrix; if the matrix does not cover the case either, raise it in the docs PR. # Content guide Source: https://docs.optimism.io/op-stack/contribute/content-guide What content belongs on docs.optimism.io, the canonical home for each content type, and how to mark third-party content. This page defines what content belongs on docs.optimism.io and, for every content type, which source is canonical. It exists so that "where does this live?" is settled by citing a rule, not re-argued in every pull request. Reviewers should link the relevant section of this page when requesting changes. The approach is adapted from the Kubernetes [content guide](https://kubernetes.io/docs/contribute/style/content-guide/), which governs kubernetes.io with the same two ideas: a short allowlist test for what the site hosts, and a strict preference for linking canonical sources over restating them. ## What's allowed: the three-clause test Content belongs on docs.optimism.io only if at least one of the following is true (adapted from the Kubernetes content guide's third-party content rules): 1. **It documents first-party OP Stack software** — software whose source of truth lives in [Optimism](https://github.com/ethereum-optimism) repositories, such as the components listed on the [Releases](/releases) page. 2. **It documents third-party software that the OP Stack needs to function** — for example, an L1 execution client or key-management tooling that an OP Stack chain cannot run without. Such content must be marked with the [`` component](#marking-third-party-content). 3. **It routes to canonical content that lives elsewhere** — a selection, orientation, or hub page whose job is to send readers to the right canonical home (for example, a curated matrix of SDKs that links each SDK's own documentation). Content that satisfies none of the three clauses — tooling promotion, project-specific marketing, or documentation for software that is neither first-party nor required by the OP Stack — belongs on the third party's own site, not here. ## Link, don't restate: the dual-sourcing ban Wherever a canonical source already exists, **link it — never restate it**. The Kubernetes content guide states the reason plainly: dual-sourced content "requires double the effort to maintain and grows stale more quickly." In practice: * **Never paraphrase normative protocol text.** Explain the concept in your own words at explanation depth, then deep-link the exact section of the [OP Stack specifications](https://specs.optimism.io/) for the normative definition. * **Never copy reference material from another living document.** If a component's book, README, or upstream API reference already documents something, link to it. * **Never fork a table of facts** (versions, addresses, activation times, flag lists) that another system maintains. Render from the source of truth or link it. ## Canonical homes One home per thing. The matrix below assigns a canonical home to each content type across the three layers of the OP Stack documentation surface — the protocol, the components, and the periphery — and states what docs.optimism.io holds for each. | Layer | Content type | Canonical home | What docs.optimism.io holds | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Protocol | Normative protocol behavior | [specs.optimism.io](https://specs.optimism.io/) | Explanation and routing pages that cite the spec with deep links — never restated normative text | | Protocol | Hardfork activations and chain metadata | [superchain-registry](https://github.com/ethereum-optimism/superchain-registry) | Pages rendered from the registry's structured data, joined — not hand-copied | | Components | Concepts, how-tos, and tutorials for running components | docs.optimism.io (full ownership) | The pages themselves, e.g. the [batcher guide](/chain-operators/guides/configuration/batcher) | | Components | Flags and configuration reference | The component's source at a tagged release | A reference page generated from source where a generator exists; otherwise a hand-maintained page pinned to a named release, e.g. the [batcher configuration reference](/chain-operators/reference/batcher-configuration) | | Components | Implementation internals and developer books (e.g. [kona](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona), [op-reth](https://github.com/ethereum-optimism/optimism/tree/develop/rust/op-reth)) | The component's developer documentation, maintained beside its source | Orientation and selection pages that link into the deep material | | Periphery | SDKs and ecosystem tooling (e.g. [viem](https://viem.sh/op-stack), wagmi) | The upstream project's own documentation | One curated hub with a support matrix; every listing marked with `` | Precedents for the matrix, clause by clause: * **Spec joined, never mirrored.** Kubernetes documents feature lifecycles through its structured [feature gates reference](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) rather than copying design documents into prose. * **One identity page per component.** Cloudflare publishes a uniform per-product [content strategy](https://developers.cloudflare.com/style-guide/documentation-content-strategy/) so every product's documentation set has the same shape. * **A curated matrix over the periphery.** Stripe's [SDK page](https://docs.stripe.com/sdks) differentiates its client surfaces in one table; ethereum.org publishes written [listing criteria](https://ethereum.org/en/contributing/adding-products/) so curation is policy application rather than per-PR debate. * **The component declares its docs home.** Each component's README should point at its canonical documentation, following the [op-deployer README](https://github.com/ethereum-optimism/optimism/blob/develop/op-deployer/README.md) model. When two pages could both claim a topic, the matrix decides. If the matrix does not cover the case, raise it in the docs PR and propose a new row — amendments to this page go through the same review as any other docs change. ## Marking third-party content This section documents the `` component, following the Kubernetes [`thirdparty-content` shortcode](https://kubernetes.io/docs/contribute/style/content-guide/) pattern: every third-party mention is stamped the same way, so third-party content stays greppable and auditable. Pages or sections that document or list third-party software (clauses 2 and 3 of the [three-clause test](#whats-allowed-the-three-clause-test)) must open with the `` component: ```mdx theme={null} import ThirdPartyContent from "/snippets/third-party-content.mdx" ``` Which renders: Items on this page refer to third-party projects or products that are not maintained by Optimism. They are provided for convenience; refer to each project's own documentation as the source of truth. When an entire page is about a single third-party project or product, use the single-project variant instead: ```mdx theme={null} import ThirdPartyContentSingle from "/snippets/third-party-content-single.mdx" ``` Which renders: This page refers to a third-party project or product that is not maintained by Optimism. It is provided for convenience; refer to the project's own documentation as the source of truth. ## Citing the normative spec This section documents the `` component, the standing callout that applies the [dual-sourcing ban](#link-dont-restate-the-dual-sourcing-ban) to protocol pages: every page whose subject is normatively defined in the [OP Stack specifications](https://specs.optimism.io/) is stamped the same way, so spec citations stay uniform and greppable. The component is **reserved for explainer pages** — pages whose frontmatter declares `diataxis: explanation`, primarily the concept pages in the OP Stack section. An explainer page whose subject is normatively defined in the spec must open with the `` component, deep-linking the exact spec section that defines its subject: ```mdx theme={null} import { NormativeSpec } from "/snippets/normative-spec.mdx" ``` Which renders: All four variables are required: `what` names the subject the spec defines, `title` and `href` name and deep-link the governing spec section (a rendered `specs.optimism.io` URL on its current path, per the [link policy](/op-stack/contribute/link-policy)), and `note` states what the page does instead of restating the spec. Guides, tutorials, and reference pages do **not** open with the component. They should not go deep into protocol workings at all — that depth belongs on an explainer page or in the spec itself. Where a guide, tutorial, or reference page needs to touch a spec-defined concept, link the relevant spec section inline at the point of use instead. One deliberate exception: the [hardfork registry pages](/op-stack/protocol/network-upgrades) are reference pages, but the registry's purpose is the spec pointer, so they carry the same component with the spec URL from their structured frontmatter. ## Next steps * Read the [style guide](/op-stack/contribute/style-guide) for voice, tone, and formatting conventions. * Read the [contributing guide](https://github.com/ethereum-optimism/optimism/blob/develop/docs/public-docs/DOCS_CONTRIBUTING.md) for development setup and the pull request process. * Have questions? Open an issue in the [Optimism monorepo](https://github.com/ethereum-optimism/optimism/issues). # Curation review policy Source: https://docs.optimism.io/op-stack/contribute/curation-policy The review cadence for curated pages, the last-reviewed frontmatter contract, the sweep that keeps curated content fresh, and the rule for delisting what rots. Some pages in these docs are **curated artifacts**: they do not document one component, they select, sequence, or recommend across many. A solution guide is a chain of links and decisions; a router page is a set of chosen entry points; a selection page compares options that keep evolving. Curated content is the most valuable kind of page and the fastest to rot, because nothing breaks when it goes stale. This page is the standing policy that keeps it fresh. ## What counts as a curated artifact Any page whose main job is choosing or sequencing rather than documenting: * **Solution guides** (`content-type: solution-guide`), each a chain of links plus decision tables. * **Router and landing pages** (`content-type: router-landing`), including the section indexes that choose what to surface. * **Curriculum hubs and learning-track indexes** (`content-type: curriculum-hub`), which sequence existing pages into a path. * **Selection and comparison pages**: any page presenting dated facts about alternatives (client choices, tool matrices). * **Prompt libraries and AI onboarding pages**: curated prompts and integration instructions that reference specific product surfaces. Ordinary tutorials, how-to guides, reference pages, and explanations are not curated artifacts; they are maintained by the normal review flow for their component. ## The `last-reviewed:` contract Every curated artifact carries a review stamp in its frontmatter: ```yaml theme={null} last-reviewed: YYYY-MM-DD ``` The stamp means: on that date, a reviewer confirmed the page's links resolve, its load-bearing claims still match source, and its recommendations are still the ones we would make. It is set on merge for a new page and bumped only by a review that actually re-verified the page, never by an unrelated edit passing through. The frontmatter is deliberately greppable so staleness is checkable mechanically: ```bash theme={null} # from docs/public-docs/ grep -rn "last-reviewed:" --include="*.mdx" . ``` ## Sweep intervals by artifact class | Artifact class | Sweep interval | Rationale | | ------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------ | | Solution guides, selection and comparison pages | 90 days | They carry decision logic and version-sensitive facts; a stale recommendation misleads directly. | | Prompt libraries and AI onboarding pages | 90 days | They name concrete product surfaces (URLs, server endpoints) that change without notice. | | Router/landing pages, curriculum hubs, learning-track indexes | 180 days | They mostly sequence links; the linked pages carry their own accuracy burden. | A page past its interval is not automatically wrong, but it is unverified, and unverified curation is treated as a defect: it goes to the front of the next sweep. ## What a sweep does Each sweep pass picks the curated artifact whose `last-reviewed:` is oldest relative to its class interval and re-verifies it: 1. **Chain integrity**: every link on the page resolves, including the off-site exits, per the [link policy](/op-stack/contribute/link-policy). For solution guides this covers the whole chain the guide sequences, not just the guide page: one dead link breaks the paved path. 2. **Load-bearing claims**: defaults, thresholds, version numbers, and "as of" markers are re-checked against source, and every "as of" date is either re-confirmed (and re-dated) or the claim is corrected. 3. **The stamp**: `last-reviewed:` is bumped to the sweep date in the same change, so the stamp and the verification never drift apart. Sweeps run as scheduled, review-gated docs automation, with the results landing as ordinary reviewable pull requests; a human still owns every merge. ## The delisting rule Curated pages recommend things, and a recommendation we can no longer stand behind is removed, not hedged: * If a sweep finds a curated entry (an exit link, a listed tool, a recommended option) that is dead, deprecated, or no longer something the docs would recommend, the entry is **removed or replaced in that sweep's change**, not annotated with a warning and left in place. * If an entire curated page can no longer be verified (its subject was deprecated, its journey no longer exists), the page is removed from the nav and redirected per the [redirects guidance](https://github.com/ethereum-optimism/optimism/blob/develop/docs/public-docs/REDIRECTS_GUIDE.md), with the removal recorded in the pull request. Listing is a maintenance commitment: a curated entry that nobody re-verifies on schedule loses its place. This is the same bargain the [content guide](/op-stack/contribute/content-guide) makes for canonical homes, applied to curation. ## Adding a new curated page A new curated artifact enters the rotation on merge: 1. Carry `last-reviewed:` set to a date within its review cycle (normally the merge date) plus the `content-type:` its [content-type contract](/op-stack/contribute/choose-a-content-type) requires. 2. Its pull request states the artifact class, so reviewers know which interval it signed up for. 3. No exemptions: a curated page that cannot commit to its class's sweep interval should not ship as a curated page. # Content type: curriculum hub Source: https://docs.optimism.io/op-stack/contribute/curriculum-hub The published contract for curriculum hubs — purpose, tone, required components, title grammar, and a copy-paste template. A **curriculum hub** gathers everything a reader needs to master one feature — fault proofs, interop — under a single sidebar node, ordered from gentle introduction to normative spec. It is the answer to "I want to actually understand X": one place, one reading order, all four documentation modes composed for one topic. This page is the contract for the type. A new curriculum hub is reviewed against it; cite the relevant section in review instead of re-arguing it. ## Purpose * Give each major feature **one front door** with a recommended reading order, instead of pages scattered across nav groups. * **Compose, don't rewrite**: the hub resequences existing pages and adds at most a few short learning-unit pages where the sequence has a gap. * Make the exits explicit: every hub ends at the **normative spec** (and audits, where they exist) so depth-seekers are routed off-site on purpose, never stranded. ## Composition A curriculum hub composes all four quadrants for one feature: explanation (the gentle intro and deep dives), tutorial/how-to (the hands-on stops), reference (component and configuration pages), and the spec exit. The hub's index page carries `diataxis: explanation` (it orients the reader in the feature) plus `content-type: curriculum-hub`. Stops inside the hub keep their own quadrant values; new gap-filling stops follow the [learning unit contract](/op-stack/contribute/learning-unit). See [Choose a content type](/op-stack/contribute/choose-a-content-type) for how the composed types relate to the `diataxis:` taxonomy. ## Tone * The index page orients: what the feature is, why it matters, and how the materials fit together — in a few short paragraphs, not an essay. * Every listed stop gets a one-line reason ("read this to …"), written for the learner deciding whether to click, not as a summary. * Confidence about order, honesty about depth: say what is skippable and what is normative. ## Required components Every curriculum hub must have: 1. **One sidebar node**: the hub is a single nav group; a hub that spans groups has failed its purpose. 2. **An index page** with frontmatter `title`, `description`, `diataxis: explanation`, `content-type: curriculum-hub`, and `last-reviewed: YYYY-MM-DD` (hubs are curated artifacts and enter the review sweep on merge). 3. **An ordered path** on the index, in this shape (sections may be merged or omitted only where the feature genuinely lacks the material): * `## Start here` — the gentle introduction. * `## Go deeper` — mechanism and architecture material. * `## Get hands-on` — the tutorials and how-tos, where they exist. * `## Economics and incentives` — where the feature has them. * `## The normative spec` — deep links into [specs.optimism.io](https://specs.optimism.io/) on **current spec paths** (never retired path generations), per the [content guide](/op-stack/contribute/content-guide). * `## Audits and security` — where audits exist. 4. **One-line reasons** on every link. 5. **No duplicated content**: the hub links existing pages; a stop needing rework gets an issue, not a fork. Gap-filling stops are new [learning units](/op-stack/contribute/learning-unit), capped at a few per hub. ## Title grammar The hub's nav group and index title are the feature's plain name in sentence case: "Fault proofs", "Interoperability". No "hub", "curriculum", "guide to", or "learn" in the title — the shape is visible from the sidebar; the name should match what readers search for. ## Template Copy this template for a new hub's index page: ```mdx theme={null} --- title: description: diataxis: explanation content-type: curriculum-hub last-reviewed: --- is, why it matters to this audience, and how the materials below fit together.> ## Start here * []() — read this first for the mental model. ## Go deeper * []() — . * []() — . ## Get hands-on * []() — . ## Economics and incentives * []() — . ## The normative spec The definitive definition of behavior lives in the OP Stack specifications: * [](https://specs.optimism.io/) — . ## Audits and security * []() — . ``` ## Exemplars Calibrate against the shipped hubs: * [Fault proofs](/op-stack/fault-proofs/index): the first shipped hub, sequencing the six existing fault-proofs pages plus the hands-on guides, bond economics, spec exits, and security material. * [Interoperability](/op-stack/interop/index): the second shipped hub, which shows how to frame a hub honestly for a feature still in active development. # Contribute to the docs Source: https://docs.optimism.io/op-stack/contribute/index The contributor policies and content-type contracts for docs.optimism.io, routed by the task you came to do. This section holds the policies and templates that govern contributions to docs.optimism.io. Each page is a contract: reviewers cite its sections in docs PRs instead of re-arguing them, so read the pages that match what you are about to write. Find the canonical home for what you want to write, and what stays out of the docs entirely. Match the voice, tone, formatting, and naming conventions every page follows. Use the decision table to choose a content type, then follow its published contract and template. Write time-bound, persona-specific upgrade or deprecation guidance from the reusable notice template. Write cross-repo links in the canonical form the link linter enforces. Follow the review cadence, the last-reviewed contract, and the rule for delisting content that rots. Build a new component's identity page against the uniform hub skeleton. Propose changes to the "Learn the OP Stack" track through its governance artifact. Browse the documentation by role: app developer, chain operator, or node operator. # Learn track syllabus Source: https://docs.optimism.io/op-stack/contribute/learn-track-syllabus The governance artifact for the "Learn the OP Stack" track, including its scope contract, curriculum owner, stop list with rationale, design rules, and changelog. This page is the syllabus for the [Learn the OP Stack](/op-stack/learn/index) track: the maintainer-facing record of what the track covers, why each stop sits where it does, who owns the curriculum, and how the track changes. The reader-facing front door is the [track index](/op-stack/learn/index); this page exists so the track has an owner and a change history instead of drifting, following the MDN curriculum pattern of a published syllabus with its own changelog. ## Scope contract The track takes a reader **from newcomer to comfortable**. A finisher has deployed a test chain, followed a transaction from submission to finality on Ethereum, moved assets in both directions between layers, and run a node, and knows where the deeper material lives. Exhaustive detail is out of scope by design: depth lives in the reference sections and the [OP Stack specifications](https://specs.optimism.io/), and the track exits to them. This sentence is the governance model. A proposed stop that adds depth rather than progression fails the scope test, however good the page is; route it through the "After the track" exits on the index instead. ## Ownership * **Curriculum owner:** Matthew Cruz ([@sbvegan](https://github.com/sbvegan)). * The owner arbitrates scope questions, reviews any change to the stop list or its order, and is the named reviewer when the track index comes up in the [curation sweep](/op-stack/contribute/curation-policy) (learning-track indexes sweep on the 180-day interval). * A syllabus change merged without the owner's review is reverted on sight, not debated after the fact. ## The syllabus Thirteen stops: three concept blocks punctuated by three hands-on projects, so each block of ideas is consolidated by using it. Stops are existing pages; the track adds only a framing note per stop, per the [learning unit contract](/op-stack/contribute/learning-unit). | Stop | Page | Kind | What it adds at this position | | ---- | ------------------------------------------------------------------------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------- | | 1 | [The OP Stack](/op-stack/introduction/op-stack) | Concept | The mental model: what the stack is, what it powers, what you can build. | | 2 | [Design philosophy & principles](/op-stack/protocol/design-principles) | Concept | Why the stack is shaped the way it is; vocabulary the rest of the docs assume. | | 3 | [Differences from Ethereum](/op-stack/protocol/differences) | Concept | Grounds "EVM equivalent" before any hands-on work; prevents false transfer from Ethereum experience. | | 4 | [OP Stack components](/op-stack/protocol/components) | Concept | Names the layers and modules the learner is about to deploy in project 1. | | 5 | [Creating your own L2 rollup testnet](/chain-operators/tutorials/create-l2-rollup) | Project | Consolidates part 1: deploy a rollup testnet with op-deployer and start each component just named. | | 6 | [Transaction flow](/op-stack/transactions/transaction-flow) | Concept | Reinterprets the components the learner just ran as stages in one transaction's life. | | 7 | [Transaction fees on OP Mainnet](/op-stack/transactions/fees) | Concept | The fee components of a transaction; the economic consequence of the flow in stop 6. | | 8 | [Deposit flow](/op-stack/bridging/deposit-flow) | Concept | First direction of cross-layer movement: L1-triggered L2 transactions. | | 9 | [Withdrawal flow](/op-stack/bridging/withdrawal-flow) | Concept | Second direction: the initiate, prove, finalize sequence, and why it exists. | | 10 | [Submitting transactions from L1](/app-developers/tutorials/bridging/cross-dom-bridge-eth) | Project | Consolidates part 2: walk a deposit and a withdrawal from code with Viem. | | 11 | [Fault proofs explainer](/op-stack/fault-proofs/explainer) | Concept | Why the withdrawal the learner just proved can be trusted: permissionless proposals and challenges. | | 12 | [OP Stack interoperability explainer](/op-stack/interop/explainer) | Concept | Where the stack is going: a network of chains that feels like a single blockchain. | | 13 | [Running a node with Docker](/node-operators/tutorials/node-from-docker) | Capstone project | Ends the track operating real infrastructure: run a node on a live network with the official images. | ## Design rules 1. **Stops are existing pages, never forks.** A stop that needs rewording gets an issue filed against the page, not a track-local copy. The only track-owned artifacts are the [index](/op-stack/learn/index), this syllabus, and the framing notes. 2. **Framing notes follow the [learning unit contract](/op-stack/contribute/learning-unit)** (framing header form): track name, stop position, one sentence of arrival context, one sentence of what the stop adds, link to the next stop. Nothing else on the page changes. 3. **Cap: 15 stops.** Past that the track has stopped being linear and started being a second navigation; split material into the "After the track" exits instead. 4. **Projects are spaced, not appended.** Each concept block ends in a hands-on stop that uses it (Rust Book cadence). A resequencing that leaves two projects adjacent or a concept block unconsolidated needs the owner's explicit sign-off. 5. **Resequencing procedure:** update the index, renumber every affected framing note ("stop N of M"), verify every next-stop link, and add a changelog entry below. Position lives only in framing notes and the index, never in page titles, so stops can move without retitling. 6. **Every change lands with a changelog entry.** The changelog is the curriculum's memory; an entry states what changed and why, one line each. ## Changelog | Date | Change | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 2026-07-21 | Initial syllabus: 13 stops (three concept blocks, three projects: deploy a chain, bridge both directions, run a node). Curriculum owner: Matthew Cruz ([@sbvegan](https://github.com/sbvegan)). | ## Next steps * Reader-facing front door: [Learn the OP Stack](/op-stack/learn/index). * Framing-note contract: [learning unit](/op-stack/contribute/learning-unit). * Review cadence: [curation review policy](/op-stack/contribute/curation-policy). # Content type: learning unit Source: https://docs.optimism.io/op-stack/contribute/learning-unit The published contract for learning units — purpose, tone, required components, title grammar, and copy-paste templates for both forms. A **learning unit** is one stop in an ordered learning sequence — the "Learn the OP Stack" track or a per-feature curriculum hub. It gives an existing page a place in a syllabus: what the learner already knows on arrival, what this stop adds, and where to go next. Content is linked and framed, never duplicated. This page is the contract for the type. A new learning unit is reviewed against it; cite the relevant section in review instead of re-arguing it. ## Purpose * Let newcomers progress **linearly** through material that was written to be read in any order. * Add **sequencing context only**: orientation, prerequisites-by-position, and a pointer to the next stop. * Protect the underlying pages: a track that needs a page reworded forks nothing — it files an issue against the page itself. ## Composition A learning unit is a composition, not a fifth quadrant. It has two forms: * **Framing header** (the default): a short framing block prepended to an existing page that serves as a track stop. The page keeps its own `diataxis:` value; nothing else about it changes. * **Standalone unit page** (the exception): a new short page written because a sequence needs a stop that no existing page provides (for example, a bridging paragraph between two concepts in a curriculum hub). It carries the quadrant of what it actually is — usually `diataxis: explanation`, or `diataxis: tutorial` for a hands-on stop — plus `content-type: learning-unit`. See [Choose a content type](/op-stack/contribute/choose-a-content-type) for the explanation-vs-learning-unit decision table. ## Tone * Welcoming but not chatty; the learner is mid-sequence, so respect their momentum. * Second person, present tense: "you now know…", "this page adds…". * The frame never editorializes about the underlying page ("this excellent guide…") and never summarizes it — a one-line statement of what the stop adds is the ceiling. ## Required components **Framing header** (on an existing page): 1. An `` block at the top of the page body, below the frontmatter and any existing callouts. 2. Inside it, in order: the track name and stop position ("stop N of M"), one sentence of arrival context (what the learner knows from previous stops), one sentence of what this stop adds, and a link to the next stop (or a completion line on the last stop). 3. Nothing else changes on the page: same `diataxis:` value, same content. **Standalone unit page**: 1. **Frontmatter**: `title`, `description`, `diataxis:` (the quadrant of what the page actually is), `content-type: learning-unit`. 2. **The same framing block** as above, so every stop reads uniformly. 3. **A body that earns its existence**: material no existing page owns. If an existing page covers it, use a framing header on that page instead. 4. **A forward exit**: the last line links the next stop, or the track index on completion. ## Title grammar * A framing header adds **no title** — the underlying page keeps its own. * A standalone unit page titles the concept as a plain noun phrase in sentence case ("Fault proof economics", "From transactions to blocks"). Position ("Part 3:", "Lesson 3") never appears in the title — order lives in the track's nav group and the framing block, so stops can be resequenced without retitling. ## Templates Framing header — copy onto an existing page that becomes a track stop: ```mdx theme={null} ** — stop of .** You've . This page . When you're done, continue to [](). ``` Standalone unit page: ```mdx theme={null} --- title: description: diataxis: explanation content-type: learning-unit --- ** — stop of .** You've . This page . When you're done, continue to [](). ## Next stop Continue to [](), where you'll . ``` ## Exemplars No track is wired yet — the learn track and curriculum hubs consume this contract when they ship. Calibrate against the pages that would become stops, and the external patterns: * [The OP Stack](/op-stack/introduction/op-stack) and the [fault proofs explainer](/op-stack/fault-proofs/explainer) — existing explanations that would gain a framing header, unchanged otherwise. * [Bridging your ERC-20 token](/app-developers/tutorials/bridging/cross-dom-bridge-erc20) — the shape of a hands-on stop (`diataxis: tutorial`). * The [Rust Book](https://doc.rust-lang.org/book/) — the cadence this type exists to reproduce: strictly ordered chapters, hands-on projects spaced through the sequence, depth exiled to reference. # Cross-repo link policy Source: https://docs.optimism.io/op-stack/contribute/link-policy The canonical form for every link from docs.optimism.io into the specs, source repositories, and other pages — and the linter that enforces it. The documentation joins three layers — the [OP Stack specifications](https://specs.optimism.io/), the component source repositories, and these docs — with links. Links rot silently: a retired spec path keeps "working" through a hand-maintained redirect table, a commit-pinned contract link never 404s while teaching a two-generations-old architecture, and a misplaced tracking parameter breaks an anchor without breaking the page. This page defines one canonical form for each link target, and every rule on it is enforced by a deterministic linter (`scripts/lint-link-policy.mjs`). This policy is an annex of the [content guide](/op-stack/contribute/content-guide): the guide decides *where* content lives and when to link instead of restate; this page defines *how* those links must be written. ## Linking the specs **Always link the rendered site, on its current paths.** * Link `https://specs.optimism.io/...`, never a GitHub blob of a file under the specs repo's `specs/` directory — every `specs/**.md` source has a rendered page, and the rendered page is the canonical, navigable form. (GitHub links to non-rendered specs-repo files, such as `book.toml`, are fine.) * Use the page's **current** path. Retired paths (for example `/experimental/fault-proof/...`, now `/fault-proof/...`) survive only through a hand-maintained redirect table in the specs repo's `book.toml` and can disappear without notice. The linter vendors that redirect table and reports the current path to use. * **Deep anchors must resolve.** An anchor like `#frame-format` must match a real heading slug in the target page. The linter resolves every specs anchor against a checkout of the specs source (`--specs-src`), so a heading rename upstream surfaces as a lint failure here instead of a silently dead fragment. ## Query parameters come before the fragment UTM decoration (or any query string) goes **before** the `#fragment`, per the URL standard — a query appended after the fragment becomes part of the fragment, and the anchor never resolves. ```text theme={null} ✅ https://specs.optimism.io/protocol/derivation.html?utm_source=op-docs&utm_medium=docs#frame-format ❌ https://specs.optimism.io/protocol/derivation.html#frame-format?utm_source=op-docs&utm_medium=docs ``` ## Linking source code **Prefer floating links; badge every pin.** * Links that track a branch (`.../blob/develop/...`) are the default: they follow the code and never teach a stale layout. * A link pinned to a commit sha or release tag (`.../blob/v1.1.4/...`, `.../blob/op-contracts/v1.6.0/...`, `.../blob/62c7f3b0.../...`) is allowed **only** when the pin is the point — quoting behavior at a specific release — and it must carry an ``as of `` `` badge on, or immediately adjacent to, the same line: ```mdx theme={null} [OptimismPortal.sol](https://github.com/ethereum-optimism/optimism/blob/op-contracts/v1.6.0/packages/contracts-bedrock/src/L1/OptimismPortal2.sol) (as of `op-contracts/v1.6.0`) ``` The badge tells the reader the link is a snapshot, and tells the maintenance sweep which pins are deliberate. An unbadged pin is presumed to be accidental staleness and fails the linter. ## Internal links * Internal page links are **root-relative**: `/chain-operators/...`, never `./sibling-page` or a bare word. The target page must exist (or be covered by a redirect in `docs.json`). * Static assets are referenced by their on-disk path from the docs root, including the `public/` prefix: `/public/img/...`. ## The linter `scripts/lint-link-policy.mjs` enforces all of the above plus dead-internal-link detection. It is dependency-free and offline-deterministic; Mintlify's `mint broken-links` serves as an advisory second opinion on internal links. ```bash theme={null} # from docs/public-docs/ node scripts/lint-link-policy.mjs --baseline scripts/lint-link-policy.baseline.json # with specs anchor resolution git clone --depth 1 https://github.com/ethereum-optimism/specs.git /tmp/specs node scripts/lint-link-policy.mjs --specs-src /tmp/specs --baseline scripts/lint-link-policy.baseline.json # verify the linter itself against its embedded self-test fixtures node scripts/lint-link-policy.mjs --self-test ``` Violations that predate the linter are recorded in `scripts/lint-link-policy.baseline.json`, so a run flags only **new** violations. The baseline is a burn-down list, not an allowlist: remediation batches shrink it with `--update-baseline`, and pull requests must never grow it. If the linter flags a link you believe is a deliberate exception, raise it in review — do not rebaseline silently. Enforcement runs as a scheduled, review-gated docs automation plus the local runs above; the linter, its baseline, and its embedded self-test fixtures all live under `docs/public-docs/`. # Content type: notice Source: https://docs.optimism.io/op-stack/contribute/notice The published contract for time-bound network notices, including required persona impacts, actions, timing, and a copy-paste template. A **notice** tells affected readers about an upcoming network upgrade, deprecation, or operational change and gives them the actions required to stay compatible. Notices are time-bound: they remain active while readers need to prepare, then move to the notice archive after the change is complete. This page is the contract for the type. Review a new notice against it and cite the relevant section instead of re-arguing the structure in each pull request. ## Composition A notice is `diataxis: reference`: it gives readers authoritative facts about one change, including its scope, compatibility, timing, and affected versions. Put the executable migration procedure in a how-to guide or runbook and link it from the notice. The additional `content_type: notice` metadata key (with an underscore) marks the page's operational purpose and lifecycle. It is not a fifth Diátaxis quadrant or one of the composed documentation types. The similarly named `content-type:` key (with a hyphen) remains reserved for the four compositions in [Choose a content type](/op-stack/contribute/choose-a-content-type). ## Purpose * Name the change, why it is happening, and when it takes effect. * Identify every affected persona and state the breaking changes or explicit no-action outcome for each one. * Give readers an action checklist with versions, configuration, contract, or application changes they can verify before the cutover. * Preserve the transition behavior readers need to know, such as what happens to in-flight withdrawals, disputes, or transactions. Do not use a notice as the permanent explanation of a feature or the only record of an upgrade. Link canonical guides and reference pages for durable details. ## Required frontmatter Every notice carries the metadata used by the notice index and site search: ```yaml theme={null} --- title: description: diataxis: reference lang: en-US content_type: notice topic: personas: - categories: - is_imported_content: 'false' --- ``` Use every applicable persona from `keywords.config.yaml`; do not reduce the list to the primary audience. Add `audit-source:` when source files or generated artifacts were checked to substantiate the notice. Add `date:` (an ISO `YYYY-MM-DD` value) when the notice is archived. It records the date the change took effect — the mainnet hardfork activation, the end-of-support date, the mainnet execution date of a contract upgrade, or the start of a time-boxed experiment — and it must match the row for the page in the [notice archive](/notices/archive). Omit the key rather than guess: when no canonical in-tree source gives a date, the archive row says "Not dated" instead. ## Required components Every notice must include: 1. **Summary**: one or two paragraphs naming the change, its scope, and the primary action. 2. **Motivation** (`## Why ` or `## Why this is changing`): the user-facing reason for the change, with links to durable explanations when more background is useful. 3. **Change scope** (`## What's included` or `## What is changing`): the concrete protocol, contract, component, or product changes. State important exclusions explicitly. 4. **Persona impacts** (`## Breaking Changes`): one `###` subsection for each persona in frontmatter. State what breaks, what must change, and what remains compatible. If a persona has no action, say so directly. 5. **Required actions**: copy-pasteable configuration, version, contract, or application changes. Use a component table when several releases are involved. 6. **Timing**: the activation mechanism and schedule. For a network upgrade, say whether it has a hardfork activation. Do not invent a timestamp or release version; add it when the canonical source is available. 7. **Verification and support**: tell readers how to verify readiness and where to report a problem. When a change affects state that can span the cutover, explain the transition. Common examples include Dispute Games already in progress, withdrawals already proved, transactions in flight, and old configuration that must remain temporarily available. ## Writing rules * Lead with the action and affected reader, not the internal project history. * Use proper product and protocol names. Preserve command, flag, package, function, and component spelling in code formatting. * Separate confirmed scope from unknown timing or release data. Do not weaken confirmed changes by labeling the entire notice provisional. * Link to the canonical runbook or reference rather than duplicating its full procedure. * Keep persona subsections independently scannable. A reader should not need to infer their action from another persona's section. ## Lifecycle Add an active notice to both `/notices` and the matching Network Notices navigation group in `docs.json`. After activation and completion of the required migration window: 1. Move the page under `/notices/archive`. 2. Remove its active card from `/notices` and delete its `docs.json` navigation entry. Archived notices are deliberately not in the sidebar: add the page to `scripts/lint/nav-allowlist.json` with a reason so the nav validator accepts it, set the page's `date:` frontmatter, and add a row to the [notice archive](/notices/archive), which is how readers browse to it. The page keeps its URL forever — live pages link into it. 3. Record the permanent outcome in the [network upgrade registry](/op-stack/protocol/network-upgrades), using the [contract upgrades table](/op-stack/protocol/network-upgrades#contract-upgrades) when the change has no hardfork. 4. Update durable guides and references so they describe the post-upgrade state without relying on the archived notice. ## Template Copy this template to start a notice: ```mdx theme={null} --- title: description: diataxis: reference lang: en-US content_type: notice topic: personas: - categories: - is_imported_content: 'false' --- ## Why this is changing ## What's included * * This change does not . ## Breaking Changes ### ### ## Required actions | Component or integration | Required change | | --- | --- | | `` | | ## Timing ## Verify readiness * * For support, . ``` # Content type: router/landing Source: https://docs.optimism.io/op-stack/contribute/router-landing The published contract for router and landing pages — purpose, tone, required components, title grammar, and a copy-paste template. A **router/landing page** exists to send readers somewhere else, fast. The site root routing four personas, a tab landing page, a goal-shortcut page — all are routers: pure navigation with a one-line promise per destination and nothing to read for its own sake. This page is the contract for the type. A new router is reviewed against it; cite the relevant section in review instead of re-arguing it. ## Purpose * Get every arriving reader onto the **right path in one decision**: by persona (app developer, chain operator, node operator, protocol learner) or by goal ("deploy a chain", "bridge an asset"). * Order destinations by audience size, not internal org structure — the largest audience's path comes first. * Stay small: a router that starts explaining or instructing has stopped being a router. ## Composition A pure router is the one composed type that carries **no `diataxis:` key**: it contains no documentation mode of its own to classify — it only routes into pages that do. It carries `content-type: router-landing` instead, so it remains machine-classifiable. The moment a page mixes routing with real explanatory or instructional content, it is no longer a router: classify it by what it teaches and move the routing into cards or a "next steps" section. See [Choose a content type](/op-stack/contribute/choose-a-content-type) for how the composed types relate to the `diataxis:` taxonomy. ## Tone * Second person, benefit-first: every destination is phrased as what the reader will accomplish, not what the section contains ("Deploy your first contract on an OP Stack chain", not "Documentation about contracts"). * One line per destination. If a destination needs two sentences to justify itself, the destination is wrong or the router is explaining. * No marketing register. A router is wayfinding, not a pitch. ## Required components Every router/landing page must have: 1. **Frontmatter**: `title`, `description`, `content-type: router-landing`, and `last-reviewed: YYYY-MM-DD` (routers are curated artifacts and enter the review sweep on merge). No `diataxis:` key — see Composition. `mode: wide` is allowed where the layout needs it. 2. **At most one short orienting paragraph** (or a hero block) before the routes. No concepts, no history, no feature tour. 3. **Routes as ``/`` blocks** (or an equivalent visually scannable pattern), each with a title naming the reader or goal, an `href`, and a one-line benefit. 4. **Full coverage of its audience split**: a persona router routes every persona it claims; readers outside the split get a catch-all route (search, glossary, or support). 5. **Resolving links only** — a router is a chain of links and nothing else, so every link must resolve; dead routes are release blockers, not cleanup. ## Title grammar * A **goal router** takes the goal as an imperative phrase in sentence case: "Deploy the OP Stack". * A **persona/section landing page** takes the audience or section's plain name: "App developers". * Never "Welcome", "Home", "Overview", "Getting started" as the full title — the title should say where the reader is or what they came to do. ## Template Copy this template for a new router/landing page: ```mdx theme={null} --- title: description: content-type: router-landing last-reviewed: --- ``` ## Exemplars * The [site root](/) — today a single-persona landing page ("Deploy the OP Stack"); its planned rewrite into a four-persona router is the first page that must pass this spec. * [The OP Stack](/op-stack/introduction/op-stack) — a hybrid worth studying for the boundary: it routes with cards *and* explains, which is why it is classified `diataxis: explanation`, not `content-type: router-landing`. * Cloudflare's [documentation content strategy](https://developers.cloudflare.com/style-guide/documentation-content-strategy/) — the published-content-type pattern this contract follows. # Content type: solution guide Source: https://docs.optimism.io/op-stack/contribute/solution-guide The published contract for solution guides — purpose, tone, required components, title grammar, and a copy-paste template. A **solution guide** takes a reader with a real goal that spans multiple components — "tune my batcher costs", "run a fault-proof challenger" — and sequences the existing documentation into one paved path. It is the page a reader would otherwise have to assemble themselves from guides, reference pages, specs, and READMEs across several properties. This page is the contract for the type. A new solution guide is reviewed against it; cite the relevant section in review instead of re-arguing it. ## Purpose * Turn a traced reader journey into **one in-site page with curated exits**, so the goal is completable without leaving docs.optimism.io except through exits the guide chose on purpose. * Add the **connective decision logic** — which option to pick when, and why — that no single component page can own. * **Derive, never duplicate.** Each stop links the canonical page and states what to extract from it. Restating a linked page's steps or facts violates the [dual-sourcing ban](/op-stack/contribute/content-guide#link-dont-restate-the-dual-sourcing-ban). ## Composition A solution guide is a composition of the existing taxonomy, not a fifth quadrant: frontmatter carries `diataxis: how-to` (it is goal- and action-oriented) plus `content-type: solution-guide`. See [Choose a content type](/op-stack/contribute/choose-a-content-type) for how it differs from a plain how-to guide and from a tutorial. ## Tone * Direct and economical. The reader has a goal and a working system; no scene-setting beyond the one-paragraph goal statement. * Decisions are stated as conditions: "if X, choose Y because W" — never a bare "we recommend Y". * Honest about staleness: any exit into hand-maintained or version-pinned material carries an "as of" marker rather than implying freshness. ## Required components Every solution guide must have, in order: 1. **Frontmatter**: `title`, `description`, `diataxis: how-to`, `content-type: solution-guide`, and `last-reviewed: YYYY-MM-DD` (solution guides are curated artifacts and enter the review sweep on merge, per the [curation review policy](/op-stack/contribute/curation-policy)). 2. **Goal statement**: one paragraph naming the outcome, the intended reader, and the components involved. 3. **Fit test** (`## Is this guide for you?`): bullet conditions for when to use the guide, plus where to go instead when it doesn't fit. 4. **Starting state** (`## Before you start`): the working state and access the guide assumes. A solution guide never contains environment setup — that is tutorial territory; link one if needed. 5. **Sequenced stops** (`## Step 1: …`, `## Step 2: …`): numbered `##` sections, each an imperative action. A stop that derives from another page links it and states exactly what to extract. A stop that is a decision states the decision logic, preferably as an if/choose/because table. 6. **Verification** (final step): how the reader confirms the goal is reached. 7. **Next steps** (`## Next steps`): the deliberate, curated ways out — deeper reference, the normative spec, upstream material — each with a one-line reason and, where the target is version-pinned or hand-maintained, an "as of" marker. ## Title grammar ` ` in sentence case, naming the reader's goal: "Tune batcher costs", "Run a fault-proof challenger", "Choose your node stack". No "How to" prefix, no gerunds ("Tuning…"), no component-first titles ("op-batcher cost tuning"). ## Template Copy this template to start a new solution guide: ```mdx theme={null} --- title: description: diataxis: how-to content-type: solution-guide last-reviewed: --- ## Is this guide for you? Use this guide if: * * If you , see []() instead. ## Before you start You should already have: * * ## Step 1: Read []() and take away: * ## Step 2: | If ... | Choose ... | Because ... | | --- | --- | --- | | |