Skip to content
Closed
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
4 changes: 4 additions & 0 deletions README_ESPRESSO.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,10 @@ Note that `l2-genesis` is expected to take around 2 minutes.
```console
./startup.sh
```
Or build and start the devnet with AWS Nitro Enclave as the TEE:
```console
USE_TEE=true ./startup.sh
```

### View Logs
There are 15 services in total, as listed in `logs.sh`. It is supported to run logs for any
Expand Down
5 changes: 2 additions & 3 deletions espresso/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,7 @@ services:
- sh
- -c
- |
echo "Delaying op-batcher-tee for 45 minutes..."
sleep 2700
echo "Starting op-batcher-tee immediately for testing..."
export DEPLOYMENT_MODE=local
export L1_RPC_URL="http://127.0.0.1:${L1_HTTP_PORT}"
export L2_RPC_URL="http://127.0.0.1:${OP_HTTP_PORT}"
Expand Down Expand Up @@ -440,7 +439,7 @@ services:
context: ../
dockerfile: espresso/docker/op-stack/Dockerfile
target: op-proposer-target
image: op-proposer:espresso
image: op-proposer-tee:espresso
depends_on:
l1-data-init:
condition: service_completed_successfully
Expand Down
2 changes: 1 addition & 1 deletion espresso/docker/l1-geth/devnet-genesis-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"baseFeePerGas": "0x3b9aca00",
"baseFeePerGas": "0x7",
"excessBlobGas": null,
"blobGasUsed": null
}
4 changes: 3 additions & 1 deletion espresso/docker/l1-geth/l1-geth-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ elif [[ "$MODE" == "geth" ]]; then
--maxpeers 0 \
--networkid ${L1_CHAIN_ID} \
--syncmode=full \
--gcmode=archive
--gcmode=archive \
--miner.gasprice=1 \
--txpool.pricelimit=1

else
echo "Unknown MODE: $MODE. Use 'genesis' or 'geth'"
Expand Down
70 changes: 62 additions & 8 deletions espresso/docker/op-batcher-tee/run-enclave.sh
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,77 @@ BATCH_AUTHENTICATOR_ADDRESS=$(jq -r '.opChainDeployments[0].batchAuthenticatorAd

# Register PCR0 if all required values are present
if [ -n "$PCR0" ] && [ -n "$BATCH_AUTHENTICATOR_ADDRESS" ] && [ -n "$OPERATOR_PRIVATE_KEY" ]; then
echo "Registering PCR0: $PCR0 with authenticator: $BATCH_AUTHENTICATOR_ADDRESS"
enclave-tools register \
echo "=== PCR0 Registration ==="
echo "Timestamp: $(date '+%Y-%m-%d %H:%M:%S %Z')"
echo "PCR0: $PCR0"
echo "BatchAuthenticator: $BATCH_AUTHENTICATOR_ADDRESS"
echo "L1 RPC: $L1_RPC_URL"

# Check L1 connectivity before attempting registration
echo ""
echo "Pre-flight checks:"
echo " 1. Checking L1 RPC connectivity..."
BLOCK_CHECK=$(curl -s -X POST "$L1_RPC_URL" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
| jq -r '.result // empty' 2>/dev/null)

if [ -n "$BLOCK_CHECK" ]; then
BLOCK_DEC=$((BLOCK_CHECK))
echo " ✓ L1 RPC responding (block: $BLOCK_DEC)"
else
echo " ❌ L1 RPC not responding"
echo " This is why PCR0 registration will fail!"
fi

# Check if contract exists
echo " 2. Checking BatchAuthenticator contract..."
CODE_CHECK=$(curl -s -X POST "$L1_RPC_URL" \
-H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getCode\",\"params\":[\"$BATCH_AUTHENTICATOR_ADDRESS\", \"latest\"],\"id\":1}" \
| jq -r '.result // empty' 2>/dev/null)

if [ "$CODE_CHECK" != "0x" ] && [ -n "$CODE_CHECK" ]; then
echo " ✓ Contract deployed (code length: ${#CODE_CHECK})"
else
echo " ❌ Contract NOT deployed or not accessible"
echo " Response: $CODE_CHECK"
echo " This is why PCR0 registration will fail!"
fi

echo ""
echo "Attempting PCR0 registration..."
REGISTER_OUTPUT=$(enclave-tools register \
--authenticator "$BATCH_AUTHENTICATOR_ADDRESS" \
--l1-url "$L1_RPC_URL" \
--private-key "$OPERATOR_PRIVATE_KEY" \
--pcr0 "$PCR0"

if [ $? -ne 0 ]; then
echo "WARNING: Failed to register PCR0, continuing anyway..."
--pcr0 "$PCR0" 2>&1)
REGISTER_EXIT=$?

if [ $REGISTER_EXIT -ne 0 ]; then
echo "❌ PCR0 registration FAILED (exit code: $REGISTER_EXIT)"
echo ""
echo "Error output:"
echo "$REGISTER_OUTPUT" | head -50
echo ""
echo "CRITICAL: Batcher will NOT work without PCR0 registration!"
echo " Batch submission will fail with 'execution reverted, reason: 0x'"
exit 1
else
echo "PCR0 registration successful"
echo "✓ PCR0 registration SUCCESSFUL"
echo ""
echo "Registration output:"
echo "$REGISTER_OUTPUT"
fi
else
echo "Skipping PCR0 registration - missing required values:"
echo "=== Skipping PCR0 Registration ==="
echo "Missing required values:"
echo " PCR0: ${PCR0:-[missing]}"
echo " BATCH_AUTHENTICATOR_ADDRESS: ${BATCH_AUTHENTICATOR_ADDRESS:-[missing]}"
echo " OPERATOR_PRIVATE_KEY: ${OPERATOR_PRIVATE_KEY:+[set]}"
echo ""
echo "WARNING: Without PCR0 registration, batch submission will fail!"
exit 1
fi

# Setup tracking files for local deployment
Expand Down
1 change: 1 addition & 0 deletions espresso/scripts/prepare-allocs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ jq -s 'reduce .[] as $item ({}; . * $item)' \
<(jq '{ "alloc": map_values(.state) }' "${OP_ROOT}/espresso/environment/allocs.json") \
"${DEPLOYMENT_DIR}/deployer_allocs.json" \
"${OP_ROOT}/espresso/docker/l1-geth/devnet-genesis-template.json" \
| jq '.baseFeePerGas = "0x7"' \
> "${L1_CONFIG_DIR}/genesis.json"
38 changes: 33 additions & 5 deletions op-batcher/batcher/espresso.go
Original file line number Diff line number Diff line change
Expand Up @@ -1017,10 +1017,13 @@ func createVerifyCertTransaction(certManager *bindings.CertManagerCaller, certMa
}

func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {
l.Log.Info("=== registerBatcher() called ===")

if l.Attestation == nil {
l.Log.Warn("Attestation is nil, skipping registration")
return nil
}
l.Log.Info("Attestation available", "length", len(l.Attestation.COSESign1))

log.Info("Batch authenticator address", "value", l.RollupConfig.BatchAuthenticatorAddress)
code, err := l.L1Client.CodeAt(ctx, l.RollupConfig.BatchAuthenticatorAddress, nil)
Expand All @@ -1030,6 +1033,7 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {
if len(code) == 0 {
return fmt.Errorf("No contract deployed at this address %w", err)
}
l.Log.Info("BatchAuthenticator contract verified", "codeLength", len(code))

batchAuthenticator, err := bindings.NewBatchAuthenticator(l.RollupConfig.BatchAuthenticatorAddress, l.L1Client)
if err != nil {
Expand All @@ -1040,6 +1044,7 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {
if err != nil {
return fmt.Errorf("failed to get EspressoTEEVerifier address from BatchAuthenticator contract: %w", err)
}
l.Log.Info("Got EspressoTEEVerifier address", "address", verifierAddress)

espressoTEEVerifier, err := bindings.NewEspressoTEEVerifierCaller(verifierAddress, l.L1Client)
if err != nil {
Expand All @@ -1050,6 +1055,7 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {
if err != nil {
return fmt.Errorf("failed to get EspressoNitroTEEVerifier address from verifier contract: %w", err)
}
l.Log.Info("Got EspressoNitroTEEVerifier address", "address", nitroVerifierAddress)

nitroVerifier, err := bindings.NewEspressoNitroTEEVerifierCaller(nitroVerifierAddress, l.L1Client)
if err != nil {
Expand All @@ -1060,6 +1066,7 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {
if err != nil {
return fmt.Errorf("failed to get CertManager address from EspressoNitroTEEVerifier contract: %w", err)
}
l.Log.Info("Got CertManager address", "address", certManagerAddress)

certManager, err := bindings.NewCertManagerCaller(certManagerAddress, l.L1Client)
if err != nil {
Expand All @@ -1073,36 +1080,42 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {

// Verify every CA certiciate in the chain in an individual transaction. This avoids running into block gas limit
// that could happen if CertManager verifies the whole certificate chain in one transaction.
l.Log.Info("Starting CA certificate verification", "numCerts", len(l.Attestation.Document.CABundle))
parentCertHash := crypto.Keccak256Hash(l.Attestation.Document.CABundle[0])
for _, cert := range l.Attestation.Document.CABundle {
for i, cert := range l.Attestation.Document.CABundle {
txData, err := createVerifyCertTransaction(certManager, certManagerAbi, cert, true, parentCertHash)
if err != nil {
return fmt.Errorf("failed to create verify certificate transaction: %w", err)
return fmt.Errorf("failed to create verify certificate transaction for CA cert %d: %w", i, err)
}

parentCertHash = crypto.Keccak256Hash(cert)

// If createVerifyCertTransaction returned nil, certificate is already verified
// and there's no need to send a verification transaction for this certificate
if txData == nil {
l.Log.Info("CA certificate already verified, skipping", "certIndex", i)
continue
}

l.Log.Info("Sending CA certificate verification transaction", "certIndex", i, "to", certManagerAddress)
_, err = l.Txmgr.Send(ctx, txmgr.TxCandidate{
TxData: txData,
To: &certManagerAddress,
})

if err != nil {
return fmt.Errorf("verify certificate transaction failed: %w", err)
return fmt.Errorf("verify CA certificate %d transaction failed: %w", i, err)
}
l.Log.Info("CA certificate verification transaction sent successfully", "certIndex", i)
}

l.Log.Info("Starting client certificate verification")
txData, err := createVerifyCertTransaction(certManager, certManagerAbi, l.Attestation.Document.Certificate, false, parentCertHash)
if err != nil {
return fmt.Errorf("failed to create verify client certificate transaction: %w", err)
}
if txData != nil {
l.Log.Info("Sending client certificate verification transaction", "to", certManagerAddress)
_, err = l.Txmgr.Send(ctx, txmgr.TxCandidate{
TxData: txData,
To: &certManagerAddress,
Expand All @@ -1111,8 +1124,14 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {
if err != nil {
return fmt.Errorf("verify client certificate transaction failed: %w", err)
}
l.Log.Info("Client certificate verification transaction sent successfully")
} else {
l.Log.Info("Client certificate already verified, skipping")
}

l.Log.Info("Preparing registerSigner transaction")
l.Log.Info("Attestation data sizes", "COSESign1Length", len(l.Attestation.COSESign1), "SignatureLength", len(l.Attestation.Signature))

abi, err := bindings.BatchAuthenticatorMetaData.GetAbi()
if err != nil {
return fmt.Errorf("failed to get Batch Authenticator ABI: %w", err)
Expand All @@ -1128,12 +1147,21 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {
To: &l.RollupConfig.BatchAuthenticatorAddress,
}

l.Log.Info("Sending registerSigner transaction",
"to", l.RollupConfig.BatchAuthenticatorAddress,
"dataLength", len(txData),
"functionSelector", hexutil.Encode(txData[:4]),
"txDataPreview", hexutil.Encode(txData[:min(len(txData), 200)]))

// Try to estimate gas first to get better error message
l.Log.Info("Attempting to estimate gas for registerSigner transaction")
_, err = l.Txmgr.Send(ctx, candidate)
if err != nil {
return fmt.Errorf("failed to send transaction: %w", err)
l.Log.Error("registerSigner transaction failed with detailed error", "error", err)
return fmt.Errorf("registerSigner transaction failed: %w", err)
}

l.Log.Info("Registered batcher with the batch inbox contract")
l.Log.Info("Registered batcher with the batch inbox contract successfully")

return nil
}
Expand Down
Loading