Skip to content

Commit 78d978e

Browse files
QuentinIphilippecamacho
authored andcommitted
Enclave-tools (#187)
Co-authored-by: Philippe Camacho <[email protected]>
1 parent fd3cd5c commit 78d978e

File tree

7 files changed

+612
-8
lines changed

7 files changed

+612
-8
lines changed

README_ESPRESSO.md

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,12 @@ source ~/.bashrc
186186
These commands install the dependencies for, start the service related to and configures the enclave.
187187
188188
```
189-
sudo amazon-linux-extras install aws-nitro-enclaves-cli
190-
sudo sh -c "echo -e 'memory_mib: 4096\ncpu_count: 2' > /etc/nitro_enclaves/allocator.yaml"
189+
sudo yum install -y aws-nitro-enclaves-cli-1.4.2
190+
sudo systemctl stop nitro-enclaves-allocator.service || true
191+
echo -e '---\nmemory_mib: 4096\ncpu_count: 2' | sudo tee /etc/nitro_enclaves/allocator.yaml
191192
sudo systemctl start nitro-enclaves-allocator.service
192193
```
193194
194-
195-
196-
/etc/nitro_enclaves/allocator.yaml
197-
198195
* Clone repository and update submodules
199196
```
200197
git clone https://github.com/EspressoSystems/optimism-espresso-integration.git
@@ -206,9 +203,49 @@ git submodule update --init --recursive
206203
* Enter the nix shell and run the enclave tests
207204
```
208205
nix --extra-experimental-features "nix-command flakes" develop
206+
just compile-contracts
209207
just espresso-enclave-tests
210208
```
211209
210+
#### Building, running and registering enclave images
211+
212+
`op-batcher/enclave-tools` provides a command-line utility for common operations on batcher enclave images.
213+
Before using it, set your AWS instance as described in the guide above, then build the tool:
214+
215+
```
216+
cd op-batcher/
217+
just enclave-tools
218+
```
219+
220+
This should create `op-batcher/bin/enclave-tools` binary. You can run
221+
```
222+
./op-batcher/bin/enclave-tools --help
223+
```
224+
to get information on available commands and flags.
225+
226+
##### Building a batcher image
227+
228+
To build a batcher enclave image, and tag it with specified tag:
229+
```
230+
./op-batcher/bin/enclave-tools build --op-root ./ --tag op-batcher-enclave
231+
```
232+
On success this command will output PCR measurements of the enclave image, which can then be registered with BatchAuthenticator
233+
contract.
234+
235+
##### Running a batcher image
236+
To run enclave image built by the previous command:
237+
```
238+
./op-batcher/bin/enclave-tools run --image op-batcher-enclave --args --argument-1,value-1,--argument-2,value-2
239+
```
240+
Arguments will be forwarded to the op-batcher
241+
242+
##### Registering a batcher image
243+
To register PCR0 of the batcher enclave image built by the previous command:
244+
```
245+
./op-batcher/bin/enclave-tools register --l1-url example.com:1234 --authenticator 0x123..def --private-key 0x123..def --pcr0 0x123..def
246+
```
247+
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.
248+
212249
## Docker Compose
213250
214251
### Run Docker Compose

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,10 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
234234
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
235235
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
236236
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
237-
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
238-
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
239237
github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ=
240238
github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
239+
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
240+
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
241241
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
242242
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
243243
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=

op-batcher/enclave-entrypoint.bash

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,30 @@ fi
2727

2828
unset http_proxy HTTP_PROXY https_proxy HTTPS_PROXY
2929

30+
# Launch nc listener to receive null-separated arguments
31+
NC_PORT=8337
32+
received_args=()
33+
34+
echo "Starting nc listener on port $NC_PORT (60 second timeout)"
35+
{
36+
# Read null-separated arguments until we get \0\0
37+
while IFS= read -r -d '' arg; do
38+
if [[ -z "$arg" ]]; then
39+
# Empty argument signals end (\0\0)
40+
break
41+
fi
42+
received_args+=("$arg")
43+
done
44+
} < <(nc -l -p "$NC_PORT" -w 60)
45+
46+
if [ ${#received_args[@]} -eq 0 ]; then
47+
echo "Warning: No arguments received via nc listener within 60 seconds, continuing with existing arguments"
48+
else
49+
echo "Received ${#received_args[@]} arguments via nc, appending to existing arguments"
50+
# Append received arguments to existing positional parameters
51+
set -- "$@" "${received_args[@]}"
52+
fi
53+
3054
wait_for_port() {
3155
local port="$1"
3256

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/hex"
6+
"fmt"
7+
"log"
8+
"os"
9+
"strings"
10+
11+
"github.com/ethereum/go-ethereum/common"
12+
"github.com/ethereum/go-ethereum/crypto"
13+
"github.com/urfave/cli/v2"
14+
15+
enclave_tools "github.com/ethereum-optimism/optimism/op-batcher/enclave-tools"
16+
)
17+
18+
func main() {
19+
app := &cli.App{
20+
Name: "enclave-tools",
21+
Usage: "Build, register, and run enclave EIF images",
22+
Description: "A command-line interface for building, registering, and running enclave EIF (Enclave Image Format) images for the Optimism op-batcher.",
23+
Version: "1.0.0",
24+
Commands: []*cli.Command{
25+
buildCommand(),
26+
registerCommand(),
27+
runCommand(),
28+
},
29+
}
30+
31+
if err := app.Run(os.Args); err != nil {
32+
log.Fatal(err)
33+
}
34+
}
35+
36+
func buildCommand() *cli.Command {
37+
return &cli.Command{
38+
Name: "build",
39+
Usage: "Build enclave EIF image",
40+
Description: `Build a Docker image and then create an EIF (Enclave Image Format) file
41+
with the op-batcher and specified arguments.`,
42+
Flags: []cli.Flag{
43+
&cli.StringFlag{
44+
Name: "op-root",
45+
Usage: "Path to optimism root directory",
46+
Required: true,
47+
},
48+
&cli.StringFlag{
49+
Name: "tag",
50+
Usage: "Docker tag for the EIF image",
51+
Required: true,
52+
},
53+
&cli.StringFlag{
54+
Name: "args",
55+
Usage: "Command-line arguments to op-batcher (comma-separated)",
56+
},
57+
},
58+
Action: buildAction,
59+
}
60+
}
61+
62+
func registerCommand() *cli.Command {
63+
return &cli.Command{
64+
Name: "register",
65+
Usage: "Register enclave PCR with verifier",
66+
Description: `Register the enclave's PCR0 measurement with the EspressoNitroTEEVerifier contract.
67+
This allows the enclave to be trusted by the verification system.`,
68+
Flags: []cli.Flag{
69+
&cli.StringFlag{
70+
Name: "authenticator",
71+
Usage: "BatchAuthenticator contract address",
72+
Required: true,
73+
},
74+
&cli.StringFlag{
75+
Name: "l1-url",
76+
Usage: "L1 RPC URL",
77+
Required: true,
78+
},
79+
&cli.StringFlag{
80+
Name: "private-key",
81+
Usage: "Private key for transaction signing (hex format)",
82+
Required: true,
83+
},
84+
&cli.StringFlag{
85+
Name: "pcr0",
86+
Usage: "PCR0 value in hex format",
87+
Required: true,
88+
},
89+
},
90+
Action: registerAction,
91+
}
92+
}
93+
94+
func runCommand() *cli.Command {
95+
return &cli.Command{
96+
Name: "run",
97+
Usage: "Launch/run the EIF",
98+
Description: `Launch the specified EIF image in a Docker container with the necessary
99+
AWS Nitro Enclaves configuration.`,
100+
Flags: []cli.Flag{
101+
&cli.StringFlag{
102+
Name: "image",
103+
Usage: "Name of the EIF image to run",
104+
Required: true,
105+
},
106+
&cli.StringFlag{
107+
Name: "args",
108+
Usage: "Command-line arguments to dynamically send to enclave (comma-separated)",
109+
},
110+
},
111+
Action: runAction,
112+
}
113+
}
114+
115+
func buildAction(c *cli.Context) error {
116+
opRoot := c.String("op-root")
117+
tag := c.String("tag")
118+
args := c.String("args")
119+
120+
// Parse batcher arguments
121+
batcherArgs, err := ParseBatcherArgs(args)
122+
if err != nil {
123+
return fmt.Errorf("failed to parse batcher arguments: %w", err)
124+
}
125+
126+
ctx := context.Background()
127+
fmt.Printf("Building enclave image...")
128+
measurements, err := enclave_tools.BuildBatcherImage(ctx, opRoot, tag, batcherArgs...)
129+
if err != nil {
130+
return fmt.Errorf("failed to build enclave image: %w", err)
131+
}
132+
133+
fmt.Println("Build completed successfully!")
134+
fmt.Println("Measurements:")
135+
fmt.Printf(" PCR0: %s\n", measurements.PCR0)
136+
fmt.Printf(" PCR1: %s\n", measurements.PCR1)
137+
fmt.Printf(" PCR2: %s\n", measurements.PCR2)
138+
139+
return nil
140+
}
141+
142+
func registerAction(c *cli.Context) error {
143+
authenticatorAddr := c.String("authenticator")
144+
l1URL := c.String("l1-url")
145+
privateKey := c.String("private-key")
146+
pcr0 := c.String("pcr0")
147+
148+
key, err := crypto.HexToECDSA(strings.TrimPrefix(privateKey, "0x"))
149+
if err != nil {
150+
return fmt.Errorf("invalid private key: %w", err)
151+
}
152+
153+
// Parse authenticator address
154+
authAddr := common.HexToAddress(authenticatorAddr)
155+
if authAddr == (common.Address{}) {
156+
return fmt.Errorf("invalid authenticator address")
157+
}
158+
159+
// Parse PCR0
160+
pcr0Bytes, err := hex.DecodeString(strings.TrimPrefix(pcr0, "0x"))
161+
if err != nil {
162+
return fmt.Errorf("failed to parse PCR0: %w", err)
163+
}
164+
165+
ctx := context.Background()
166+
fmt.Printf("Registering enclave hash...")
167+
err = enclave_tools.RegisterEnclaveHash(ctx, authAddr, l1URL, key, pcr0Bytes)
168+
if err != nil {
169+
return fmt.Errorf("failed to register enclave hash: %w", err)
170+
}
171+
172+
fmt.Printf("Enclave hash registered successfully!")
173+
return nil
174+
}
175+
176+
func runAction(c *cli.Context) error {
177+
imageName := c.String("image")
178+
argsStr := c.String("args")
179+
180+
// Parse arguments
181+
args, err := ParseBatcherArgs(argsStr)
182+
if err != nil {
183+
return fmt.Errorf("failed to parse arguments: %w", err)
184+
}
185+
186+
ctx := context.Background()
187+
enclaverCli := &enclave_tools.EnclaverCli{}
188+
189+
fmt.Printf("Starting enclave: %s\n", imageName)
190+
err = enclaverCli.RunEnclave(ctx, imageName, args)
191+
if err != nil {
192+
return err
193+
}
194+
195+
return nil
196+
}
197+
198+
// ParseBatcherArgs parses comma-separated batcher arguments and validates them
199+
func ParseBatcherArgs(argsStr string) ([]string, error) {
200+
if argsStr == "" {
201+
return []string{}, nil
202+
}
203+
204+
args := strings.Split(argsStr, ",")
205+
var cleanedArgs []string
206+
207+
for _, arg := range args {
208+
cleaned := strings.TrimSpace(arg)
209+
if cleaned == "" {
210+
continue // Skip empty args
211+
}
212+
cleanedArgs = append(cleanedArgs, cleaned)
213+
}
214+
215+
return cleanedArgs, nil
216+
}

0 commit comments

Comments
 (0)