Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions README_ESPRESSO.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,12 @@ source ~/.bashrc
These commands install the dependencies for, start the service related to and configures the enclave.

```
sudo amazon-linux-extras install aws-nitro-enclaves-cli
sudo sh -c "echo -e 'memory_mib: 4096\ncpu_count: 2' > /etc/nitro_enclaves/allocator.yaml"
sudo yum install -y aws-nitro-enclaves-cli-1.4.2
sudo systemctl stop nitro-enclaves-allocator.service || true
echo -e '---\nmemory_mib: 4096\ncpu_count: 2' | sudo tee /etc/nitro_enclaves/allocator.yaml
sudo systemctl start nitro-enclaves-allocator.service
```



/etc/nitro_enclaves/allocator.yaml

* Clone repository and update submodules
```
git clone https://github.com/EspressoSystems/optimism-espresso-integration.git
Expand All @@ -206,9 +203,49 @@ git submodule update --init --recursive
* Enter the nix shell and run the enclave tests
```
nix --extra-experimental-features "nix-command flakes" develop
just compile-contracts
just espresso-enclave-tests
```

#### Building, running and registering enclave images

`op-batcher/enclave-tools` provides a command-line utility for common operations on batcher enclave images.
Before using it, set your AWS instance as described in the guide above, then build the tool:

```
cd op-batcher/
just enclave-tools
```

This should create `op-batcher/bin/enclave-tools` binary. You can run
```
./op-batcher/bin/enclave-tools --help
```
to get information on available commands and flags.

##### Building a batcher image

To build a batcher enclave image, and tag it with specified tag:
```
./op-batcher/bin/enclave-tools build --op-root ./ --tag op-batcher-enclave
Comment thread
philippecamacho marked this conversation as resolved.
```
On success this command will output PCR measurements of the enclave image, which can then be registered with BatchAuthenticator
contract.

##### Running a batcher image
To run enclave image built by the previous command:
```
./op-batcher/bin/enclave-tools run --image op-batcher-enclave --args --argument-1,value-1,--argument-2,value-2
```
Arguments will be forwarded to the op-batcher

##### Registering a batcher image
To register PCR0 of the batcher enclave image built by the previous command:
```
./op-batcher/bin/enclave-tools register --l1-url example.com:1234 --authenticator 0x123..def --private-key 0x123..def --pcr0 0x123..def
```
You will need to provide the L1 URL, the contract address of BatchAuthenticator, private key of L1 account used to deploy BatchAuthenticator and PCR0 obtained when building the image.

## Docker Compose

### Run Docker Compose
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,10 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ=
github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
Expand Down
24 changes: 24 additions & 0 deletions op-batcher/enclave-entrypoint.bash
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ fi

unset http_proxy HTTP_PROXY https_proxy HTTPS_PROXY

# Launch nc listener to receive null-separated arguments
NC_PORT=8337
received_args=()

echo "Starting nc listener on port $NC_PORT (60 second timeout)"
{
# Read null-separated arguments until we get \0\0
while IFS= read -r -d '' arg; do
if [[ -z "$arg" ]]; then
# Empty argument signals end (\0\0)
break
fi
received_args+=("$arg")
done
} < <(nc -l -p "$NC_PORT" -w 60)

if [ ${#received_args[@]} -eq 0 ]; then
echo "Warning: No arguments received via nc listener within 60 seconds, continuing with existing arguments"
else
echo "Received ${#received_args[@]} arguments via nc, appending to existing arguments"
# Append received arguments to existing positional parameters
set -- "$@" "${received_args[@]}"
fi

wait_for_port() {
local port="$1"

Expand Down
216 changes: 216 additions & 0 deletions op-batcher/enclave-tools/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package main

import (
"context"
"encoding/hex"
"fmt"
"log"
"os"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/urfave/cli/v2"

enclave_tools "github.com/ethereum-optimism/optimism/op-batcher/enclave-tools"
)

func main() {
app := &cli.App{
Name: "enclave-tools",
Usage: "Build, register, and run enclave EIF images",
Description: "A command-line interface for building, registering, and running enclave EIF (Enclave Image Format) images for the Optimism op-batcher.",
Version: "1.0.0",
Commands: []*cli.Command{
buildCommand(),
registerCommand(),
runCommand(),
},
}

if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}

func buildCommand() *cli.Command {
return &cli.Command{
Name: "build",
Usage: "Build enclave EIF image",
Description: `Build a Docker image and then create an EIF (Enclave Image Format) file
with the op-batcher and specified arguments.`,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "op-root",
Usage: "Path to optimism root directory",
Required: true,
},
&cli.StringFlag{
Name: "tag",
Usage: "Docker tag for the EIF image",
Comment thread
philippecamacho marked this conversation as resolved.
Required: true,
},
&cli.StringFlag{
Comment thread
philippecamacho marked this conversation as resolved.
Name: "args",
Usage: "Command-line arguments to op-batcher (comma-separated)",
},
},
Action: buildAction,
}
}

func registerCommand() *cli.Command {
return &cli.Command{
Name: "register",
Usage: "Register enclave PCR with verifier",
Description: `Register the enclave's PCR0 measurement with the EspressoNitroTEEVerifier contract.
This allows the enclave to be trusted by the verification system.`,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "authenticator",
Usage: "BatchAuthenticator contract address",
Required: true,
},
&cli.StringFlag{
Name: "l1-url",
Usage: "L1 RPC URL",
Required: true,
},
&cli.StringFlag{
Name: "private-key",
Usage: "Private key for transaction signing (hex format)",
Required: true,
},
&cli.StringFlag{
Name: "pcr0",
Usage: "PCR0 value in hex format",
Required: true,
},
},
Action: registerAction,
}
}

func runCommand() *cli.Command {
return &cli.Command{
Name: "run",
Usage: "Launch/run the EIF",
Description: `Launch the specified EIF image in a Docker container with the necessary
AWS Nitro Enclaves configuration.`,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "image",
Usage: "Name of the EIF image to run",
Required: true,
},
&cli.StringFlag{
Name: "args",
Usage: "Command-line arguments to dynamically send to enclave (comma-separated)",
},
},
Action: runAction,
}
}

func buildAction(c *cli.Context) error {
opRoot := c.String("op-root")
tag := c.String("tag")
args := c.String("args")

// Parse batcher arguments
batcherArgs, err := ParseBatcherArgs(args)
if err != nil {
return fmt.Errorf("failed to parse batcher arguments: %w", err)
}

ctx := context.Background()
fmt.Printf("Building enclave image...")
measurements, err := enclave_tools.BuildBatcherImage(ctx, opRoot, tag, batcherArgs...)
if err != nil {
return fmt.Errorf("failed to build enclave image: %w", err)
}

fmt.Println("Build completed successfully!")
fmt.Println("Measurements:")
fmt.Printf(" PCR0: %s\n", measurements.PCR0)
fmt.Printf(" PCR1: %s\n", measurements.PCR1)
fmt.Printf(" PCR2: %s\n", measurements.PCR2)

return nil
}

func registerAction(c *cli.Context) error {
authenticatorAddr := c.String("authenticator")
l1URL := c.String("l1-url")
privateKey := c.String("private-key")
pcr0 := c.String("pcr0")

key, err := crypto.HexToECDSA(strings.TrimPrefix(privateKey, "0x"))
if err != nil {
return fmt.Errorf("invalid private key: %w", err)
}

// Parse authenticator address
authAddr := common.HexToAddress(authenticatorAddr)
if authAddr == (common.Address{}) {
return fmt.Errorf("invalid authenticator address")
}

// Parse PCR0
pcr0Bytes, err := hex.DecodeString(strings.TrimPrefix(pcr0, "0x"))
if err != nil {
return fmt.Errorf("failed to parse PCR0: %w", err)
}

ctx := context.Background()
fmt.Printf("Registering enclave hash...")
err = enclave_tools.RegisterEnclaveHash(ctx, authAddr, l1URL, key, pcr0Bytes)
if err != nil {
return fmt.Errorf("failed to register enclave hash: %w", err)
}

fmt.Printf("Enclave hash registered successfully!")
return nil
}

func runAction(c *cli.Context) error {
imageName := c.String("image")
argsStr := c.String("args")

// Parse arguments
args, err := ParseBatcherArgs(argsStr)
if err != nil {
return fmt.Errorf("failed to parse arguments: %w", err)
}

ctx := context.Background()
enclaverCli := &enclave_tools.EnclaverCli{}

fmt.Printf("Starting enclave: %s\n", imageName)
err = enclaverCli.RunEnclave(ctx, imageName, args)
if err != nil {
return err
}

return nil
}

// ParseBatcherArgs parses comma-separated batcher arguments and validates them
func ParseBatcherArgs(argsStr string) ([]string, error) {
if argsStr == "" {
return []string{}, nil
}

args := strings.Split(argsStr, ",")
var cleanedArgs []string

for _, arg := range args {
cleaned := strings.TrimSpace(arg)
if cleaned == "" {
continue // Skip empty args
}
cleanedArgs = append(cleanedArgs, cleaned)
}

return cleanedArgs, nil
}
Loading