For the complete documentation index, see llms.txt. This page is also available as Markdown.

Using TEE with Nitro

This guide is for teams integrating an existing Arbitrum Orbit chain with Espresso. Espresso provides settlement and finality on the chain's blocks. Batch posting (where applicable) is a property of the Nitro framework, not Espresso settlement itself.

Espresso is a decentralized settlement layer. Integrated chains continue to run their own sequencers; Espresso provides decentralized Proof of Stake settlement and finality on the blocks they propose. The batch poster accepts batches only after HotShot finalization, which is faster than waiting for parent-chain finality on Ethereum (typically on the order of 12–15 minutes). Espresso does not replace the chain's sequencer.

Purpose: This document describes how Espresso provides fast confirmations to Arbitrum Orbit chains. Espresso has developed a TEE based integration, which is ready for chain operators and rollup-as-a-service providers to implement. There is some assumed familiarity with the Arbitrum Nitro stack.

How it works: In a regular chain, the transaction lifecycle will look something like this: A user transacts on an Arbitrum chain. The transaction is processed by the chain’s sequencer, which provides a soft-confirmation to the user, and the transactions are packaged into a block. The sequencer is responsible for collecting these blocks, compressing, and submitting them to the base layer. If the base layer is Arbitrum One or Ethereum, then the transaction will take at least 12-15 minutes to finalize, or longer depending on how frequently the sequencer posts to the base layer. In this transaction lifecycle, the user must trust that the chain’s sequencer provided an honest soft-confirmation and will not act maliciously. There are limited ways to verify that the sequencer and batcher acted honestly or did not censor transactions.

However, if the chain is integrated with Espresso: The sequencer provides a soft-confirmation to the user, while the transactions are also sent to Espresso to provide a stronger confirmation secured by BFT consensus. A software component of the sequencer called the batch poster (or “batcher”) is run inside a TEE and must honor Espresso confirmation. It cannot change the ordering or equivocate. This gives a strong guarantee that the transaction will ultimately be included and finalized by the base layer.

  • Implication: The user must trust that the chain’s sequencer provided an honest soft-confirmation; however Espresso provides a stronger confirmation that keeps the sequencer accountable and prevents the sequencer from equivocating or acting maliciously. The initial implementation of the batch poster is permissioned and the user must trust that it will not reorder blocks produced by the sequencer.

Integration considerations: **Integrating with Espresso requires minimal changes to Arbitrum Nitro’s existing rollup design. The key change is running the Arbitrum Nitro batch poster (which collects multiple transactions, organizes them into batches, and compresses the data to post to the base layer) inside a Trusted Execution Environment (“TEE”). Espresso’s preferred TEE for this integration is built using Intel SGX, and we plan to support other approaches in the future.

Effort required: We would kick off the integration process with a full walkthrough of your architecture. Espresso will provide a config file that chains and RaaS providers can leverage during integration. We prefer to have direct access to your node (instead of through an intermediary).

Goal

Espresso settlement gives users and chain operators faster, decentralized finality on transaction ordering and a trust-minimized source of finalized state for their own chain and other integrated chains. That supports improved UX and cross-chain composability.

The goal of this document is to integrate Espresso settlement with minimal changes to Arbitrum Nitro's existing rollup design. By leveraging HotShot finalization, a rollup accepts a batch only after it has been finalized by Espresso. This integration ensures that each batch processed by the rollup is consistent with the blocks finalized via Espresso.

This approach involves running an Arbitrum Nitro node with only the batcher enabled, operating in a TEE environment (such as Intel SGX). The batcher signs the combined hash of blob hashes and add this signature to the L1 transaction calldata.

Assumption

This document assumes that the batch poster sends only blob transactions to L1. However, in some cases, it does post the data in calldata. The flow remains the same in this scenario, except that the batcher signs the data directly, and the Sequencer Inbox contract verifies the signature accordingly.

Batch Consistency Checks

To ensure that the batch has been finalized by Espresso (“HotShot” is the name of the consensus protocol), the following checks are required:

  1. Namespace Validation: Ensure that the set of transactions in an Arbitrum Nitro batch corresponds to an Arbitrum Nitro/Orbit chain namespace. Namespacing allows multiple chains to share Espresso's settlement layer simultaneously by associating each chain's transactions with a unique namespace within Espresso blocks.

  2. Espresso Block Merkle Proof Check: Confirm that the Arbitrum Nitro batch maps to a valid HotShot block. Specifically, verify that the HotShot block associated with an Arbitrum Nitro batch is a valid leaf in the Merkle tree maintained by Espresso's onchain state contract on Ethereum.

Integration Design

The integration flow is as follows:

Arbitrum Nitro integration flow with Espresso

The flow is as follows:

  1. The sequencer calls WriteSequencerMsg on the transaction streamer.

  2. The batcher fetches the message from the transaction streamer and submits the transaction to HotShot via the transaction streamer. Code for this is already implemented in the batcher here.

  3. The batcher then calls the query API to check if the transaction has been finalized by HotShot. This code is also written and can be found here.

  4. Once the transaction is finalized, the batcher performs batch consistency checks.

  5. The batcher computes the hashes of the blobs it plans to submit. (Note: Arbitrum uses blob transactions.) This allows the batcher to sign the combined hash of the blobs, along with other calldata fields, before sending the transaction. The signature is then included in the transaction’s calldata. If blob transactions are not being used, the batcher instead signs the l2MessageData along with the other calldata fields.

  6. The Sequencer Inbox contract must be modified to verify the batcher’s signature. If the signature is invalid, it will revert the transaction.

Batching Flow Changes

Running Arbitrum Nitro batch poster in TEE

The first set of changes require running the batch-poster in a Trusted Execution Environment (TEE), specifically Intel SGX.

  • Several LibOSes have been developed to run applications on SGX, including Gramine, Occlum and EGo. We selected Gramine due to its maturity, stability, and comprehensive documentation.

  • We implemented Remote Attestation support, enabling anyone to verify the SGX proof. This is accomplished by generating a Remote Attestation TLS (RA-TLS) certificate during startup, which embeds the SGX attestation report (more info here).

Submitting Transactions to Espresso (HotShot)

Most of the necessary code for this function (which allows the batcher to submit transactions to Espresso after receiving transactions from the sequencer) is already implemented in our batcher.

Checking for HotShot Finalization

We have existing code in place where the batcher prepares an Espresso justification once HotShot finalizes a transaction.

Verifying Batch Consistency

Batch consistency verification involves checking the block Merkle proof and the namespace proof. Jellyfish, Espresso’s cryptography library, is written in Rust. We created an espresso-crypto-helper Rust package that allows us to verify the Merkle proof and namespace proof.

To enable the Go-based batcher to use these Rust functions, we implemented a Foreign Function Interface (FFI) to expose the Rust verification functions to Go.

Sending Transactions to L1

We add the batcher’s signature to the transaction calldata over the blob hashes, which can be constructed using the ComputeCommitmentAndHashes method. We sign blob hashes instead of the blob data itself because, in a Blob Commitment transaction, the blob data is unavailable on the execution layer, only blob hashes are accessible in Solidity via the blobhash opcode.

In a scenario when a chain is not using blob transactions, the batcher will sign the l2MessageData.

Sequencer Inbox Contract

  • The Sequencer Inbox’s methods will need to be modified to accept the batcher signature as a parameter.

  • These methods verify that the signature is valid

Escape Hatch

We also have an escape hatch where the batch poster calls IsHotshotLive on the onchain state contract before posting a batch. Each batch poster configuration allows the chain to choose between two behaviors: (i) waiting for Hotshot to go live before posting the batch, or, (ii) if Hotshot is not live, proceeding without checking batch consistency with Hotshot. This flexibility enables chains to tailor their approach as needed.

Last updated