Arbitrum Nitro Documentation

repository·master·Indexed 21 days ago

https://github.com/offchainlabs/nitro

A high-performance Layer 2 optimistic rollup stack integrating Geth for EVM execution and WASM-based fraud proofs. Includes documentation on the BOLD (Bounded Liquidity Delay) dispute system for permissionless validation, the Rust-based Validator server for block state transitions, and the ArbOS Go-based component for cross-chain communication and L1 cost minimization.

Tokens
53.2K
Snippets
158
Records
237
Agent score
75%

What's inside Arbitrum Nitro

  1. What is Arbitrum Nitro

    master

    Arbitrum Nitro is a complete layer 2 optimistic rollup system. It integrates fraud proofs, a sequencer, token bridges, and advanced calldata compression.

    Key architectural features include:

    • Geth Integration: Instead of a custom EVM emulator, Nitro runs a compiled version of Geth (the Ethereum engine) at layer 2.
    • WASM Prover: The Nitro prover performs interactive fraud proofs over WASM code. While validators and nodes run the engine as native code for performance, they switch to WASM when a fraud proof is required.
    • ArbOS: A Go-based component that handles cross-chain communication and the batching/compression system used to minimize L1 costs.
  2. Overview of the BOLD Protocol

    master

    BOLD (Bounded Liquidity Delay) is a dispute system implemented by Offchain Labs to enable permissionless validation of Arbitrum chains. It functions as an efficient, all-vs-all challenge protocol that allows any participant on Ethereum to challenge invalid rollup state transitions.

    Key features include:

    • Fixed Upper-Bound: Provides a guaranteed maximum time for challenge confirmations.
    • Deterministic Guarantees: Since state transitions are deterministic, an honest participant is guaranteed to win against malicious entities when challenging assertions posted to the settlement chain.
  3. How Multi-Dimensional Gas (MultiGas) refunds work

    master

    Arbitrum uses a multi-dimensional constraint-based pricing model where different resources can have independent base fees. Because standard Ethereum transactions only support a single-dimensional GasLimit and MaxFeePerGas, Arbitrum uses a two-step process to handle multi-gas pricing while maintaining compatibility:

    1. Initial Charge: At the start of a transaction, Arbitrum calculates an initial price by multiplying the provided single-dimensional GasLimit by the single-dimensional base fee (which is defined as the maximum base fee among all resource dimensions). This ensures compatibility with existing Ethereum transaction APIs.
    2. Post-Execution Refund: After execution, the actual resource usage and the specific base fees for each dimension are known. Arbitrum calculates a "discounted price" by multiplying the actual amount of each resource used by its specific base fee.

    The Refund Logic:

    • If no resources are constrained, the discounted price equals the initial price.
    • If certain resources are constrained (higher base fees) while others are not, the discounted price will be lower than the initial price.
    • Arbitrum calculates the difference between the initial price and the discounted price and issues this difference back to the user as a refund.

    Note on SingleDim gas: The SingleDim resource kind (used for L1 posting costs and retryable execution fees) is a special case. It uses the maximum base fee among all resources. To prevent unintended behavior, multi-gas refunds are never applied to the SingleDim resource dimension.

  4. Machine directory discovery for the Validator

    master

    The validator needs to find machine directories containing a module-root.txt file. If the --root-path flag is not provided, the server searches for these directories in the following order:

    1. <crate_dir>/../../target/machines
    2. <cwd>/machines
    3. <cwd>/target/machines
    4. <binary_dir>/../machines

    Directory Naming:

    • A directory named latest is treated as the latest module root.
    • Directories named 0x<hex> are identified by their hex module root value.
  5. Understand the Nitro License and Usage Grants

    master

    Nitro is licensed under a Business Source License.

    Key Usage Terms:

    • Additional Use Grant: Allows users to run nodes on all public Arbitrum chains with full comfort.
    • Permissionless Deployment: You may deploy the Nitro software as a new blockchain without cost, provided that the chain settles to either Arbitrum One or Arbitrum Nova.
    • Arbitrum Expansion Program (AEP): If you wish to deploy Nitro as an L2 directly on Ethereum (or settling to another L2), you must follow the AEP, which requires contributing 10% of net revenue back to the Arbitrum community.
  6. How Edge Trackers manage challenge lifecycles

    master

    An Edge Tracker is a self-contained goroutine responsible for managing a single challenge edge.

    Lifecycle and Behavior:

    • Execution: Edge trackers wake up at specified tick intervals.
    • Decision Making: They use a Finite State Machine (FSM) to determine the next appropriate challenge move.
    • Moves: Depending on the current state, an edge tracker might attempt to bisect, confirm via one-step proof, or create a subchallenge.
    • Goal: The process continues until the FSM reaches the Confirmed state. Once a level zero edge for a challenge on an assertion is confirmed, the assertion is considered confirmed and the honest party succeeds.
  7. Constraint validation pattern in Nitro

    master

    Nitro avoids using custom constrained wrapper types (e.g., a Pos64 struct wrapping a uint64) to enforce value constraints like positivity. Instead, the project follows the Status Quo pattern: validating constraints explicitly at function boundaries.

    Why custom types are avoided

    While creating a type like Pos64 can ensure a value is positive during construction, it introduces a regression in usability because these custom types do not support standard Go arithmetic operators (e.g., +, -, *, /) without manual conversion and unwrapping.

    To ensure correctness and maintainability, follow these principles:

    1. Check constraints in multiple places: Validate constraints at the entry point of public functions. This ensures that when a function is exported or moved between packages, the safety guarantees remain intact.
    2. Avoid 'Minimize Checks' approach: Do not rely on the assumption that package-private functions are always called with valid data. Refactoring a private function to be public or adding a new caller can easily violate these assumptions and introduce bugs.
    3. Prioritize primitive types: Use standard primitive types (like uint64) for function arguments to maintain compatibility with operators, and perform validation logic within the function body.
  8. How BOLD integrates with Arbitrum Nitro

    master

    BOLD is a modular component designed to be plugged into Arbitrum Nitro chains. While Nitro handles transaction execution, batch submission to the SequencerInbox, and assertion submission to RollupCore.sol, BOLD specifically implements the logic for posting assertions and challenging invalid ones.

    To function, BOLD depends on the Nitro node to provide state data. It interacts with the Nitro node through an abstraction called the L2 State Provider, which allows BOLD to access the necessary L2 state without being tightly coupled to the internal implementation of the Nitro node.

  9. How validation modes (Native vs Continuous) work

    master

    The validator supports two execution modes for JIT-compiled WASM:

    • Native (default): Runs the JIT machine in-process via the jit crate. Each validation request spawns a JIT execution inline. This is simpler but incurs per-request overhead.
    • Continuous: Spawns long-running JIT machine subprocesses (one per module root) at server startup. Validation requests are sent to these persistent processes over a TCP-based IPC channel. This is optimized for performance by avoiding per-request process startup overhead.
  10. Understand the BOLD package directory structure

    master

    The BOLD repository is organized into several functional modules. Understanding these helps in navigating the codebase for specific tasks:

    • api/: APIs for monitoring and visualizing challenges.
    • assertions/: Logic for scanning and posting assertions.
    • protocol/: High-level wrappers around Solidity bindings for Rollup contracts.
    • challenge/: Logic for managing and executing challenges.
    • containers/: Data structures, including Finite State Machines (FSMs).
    • contracts/: Rollup and challenge smart contracts.
    • state/: Interface for requesting state and proofs from an L2 backend.
    • commitment/: Proofs, history commitments, and Merkleizations.
    • retry/: Tools for managing function lifecycles.
    • clock/: Abstract time utilities.
    • log/: Ephemeral logging helpers.
    • testing/: Non-production code.
    • third_party/: Build artifacts for dependencies.
  11. Understand Multi-Dimensional (MultiGas) Gas Metering

    master

    Arbitrum Nitro uses a multi-dimensional gas metering system instead of Ethereum's traditional single-dimensional uint64 gas accounting. This system tracks gas consumption across distinct, orthogonal resource categories (Resource Kinds).

    This approach allows the network to isolate and measure consumption for specific types of operations—such as computation, state access, or state growth—enabling fine-grained pricing adjustments per resource based on network load or policy.

  12. How the BOLD architecture works

    master

    BOLD operates through four primary components that manage the lifecycle of assertions and challenges on Ethereum:

    1. Assertion Poster: Takes validated messages from the L2 validator and posts them on-chain.
    2. Assertion Scanner: Monitors Ethereum smart contracts for new assertions and compares them against the local Nitro node's database using the L2 State Provider (implemented in assertions/sync.go).
    3. Challenge Manager: If an assertion is found to be invalid, the Challenge Manager submits an on-chain challenge by creating a level zero edge and begins tracking that edge.
    4. Chain Watcher: Runs in the background to scan for other edges created on-chain. It spawns Edge Tracker goroutines for any honest edges that are not yet being tracked.

    Core primitives include challenge edges (representing a start and end history commitment) and moves (actions taken by participants on those challenges).