Skip to content

blockblaz/native-quickstart

Repository files navigation

Native Quickstart

A tool to quickly bring up a devnet with:

  • L1 node running 0xpartha/geth:latest
  • L2 node running 0xpartha/geth:latest
  • Native sequencer running 0xpartha/native-sequencer:latest

Features

  • Optional Genesis Generation: Generate genesis file with --generate-genesis flag (10 wallets, 100 ETH each by default)
  • Pre-configured Accounts: All accounts are pre-funded and ready to use
  • Safe Defaults: Uses existing genesis file by default (prevents accidental overwrites)
  • Easy Configuration: Configurable via command-line arguments or environment variables
  • Docker-based: Uses Docker containers for easy setup and cleanup
  • Single Command: Start everything with one command (or start individual services)
  • Individual Service Control: Start/stop individual services (L1, L2, sequencer) independently
  • Automatic Block Production: L1 uses Clique PoA consensus (blocks every 5 seconds)
  • Sequencer-driven L2: L2 blocks produced by sequencer via Engine API
  • JWT Authentication: Automatically generates and configures JWT secret for Engine API authentication
  • RPC Request Logging: Full RPC request/response logging enabled for debugging
  • NativeRollup Contract: Automatically deploys NativeRollup contract on L1
  • Foundry Auto-install: Automatically installs Foundry if not present

Requirements

  • Docker: Required to run geth and sequencer containers
  • Python 3: Required for genesis generation
  • curl: Required for health checks (usually pre-installed)

Optional

  • eth-account Python library: For proper Ethereum address derivation

    pip install eth-account

    If not installed, the script uses a deterministic fallback method suitable for devnets.

  • Foundry: Automatically installed if not present (required for NativeRollup contract deployment)

Quick Start

Basic Usage

# First time: Generate genesis file and start devnet (all services)
./start-devnet.sh --generate-genesis

# Subsequent runs: Use existing genesis file and start all services (default behavior)
./start-devnet.sh

# Stop all services
./start-devnet.sh --stop

Important: The script uses existing genesis files by default. If no genesis file exists, you'll get an error prompting you to use --generate-genesis.

Starting Individual Services

You can start individual services independently:

# Start only L1 node
./start-devnet.sh --start-l1

# Start only L2 node
./start-devnet.sh --start-l2

# Start only sequencer
./start-devnet.sh --start-sequencer

# Start all services (default behavior when no flags specified)
./start-devnet.sh

Note: When starting individual services, the script will:

  • Only initialize and start the specified service
  • Only clean up containers/ports for the specified service
  • Deploy NativeRollup contract only if L1 is being started
  • Create Docker network if needed

Custom Configuration

# Generate genesis with custom parameters and start
./start-devnet.sh --generate-genesis --num-wallets 20 --wallet-balance 200

# Start with custom ports (uses existing genesis)
./start-devnet.sh --l1-port 8545 --l2-port 18545 --sequencer-port 18547

# Clean start (removes existing data, then use existing genesis)
./start-devnet.sh --clean-data

# Clean start with new genesis generation
./start-devnet.sh --clean-data --generate-genesis

# Explicitly generate genesis file (overwrites existing)
./start-devnet.sh --generate-genesis

# Skip genesis generation (use existing genesis file - default behavior)
./start-devnet.sh --no-genesis

# Use custom Docker images
./start-devnet.sh --geth-image mygeth:latest --sequencer-image mysequencer:latest

Command-Line Options

Option Description Default
--data-dir DIR Data directory ./data
--genesis-dir DIR Genesis directory ./genesis
--num-wallets N Number of wallets to create 10
--wallet-balance ETH Balance per wallet in ETH 100
--l1-chain-id ID L1 chain ID 61971
--l2-chain-id ID L2 chain ID 61972
--l1-port PORT L1 RPC port 8545
--l2-port PORT L2 RPC port 18545
--l2-engine-port PORT L2 Engine API port 18551
--sequencer-port PORT Sequencer RPC port 18547
--sequencer-metrics PORT Sequencer metrics port 9090
--geth-image IMAGE Geth Docker image 0xpartha/geth:latest
--sequencer-image IMAGE Sequencer Docker image 0xpartha/native-sequencer:latest
--clean-data Clean data directories before starting false
--generate-genesis Generate genesis file (overwrites existing) false (use existing)
--no-genesis Skip genesis generation (default behavior) true (default)
--stop Stop all running containers -
--start-l1 Start only L1 node -
--start-l2 Start only L2 node -
--start-sequencer Start only sequencer -
--stop-l1 Stop only L1 node -
--stop-l2 Stop only L2 node -
--stop-sequencer Stop only sequencer -
--help Show help message -

Note: --no-genesis is the default behavior. The script will use existing genesis files and fail with a clear error message if the genesis file doesn't exist, prompting you to use --generate-genesis.

Environment Variables

All command-line options can also be set via environment variables:

export DATA_DIR=./my-data
export NUM_WALLETS=20
export WALLET_BALANCE=200
export L1_PORT=8545
export L2_PORT=18545
./start-devnet.sh

Services

After starting, the following services are available:

  • L1 Node: http://localhost:8545 (default)
    • Uses Clique PoA consensus - automatically produces blocks every 5 seconds
    • First account from genesis is the block signer/miner
  • L2 Node: http://localhost:18545 (default)
    • Blocks are produced by the sequencer via Engine API
    • No local mining - receives blocks from sequencer
  • L2 Engine API: http://localhost:18551 (default)
    • Used by sequencer to submit blocks to L2 node
  • Sequencer: http://localhost:18547 (default)
    • Produces L2 blocks and submits them via Engine API
  • Sequencer Metrics: http://localhost:9090 (default)

NativeRollup Contract

The script automatically deploys the NativeRollup contract on L1 after all services are started:

  • Contract address is displayed in the startup summary
  • Uses the first account from genesis as the deployer
  • Deterministic deployment (same address on each devnet start)
  • Contract validates execute transaction chainId and calls EXECUTE precompile

Account Management

Generated Accounts

When you generate a genesis file (with --generate-genesis), accounts are created and saved to:

  • genesis/accounts.txt - Contains addresses and private keys in format: address:private_key
  • genesis/genesis.json - Genesis file with pre-funded accounts

Using Accounts

You can use the accounts in your applications:

# View accounts
cat genesis/accounts.txt

# Extract first account address
head -n 1 genesis/accounts.txt | cut -d: -f1

# Extract first account private key
head -n 1 genesis/accounts.txt | cut -d: -f2

Example: Send Transaction

# Get first account
ACCOUNT=$(head -n 1 genesis/accounts.txt | cut -d: -f1)
PRIVATE_KEY=$(head -n 1 genesis/accounts.txt | cut -d: -f2)

# Send transaction via L1
curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_sendTransaction\",
    \"params\": [{
      \"from\": \"$ACCOUNT\",
      \"to\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb\",
      \"value\": \"0x2386f26fc10000\"
    }],
    \"id\": 1
  }"

Monitoring

View Logs

# L1 node logs (includes RPC request logging)
docker logs -f native-quickstart-l1

# L2 node logs (includes RPC request logging)
docker logs -f native-quickstart-l2

# Sequencer logs
docker logs -f native-quickstart-sequencer

Note: Both L1 and L2 nodes have RPC request logging enabled (--vmodule "rpc=5,http=5"). You'll see detailed logs of all JSON-RPC requests and responses, making it easy to debug and monitor interactions with the nodes.

Block Production

# Check L1 block number (should increase every 5 seconds)
cast block-number --rpc-url http://localhost:8545

# Check L2 block number (produced by sequencer)
cast block-number --rpc-url http://localhost:18545

# Watch L1 blocks being produced
watch -n 1 'cast block-number --rpc-url http://localhost:8545'

Check Status

# Check if containers are running
docker ps | grep native-quickstart

# Check L1 node
curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# Check L2 node
curl -X POST http://localhost:18545 \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# Check sequencer metrics
curl http://localhost:9090

Stopping the Devnet

# Stop all containers
./start-devnet.sh --stop

# Stop individual services
./start-devnet.sh --stop-l1      # Stop only L1
./start-devnet.sh --stop-l2      # Stop only L2
./start-devnet.sh --stop-sequencer  # Stop only sequencer

# Or manually stop containers
docker stop native-quickstart-l1 native-quickstart-l2 native-quickstart-sequencer
docker rm native-quickstart-l1 native-quickstart-l2 native-quickstart-sequencer

JWT Authentication

The script automatically generates and configures JWT authentication for Engine API communication between the sequencer and L2 geth:

  • JWT Secret Generation: A 32-byte JWT secret is automatically generated on first run and stored at data/jwt.hex
  • L2 Geth Configuration: The JWT secret is mounted into the L2 geth container and configured via --authrpc.jwtsecret
  • Sequencer Configuration: The same JWT secret is passed to the sequencer via the L2_JWT_SECRET environment variable
  • Persistence: The JWT secret persists across restarts (unless --clean-data is used)

Note: The JWT secret file (data/jwt.hex) is automatically added to .gitignore for security.

Data Persistence

Data is stored in the data/ directory by default:

  • data/l1/ - L1 node data
  • data/l2/ - L2 node data
  • data/sequencer/ - Sequencer data
  • data/jwt.hex - JWT secret for Engine API authentication (auto-generated)

To start fresh:

./start-devnet.sh --clean-data

Note: Using --clean-data will also remove the JWT secret file, generating a new one on the next run.

Genesis File

The genesis file is generated in genesis/genesis.json and includes:

  • Pre-funded accounts (10 wallets with 100 ETH each by default)
  • Chain configuration
  • Network ID
  • Clique PoA consensus configuration (for L1 block production)
    • Block period: 5 seconds
    • First account is configured as the signer

Genesis Generation Behavior

The script defaults to using existing genesis files for safety:

  • Default (--no-genesis): Use existing genesis file
    • If genesis file exists: Uses it and starts the devnet
    • If genesis file doesn't exist: Shows error message prompting to use --generate-genesis
  • --generate-genesis: Generate a new genesis file (overwrites existing if present)

Error Message: If you run the script without --generate-genesis and no genesis file exists, you'll see:

❌ Error: Genesis file not found: ./genesis/genesis.json

   Please run the script with --generate-genesis option to create a new genesis file:
   ./start-devnet.sh --generate-genesis

   Or create genesis.json manually in ./genesis

Examples:

# First time setup: Generate genesis and start
./start-devnet.sh --generate-genesis

# Subsequent runs: Use existing genesis (default)
./start-devnet.sh

# Regenerate genesis with custom parameters
./start-devnet.sh --generate-genesis --num-wallets 20 --wallet-balance 200

# Generate genesis file manually, then start
./generate-genesis.sh --num-wallets 10 --wallet-balance 100
./start-devnet.sh

Troubleshooting

Port Already in Use

If a port is already in use, specify different ports:

./start-devnet.sh --l1-port 28545 --l2-port 28546 --sequencer-port 28547

Container Won't Start

Check logs:

docker logs native-quickstart-l1
docker logs native-quickstart-l2
docker logs native-quickstart-sequencer

Genesis File Issues

Error: "Genesis file not found"

❌ Error: Genesis file not found: ./genesis/genesis.json

   Please run the script with --generate-genesis option to create a new genesis file:
   ./start-devnet.sh --generate-genesis

Solution: Run with --generate-genesis flag:

./start-devnet.sh --generate-genesis

Regenerate existing genesis file:

./start-devnet.sh --generate-genesis

Clean start with new genesis:

./start-devnet.sh --clean-data --generate-genesis

Docker Image Pull Fails

The script will try to use local images if pull fails. Make sure you have the images:

docker pull 0xpartha/geth:latest
docker pull 0xpartha/native-sequencer:latest

Account Generation Issues

If you encounter issues with account generation, install the eth-account library:

pip install eth-account

Architecture

Block Production

  • L1 Node: Uses Clique (Proof of Authority) consensus

    • Automatically produces blocks every 5 seconds
    • First account from genesis is the signer/miner
    • No beacon node required
    • Block rewards go to the signer account
  • L2 Node: Receives blocks from sequencer

    • No local mining/mining flags
    • Blocks are produced by the sequencer
    • Sequencer submits blocks via Engine API (engine_newPayloadV2, engine_forkchoiceUpdatedV2)
    • Standard rollup architecture

Consensus Mechanisms

  • L1: Clique PoA (Proof of Authority)

    • Simple consensus for devnets
    • Automatic block production
    • No external dependencies
  • L2: Engine API (PoS-like)

    • Sequencer-driven block production
    • Compatible with standard rollup architecture
    • Engine API for block submission

Advanced Usage

Starting Services Individually

You can start services one at a time for debugging or development:

# Start L1 first
./start-devnet.sh --start-l1

# Wait for L1 to be ready, then start L2
./start-devnet.sh --start-l2

# Finally start the sequencer
./start-devnet.sh --start-sequencer

Use Cases:

  • Debug individual service startup issues
  • Test services independently
  • Start services in a specific order
  • Restart a single service without affecting others

Note: When starting individual services:

  • The Docker network is created automatically if needed
  • Only the specified service's containers are cleaned up
  • NativeRollup contract is deployed only when starting L1 (or all services)

Custom Chain IDs

# Use custom chain IDs (defaults are 61971 for L1, 61972 for L2)
./start-devnet.sh --l1-chain-id 1337 --l2-chain-id 1338

Note: If you change chain IDs, make sure to regenerate the genesis file:

./start-devnet.sh --clean-data --generate-genesis --l1-chain-id 1337 --l2-chain-id 1338

Multiple Devnets

Run multiple devnets on different ports:

# Devnet 1
DATA_DIR=./data1 ./start-devnet.sh --l1-port 8545 --l2-port 18545 --sequencer-port 18547

# Devnet 2
DATA_DIR=./data2 ./start-devnet.sh --l1-port 28545 --l2-port 28546 --sequencer-port 28547

NativeRollup Contract

The NativeRollup contract is automatically deployed on L1 after all services start. The contract address is displayed in the startup summary.

Contract Features:

  • Validates chainId from execute transaction calldata
  • Calls EXECUTE precompile (address 0x12) to validate witness data
  • Returns gas consumed or errors on failure
  • Located in native-rollup/ directory

Using the Contract:

# Contract address is shown in startup summary
# Example usage with cast:
cast call <CONTRACT_ADDRESS> "chainId()" --rpc-url http://localhost:8545

Integration with Other Tools

The devnet can be integrated with other development tools:

# Set environment variables for your tools
export L1_RPC_URL=http://localhost:8545
export L2_RPC_URL=http://localhost:18545
export SEQUENCER_RPC_URL=http://localhost:18547

# Your tool can now connect to the devnet

RPC Request Logging

Both L1 and L2 nodes log all RPC requests with detailed information:

  • Incoming JSON-RPC requests
  • Method calls and parameters
  • HTTP request details
  • Response data

View logs to see all RPC activity:

# View L1 RPC requests
docker logs -f native-quickstart-l1 | grep -i rpc

# View L2 RPC requests
docker logs -f native-quickstart-l2 | grep -i rpc

License

See LICENSE file.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •