> For the complete documentation index, see [llms.txt](https://docs.ethscriptions.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ethscriptions.com/ethscriptions-appchain/running-a-node.md).

# Running a Node

This guide explains how to run your own Ethscriptions AppChain node using Docker Compose.

## Prerequisites

* **Docker Desktop** (includes the Compose plugin)
* **L1 RPC endpoint** - Archive-quality recommended for historical sync

## Quick Start

```bash
# Clone the repository
git clone https://github.com/ethscriptions-protocol/ethscriptions-node.git
cd ethscriptions-node

# Copy the environment template
cp docker-compose/.env.example docker-compose/.env

# Edit .env with your settings (see Environment Reference below)
# At minimum, set L1_RPC_URL to your L1 endpoint

# Bring up the stack
cd docker-compose
docker compose --env-file .env up -d

# Follow logs while it syncs
docker compose logs -f node

# Query the L2 RPC (default port 8545)
curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# Shut down when done
docker compose down
```

## Services

The stack runs two containers:

| Service | Description                                               |
| ------- | --------------------------------------------------------- |
| `geth`  | Ethscriptions-customized Ethereum execution client (L2)   |
| `node`  | Ruby derivation app that processes L1 data into L2 blocks |

The node waits for geth to be healthy before starting. Both services communicate via a shared IPC socket.

## Environment Reference

Key variables in `docker-compose/.env`:

### Core Configuration

| Variable               | Description                                       | Default                      |
| ---------------------- | ------------------------------------------------- | ---------------------------- |
| `COMPOSE_PROJECT_NAME` | Docker resource naming prefix                     | `ethscriptions-evm`          |
| `JWT_SECRET`           | 32-byte hex for Engine API auth (must match geth) | —                            |
| `L1_NETWORK`           | Ethereum network (mainnet, sepolia, etc.)         | `mainnet`                    |
| `L1_RPC_URL`           | Archive-quality L1 RPC endpoint                   | —                            |
| `L1_GENESIS_BLOCK`     | L1 block where the rollup anchors                 | `17478949`                   |
| `GENESIS_FILE`         | Genesis snapshot filename                         | `ethscriptions-mainnet.json` |
| `GETH_EXTERNAL_PORT`   | Host port for L2 RPC                              | `8545`                       |

### Performance Tuning

| Variable              | Description                   | Default |
| --------------------- | ----------------------------- | ------- |
| `L1_PREFETCH_FORWARD` | Blocks to prefetch ahead      | `200`   |
| `L1_PREFETCH_THREADS` | Prefetch worker threads       | `10`    |
| `JOB_CONCURRENCY`     | SolidQueue worker concurrency | `6`     |
| `JOB_THREADS`         | Job worker threads            | `3`     |

### Geth Configuration

| Variable           | Description                                 | Default  |
| ------------------ | ------------------------------------------- | -------- |
| `GC_MODE`          | `full` (pruned) or `archive` (full history) | `full`   |
| `STATE_HISTORY`    | State trie history depth                    | `100000` |
| `TX_HISTORY`       | Transaction history depth                   | `100000` |
| `ENABLE_PREIMAGES` | Retain preimages                            | `true`   |
| `CACHE_SIZE`       | State cache size                            | `25000`  |

### Validation (Optional)

| Variable                     | Description                            | Default |
| ---------------------------- | -------------------------------------- | ------- |
| `VALIDATION_ENABLED`         | Enable validator against reference API | `false` |
| `ETHSCRIPTIONS_API_BASE_URL` | Reference API endpoint                 | —       |
| `ETHSCRIPTIONS_API_KEY`      | API authentication key                 | —       |

## Monitoring

### View Logs

```bash
# All services
docker compose logs -f

# Just the derivation node
docker compose logs -f node

# Just geth
docker compose logs -f geth
```

### Check Block Height

```bash
# L2 block number
curl -s -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' | jq -r '.result' | xargs printf "%d\n"
```

### Check Sync Status

The derivation node logs show the current L1 block being processed. Compare this to the current L1 head to gauge sync progress.

## Validator (Optional)

The validator compares L2 state against a reference Ethscriptions API to verify derivation correctness. It pauses the importer when discrepancies appear so you can investigate.

To enable:

```bash
VALIDATION_ENABLED=true
ETHSCRIPTIONS_API_BASE_URL=https://your-api-endpoint.com
ETHSCRIPTIONS_API_KEY=your-api-key
```

The temporary SQLite databases in `storage/` and the SolidQueue worker pool support this reconciliation. Once historical import is verified, the derivation app remains stateless.

## Local Development

If you want to modify the Ruby code outside of Docker:

```bash
# Install Ruby 3.4.x (via rbenv, rvm, or asdf)
ruby --version  # Should show 3.4.x

# Install dependencies
bundle install

# Initialize local SQLite files
bin/setup

# Run the derivation (requires running ethscriptions-geth and L1 RPC)
# See bin/jobs and config/derive_ethscriptions_blocks.rb
```

The Docker Compose stack is recommended for production-like runs.

## Troubleshooting

### Node won't start

* Check that geth is healthy: `docker compose ps`
* Verify `L1_RPC_URL` is accessible
* Ensure `JWT_SECRET` matches between services

### Slow sync

* Increase `L1_PREFETCH_FORWARD` and `L1_PREFETCH_THREADS`
* Use a faster L1 RPC endpoint
* Consider archive mode (`GC_MODE=archive`) only if needed

### Out of disk space

* Pruned mode (`GC_MODE=full`) uses less space
* Reduce `STATE_HISTORY` and `TX_HISTORY`

## Resources

* [GitHub Repository](https://github.com/ethscriptions-protocol/ethscriptions-node)
* [ethscriptions-geth](https://github.com/ethscriptions-protocol/ethscriptions-geth)
