diff --git a/.gitignore b/.gitignore index 3490453..cc91919 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ devnet/saved-cannon-data devnet/init.log devnet/l1-geth/ profiling/ +devnet/mainnet.genesis.json \ No newline at end of file diff --git a/devnet/3-op-init.sh b/devnet/3-op-init.sh index d83868e..a9113d6 100755 --- a/devnet/3-op-init.sh +++ b/devnet/3-op-init.sh @@ -12,22 +12,31 @@ sed_inplace() { fi } -# Check if FORK_BLOCK is set -if [ -z "$FORK_BLOCK" ]; then - echo " ❌ FORK_BLOCK environment variable is not set" - echo "Please set FORK_BLOCK in your .env file" - exit 1 -fi +# ======================================== +# Genesis Preparation +# ======================================== +if [ "$USE_FAKE_MAINNET" = "true" ]; then + # Fake mainnet mode: use unified script with mainnet genesis + source scripts/prepare-genesis.sh + _prepare_mainnet_genesis +else + # Original generated genesis logic + if [ -z "$FORK_BLOCK" ]; then + echo " ❌ FORK_BLOCK environment variable is not set" + echo "Please set FORK_BLOCK in your .env file" + exit 1 + fi -FORK_BLOCK_HEX=$(printf "0x%x" "$FORK_BLOCK") -sed_inplace '/"config": {/,/}/ s/"optimism": {/"legacyXLayerBlock": '"$((FORK_BLOCK + 1))"',\n "optimism": {/' ./config-op/genesis.json -sed_inplace 's/"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"/"parentHash": "'"$PARENT_HASH"'"/' ./config-op/genesis.json -sed_inplace '/"70997970c51812dc3a010c7d01b50e0d17dc79c8": {/,/}/ s/"balance": "[^"]*"/"balance": "0x446c3b15f9926687d2c40534fdb564000000000000"/' ./config-op/genesis.json -NEXT_BLOCK_NUMBER=$((FORK_BLOCK + 1)) -NEXT_BLOCK_NUMBER_HEX=$(printf "0x%x" "$NEXT_BLOCK_NUMBER") -sed_inplace 's/"number": 0/"number": '"$NEXT_BLOCK_NUMBER"'/' ./config-op/rollup.json -cp ./config-op/genesis.json ./config-op/genesis-reth.json -sed_inplace 's/"number": "0x0"/"number": "'"$NEXT_BLOCK_NUMBER_HEX"'"/' ./config-op/genesis-reth.json + FORK_BLOCK_HEX=$(printf "0x%x" "$FORK_BLOCK") + sed_inplace '/"config": {/,/}/ s/"optimism": {/"legacyXLayerBlock": '"$((FORK_BLOCK + 1))"',\n "optimism": {/' ./config-op/genesis.json + sed_inplace 's/"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"/"parentHash": "'"$PARENT_HASH"'"/' ./config-op/genesis.json + sed_inplace '/"70997970c51812dc3a010c7d01b50e0d17dc79c8": {/,/}/ s/"balance": "[^"]*"/"balance": "0x446c3b15f9926687d2c40534fdb564000000000000"/' ./config-op/genesis.json + NEXT_BLOCK_NUMBER=$((FORK_BLOCK + 1)) + NEXT_BLOCK_NUMBER_HEX=$(printf "0x%x" "$NEXT_BLOCK_NUMBER") + sed_inplace 's/"number": 0/"number": '"$NEXT_BLOCK_NUMBER"'/' ./config-op/rollup.json + cp ./config-op/genesis.json ./config-op/genesis-reth.json + sed_inplace 's/"number": "0x0"/"number": "'"$NEXT_BLOCK_NUMBER_HEX"'"/' ./config-op/genesis-reth.json +fi # Extract contract addresses from state.json and update .env file echo "🔧 Extracting contract addresses from state.json..." diff --git a/devnet/example.env b/devnet/example.env index ce39fe7..0033125 100644 --- a/devnet/example.env +++ b/devnet/example.env @@ -49,6 +49,11 @@ SKIP_BUILD_PRESTATE=false # Set to false if you need full mode with op-proposer, op-challenger, op-dispute-mon MIN_RUN=true +# ============================================================================== +# Fake Mainnet Configuration +# ============================================================================== +USE_FAKE_MAINNET=false + # ============================================================================== # Docker & Network Configuration # ============================================================================== diff --git a/devnet/scripts/prepare-genesis.sh b/devnet/scripts/prepare-genesis.sh new file mode 100755 index 0000000..e6c034f --- /dev/null +++ b/devnet/scripts/prepare-genesis.sh @@ -0,0 +1,233 @@ +#!/bin/bash +# ============================================================================== +# prepare-genesis.sh - Unified genesis preparation script +# ============================================================================== +# Supports two modes: +# 1. Mainnet genesis mode (USE_FAKE_MAINNET=true) +# - Downloads and uses real mainnet genesis data (6.6GB+) +# - Requires MIN_RUN=true +# 2. Generated genesis mode (default) +# - Uses genesis generated by op-deployer +# +# Usage: +# source scripts/prepare-genesis.sh # Called from 3-op-init.sh +# ./scripts/prepare-genesis.sh # Standalone execution +# ============================================================================== + +set -e + +MAINNET_GENESIS_URL="https://okg-pub-hk.oss-cn-hongkong.aliyuncs.com/cdn/chain/xlayer/snapshot/merged.genesis.json.mainnet.tar.gz" +MAINNET_GENESIS_PATH="mainnet.genesis.json" +TEST_ACCOUNT_ADDRESS="0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +TEST_ACCOUNT_BALANCE="0x52B7D2DCC80CD2E4000000" # 100,000 ETH + +# ============================================================================== +# Helper Functions +# ============================================================================== +_sed_inplace() { + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "$@" + else + sed -i "$@" + fi +} + +# ============================================================================== +# Download Mainnet Genesis +# ============================================================================== +_download_mainnet_genesis() { + if [ -f "$MAINNET_GENESIS_PATH" ]; then + echo "✅ Mainnet genesis already exists: $MAINNET_GENESIS_PATH" + return 0 + fi + + echo "📥 Downloading mainnet genesis..." + echo " URL: $MAINNET_GENESIS_URL" + + local TAR_FILE="mainnet-genesis.tar.gz" + + # Download + if ! curl -L --progress-bar "$MAINNET_GENESIS_URL" -o "$TAR_FILE"; then + echo "❌ ERROR: Failed to download mainnet genesis" + exit 1 + fi + + echo "📂 Extracting..." + tar -xzf "$TAR_FILE" + + # Find and rename the extracted file + if [ -f "merged.genesis.json" ]; then + mv "merged.genesis.json" "$MAINNET_GENESIS_PATH" + elif [ -f "merged.genesis.json.mainnet" ]; then + mv "merged.genesis.json.mainnet" "$MAINNET_GENESIS_PATH" + else + echo "❌ ERROR: Extraction failed (genesis file not found in archive)" + rm -f "$TAR_FILE" + exit 1 + fi + + rm -f "$TAR_FILE" + echo "✅ Downloaded and extracted successfully" +} + +# ============================================================================== +# Mainnet Genesis Mode +# ============================================================================== +_prepare_mainnet_genesis() { + echo "" + echo "🌐 Mainnet genesis mode enabled" + + # 1. Enforce MIN_RUN requirement + if [ "$MIN_RUN" != "true" ]; then + echo "" + echo "❌ ERROR: Mainnet genesis requires MIN_RUN=true" + echo "" + echo "Reason:" + echo " • Mainnet genesis is too large (6.6GB+)" + echo " • Building op-program prestate would fail or timeout" + echo " • Dispute game features are not compatible with mainnet data" + echo "" + echo "Solution:" + echo " Set MIN_RUN=true in your .env file" + echo "" + exit 1 + fi + echo "✅ MIN_RUN=true verified" + + # 2. Download genesis if not exists + _download_mainnet_genesis + + # Verify file size + GENESIS_SIZE_MB=$(du -m "$MAINNET_GENESIS_PATH" | cut -f1) + GENESIS_SIZE_GB=$(echo "scale=2; $GENESIS_SIZE_MB / 1024" | bc) + echo "✅ Found mainnet genesis ($GENESIS_SIZE_GB GB)" + + # 3. Validate configuration + if [ -z "$FORK_BLOCK" ] || [ -z "$PARENT_HASH" ]; then + echo "❌ ERROR: FORK_BLOCK and PARENT_HASH must be set" + exit 1 + fi + + if [ -z "$CHAIN_ID" ]; then + echo "❌ ERROR: CHAIN_ID must be set" + exit 1 + fi + + NEXT_BLOCK=$((FORK_BLOCK + 1)) + echo "" + echo "🎯 Configuration:" + echo " • CHAIN_ID: $CHAIN_ID" + echo " • FORK_BLOCK: $FORK_BLOCK" + echo " • PARENT_HASH: $PARENT_HASH" + echo " • Next block: $NEXT_BLOCK" + echo " • Test account: $TEST_ACCOUNT_ADDRESS" + + # 4. Process genesis using embedded Python (optimized for large files) + echo "" + echo "🔧 Processing genesis (this may take 1-2 minutes)..." + + mkdir -p "$CONFIG_DIR" + + # Run embedded Python script + python3 - "$MAINNET_GENESIS_PATH" "$CONFIG_DIR/genesis.json" "$NEXT_BLOCK" "$PARENT_HASH" "$CHAIN_ID" "$TEST_ACCOUNT_ADDRESS" "$TEST_ACCOUNT_BALANCE" << 'PYTHON_EOF' +import json +import sys +import os +import time + +def main(): + input_file = sys.argv[1] + output_file = sys.argv[2] + next_block = int(sys.argv[3]) + parent_hash = sys.argv[4] + chain_id = int(sys.argv[5]) + test_account = sys.argv[6] if len(sys.argv) > 6 and sys.argv[6] else None + test_balance = sys.argv[7] if len(sys.argv) > 7 and sys.argv[7] else None + + # Load genesis + file_size_gb = os.path.getsize(input_file) / (1024**3) + print(f" Loading genesis ({file_size_gb:.2f} GB)...") + + with open(input_file, 'r') as f: + genesis = json.load(f) + + account_count = len(genesis.get('alloc', {})) + print(f" ✓ Loaded {account_count:,} accounts") + + # Update config fields + if 'config' not in genesis: + genesis['config'] = {} + + # Replace chainId with configured value + old_chain_id = genesis['config'].get('chainId', 'unknown') + genesis['config']['chainId'] = chain_id + print(f" ✓ chainId: {old_chain_id} → {chain_id}") + + genesis['config']['legacyXLayerBlock'] = next_block + genesis['config']['jovianTime'] = 0 # Enable Jovian upgrade + genesis['parentHash'] = parent_hash + genesis['number'] = 0 # Required for geth init + + # Update timestamp to 15 minutes in the future (avoid conductor "unsafe head falling behind" error) + # This gives buffer time between init and service startup + current_timestamp = int(time.time()) + 15 * 60 # +15 minutes + genesis['timestamp'] = hex(current_timestamp) + + print(f" ✓ legacyXLayerBlock: {next_block}") + print(f" ✓ jovianTime: 0 (Jovian upgrade enabled)") + print(f" ✓ parentHash: {parent_hash[:20]}...") + print(f" ✓ number: 0 (required for geth init)") + print(f" ✓ timestamp: {hex(current_timestamp)} (+15min from now)") + + # Inject test account (enabled by default in mainnet mode) + if test_account and test_balance: + if 'alloc' not in genesis: + genesis['alloc'] = {} + + account_key = test_account.lower() + if account_key.startswith('0x'): + account_key = account_key[2:] + + if account_key in genesis['alloc']: + print(f" ⚠️ Account {test_account} exists, updating balance...") + genesis['alloc'][account_key]['balance'] = test_balance + else: + print(f" 💰 Injecting test account {test_account}...") + genesis['alloc'][account_key] = {"balance": test_balance} + + balance_eth = int(test_balance, 16) / (10**18) + print(f" ✓ Test balance: {balance_eth:,.0f} ETH") + + # Write genesis.json + print(f" Writing genesis.json...") + with open(output_file, 'w') as f: + json.dump(genesis, f, separators=(',', ':')) + + # Create reth version (number as hex string "0x0") + reth_file = output_file.replace('.json', '-reth.json') + genesis['number'] = "0x0" + + print(f" Writing genesis-reth.json...") + with open(reth_file, 'w') as f: + json.dump(genesis, f, separators=(',', ':')) + + output_size_gb = os.path.getsize(output_file) / (1024**3) + print(f" ✓ Output size: {output_size_gb:.2f} GB") + +if __name__ == '__main__': + main() +PYTHON_EOF + + if [ $? -ne 0 ]; then + echo "❌ ERROR: Failed to process mainnet genesis" + exit 1 + fi + + # 5. Update rollup.json + _sed_inplace 's/"number": 0/"number": '"$NEXT_BLOCK"'/' ./config-op/rollup.json + + echo "" + echo "✅ Mainnet genesis prepared" + echo " • Output: $CONFIG_DIR/genesis.json" + echo " • Reth version: $CONFIG_DIR/genesis-reth.json" +}