diff --git a/README_ESPRESSO.md b/README_ESPRESSO.md index 2ab569ba2a1..5ecf2bbc56f 100644 --- a/README_ESPRESSO.md +++ b/README_ESPRESSO.md @@ -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 diff --git a/espresso/docker-compose.yml b/espresso/docker-compose.yml index 053daf3960c..5627a31fbef 100644 --- a/espresso/docker-compose.yml +++ b/espresso/docker-compose.yml @@ -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}" @@ -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 diff --git a/espresso/docker/l1-geth/devnet-genesis-template.json b/espresso/docker/l1-geth/devnet-genesis-template.json index 8af2de39e98..cd9ce3ad3e7 100644 --- a/espresso/docker/l1-geth/devnet-genesis-template.json +++ b/espresso/docker/l1-geth/devnet-genesis-template.json @@ -57,7 +57,7 @@ "number": "0x0", "gasUsed": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "baseFeePerGas": "0x3b9aca00", + "baseFeePerGas": "0x7", "excessBlobGas": null, "blobGasUsed": null } diff --git a/espresso/docker/l1-geth/l1-geth-init.sh b/espresso/docker/l1-geth/l1-geth-init.sh index 822c5c24ebf..c3e122995e0 100644 --- a/espresso/docker/l1-geth/l1-geth-init.sh +++ b/espresso/docker/l1-geth/l1-geth-init.sh @@ -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'" diff --git a/espresso/docker/op-batcher-tee/run-enclave.sh b/espresso/docker/op-batcher-tee/run-enclave.sh index 9ba86cab307..34a68c6cc57 100755 --- a/espresso/docker/op-batcher-tee/run-enclave.sh +++ b/espresso/docker/op-batcher-tee/run-enclave.sh @@ -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 diff --git a/espresso/scripts/prepare-allocs.sh b/espresso/scripts/prepare-allocs.sh index 053050b5934..bb4585a30e7 100755 --- a/espresso/scripts/prepare-allocs.sh +++ b/espresso/scripts/prepare-allocs.sh @@ -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" diff --git a/op-batcher/batcher/espresso.go b/op-batcher/batcher/espresso.go index 9ae4c68f624..e898f6521d2 100644 --- a/op-batcher/batcher/espresso.go +++ b/op-batcher/batcher/espresso.go @@ -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) @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -1073,11 +1080,12 @@ 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) @@ -1085,24 +1093,29 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error { // 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, @@ -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) @@ -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 }