Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Run a Node

Run a Taiko node using Docker or from source.

Architecture

Taiko nodes still follow Ethereum's execution/consensus split, but in the Shasta architecture the consensus side is driven by Taiko's L1 inbox, proposal derivation rules, and L2 anchoring logic instead of an Ethereum beacon chain. The two main components are:

  • taiko-geth — a minimally modified fork of go-ethereum that serves as the execution client. It executes L2 blocks, maintains chain state, and exposes standard Ethereum JSON-RPC interfaces.
  • taiko-client — the consensus and rollup driver. It watches the Shasta inbox on L1, derives L2 blocks from proposal data, tracks finalization, and drives taiko-geth through the Engine API.

In Shasta, the protocol no longer upgrades the old Pacaya inbox in place. It uses a separate Shasta Inbox on L1 for proposing, proving, forced inclusion, and finalization, while the L2 side uses the TaikoAnchor plus fork-router contracts to keep pre-fork and post-fork behavior compatible during the transition.

taiko-client roles

ComponentResponsibility
driverTracks L1 proposals and finalized proposal ranges, derives L2 blocks, and feeds them into the execution engine
proposerCollects transactions and submits Shasta proposals to the L1 inbox, including lookahead data when preconfirmations are enabled
proverGenerates and submits validity proofs that finalize consecutive proposal ranges

Chain synchronization

At a high level, sync works like this:

  1. Read the latest finalized proposal state from the L1 inbox
  2. Attempt to catch up to the network tip via P2P preconfirmation peers
  3. If needed, replay finalized L2 blocks through the Engine API
  4. Listen for new Proposed events on L1
  5. Reconstruct and execute the corresponding L2 blocks from proposal data and forced inclusions
  6. Keep the L2 head anchored to the L1 checkpoints exposed through the Shasta anchor path

If a proposed tx list is invalid, the protocol still advances by constructing an empty anchor-only block rather than halting execution.

APIs

Taiko nodes expose standard Ethereum-style interfaces:

  • JSON-RPC API for standard execution-layer workflows
  • Engine API for communication between taiko-client and taiko-geth

This is what allows most Ethereum tooling to work against Taiko with minimal changes.

Prerequisites

Hardware

ResourceMinimum
CPU4 cores
RAM16 GB
Storage2 TB SSD

Storage requirements grow over time. Plan accordingly.

Software

DependencyVersionCheck
Git2+git --version
Docker24+ (Docker method)docker --version
Go1.21+ (source method)go version
Make4+ (source method)make --version

L1 Endpoint

You need access to an Ethereum L1 node (execution + beacon).

  • Mainnet nodes require an Ethereum mainnet L1 endpoint.
  • Hoodi testnet nodes require an Ethereum Hoodi testnet L1 endpoint.

Docker Method

Clone simple-taiko-node

git clone https://github.com/taikoxyz/simple-taiko-node.git
cd simple-taiko-node

On Windows, also run git config core.autocrlf false after cloning.

Copy the sample environment file

Mainnet
cp .env.sample .env

Configure L1 endpoints

Open .env in a text editor and set:

L1_ENDPOINT_WS=ws://<your-l1-node>:8546
L1_BEACON_HTTP=http://<your-l1-node>:5052

Set compose profiles

In .env, set COMPOSE_PROFILES to the services you want to run:

COMPOSE_PROFILES=l2_execution_engine

Add prover to the list if you plan to prove (requires ENABLE_PROVER=true separately).

Configure preconfirmations (recommended)

To receive preconfirmed blocks and keep your node at the tip of the chain, configure these settings in .env:

  1. Set ENABLE_PRECONFS_P2P=true.

  2. Set PUBLIC_IP to your machine's external IP. If left blank, NAT traversal (PMP/UPnP) is used automatically, but manual configuration is preferred.

  3. Open these ports on your firewall/router so they are reachable from the internet:

    • TCP 4001 (or your custom P2P_TCP_PORT)
    • UDP 30303 (or your custom P2P_UDP_PORT)
  4. Set a private key for your P2P peer identity. Use either:

    • PRIV_RAW — hex-encoded private key in plaintext
    • PRIV_FILE — filename of a key file in the script/ directory

Start the node

Mainnet
docker compose up -d

You may need sudo if your user is not in the docker group.

Verify the node is running

Check that the execution engine is connected:

curl http://localhost:8547 \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{"method":"eth_chainId","params":[],"id":1,"jsonrpc":"2.0"}'

Expected response for mainnet: "result":"0x28c58" (chain ID 167000).

Check sync progress:

curl http://localhost:8547 \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}'

If the block number is 0 or not growing, inspect the logs:

docker compose logs -f

Verify P2P connectivity

Search for peer tick in the logs:

docker compose logs -f | grep "peer tick"

Look for output like:

INFO [07-30|18:37:38.168] Peer tick  peersLen=6 peers="[...]" ...

If peersLen is 6 or higher, P2P is working correctly.

From Source Method

A Taiko node has two components:

  • taiko-geth (execution engine) — executes block payloads and holds chain state. Exposes the standard Ethereum JSON-RPC API.
  • taiko-client (consensus client) — decodes L2 blocks from L1 calldata/blobspace and passes payloads to taiko-geth.

Build taiko-geth

Clone the repository and check out the release branch from the releases page:

git clone https://github.com/taikoxyz/taiko-geth.git
cd taiko-geth
git checkout <release-branch>
make geth

Build taiko-client

Clone the monorepo and check out the release branch from the releases page (search for taiko-client):

git clone https://github.com/taikoxyz/taiko-mono.git
cd taiko-mono/packages/taiko-client
git checkout <release-branch>
make build

Create a JWT secret

taiko-geth and taiko-client communicate over the Engine API, secured by a shared secret:

openssl rand -hex 32 > jwt.txt

Copy jwt.txt into both the taiko-geth and taiko-client directories.

Start taiko-geth

Mainnet
./build/bin/geth \
  --taiko \
  --networkid 167000 \
  --gcmode archive \
  --datadir ./data/taiko-geth \
  --metrics \
  --metrics.expensive \
  --metrics.addr "0.0.0.0" \
  --bootnodes enode://266a8e3b5e44201eca9c368d58aa59a7750295397e77d5b32aea2644f9962cbc4e1cb0543aab0480995a209408174413f65e5ce253d60bb83d22d3b8ab12eb89@34.142.239.251:30303,enode://264a7fc4bd1ee16cfc6eb420c643407bfc61b9c9534c5a39ba6e68c8759beda2fbeccefee8677385e3d99691eeb218da4bce7f5207cf38594ac0f6a53c128b9b@35.247.159.156:30303,enode://2d4e5b7ec0c57f9def6ebe72f9bd1f65c33c87b7dc38875bbb147c10e8ec9a8cd157558b695f9a02ac6ad789f300fab4f1f19d41273956491372e96880a3459f@34.126.90.255:30303,enode://57f4b29cd8b59dc8db74be51eedc6425df2a6265fad680c843be113232bbe632933541678783c2a5759d65eac2e2241c45a34e1c36254bccfe7f72e52707e561@104.197.107.1:30303,enode://87a68eef46cc1fe862becef1185ac969dfbcc050d9304f6be21599bfdcb45a0eb9235d3742776bc4528ac3ab631eba6816e9b47f6ee7a78cc5fcaeb10cd32574@35.232.246.122:30303 \
  --authrpc.addr "0.0.0.0" \
  --authrpc.port 28551 \
  --authrpc.vhosts "*" \
  --authrpc.jwtsecret ./jwt.txt \
  --http \
  --http.api admin,debug,eth,net,web3,txpool,miner,taiko \
  --http.addr "0.0.0.0" \
  --http.port 28545 \
  --http.vhosts "*" \
  --ws \
  --ws.api admin,debug,eth,net,web3,txpool,miner,taiko \
  --ws.addr "0.0.0.0" \
  --ws.port 28546 \
  --ws.origins "*" \
  --gpo.ignoreprice "100000000" \
  --port 30304 \
  --syncmode full \
  --state.scheme=path

Start taiko-geth first. It will wait for taiko-client to connect.

Start taiko-client

Set your L1 endpoint environment variables:

export L1_WS=<your-l1-ws-endpoint>
export L1_BEACON_URL=<your-l1-beacon-http-endpoint>
Mainnet
./bin/taiko-client driver \
  --l1.ws "${L1_ENDPOINT_WS}" \
  --l2.ws ws://localhost:28546 \
  --l1.beacon "${L1_BEACON_HTTP}" \
  --l2.auth http://localhost:28551 \
  --pacayaInbox 0x06a9Ab27c7e2255df1815E6CC0168d7755Feb19a \
  --shastaInbox 0x6f21C543a4aF5189eBdb0723827577e1EF57ef1f \
  --taikoAnchor 0x1670000000000000000000000000000000010001 \
  --shasta.time 1775135700 \
  --preconfirmation.whitelist 0xFD019460881e6EeC632258222393d5821029b2ac \
  --jwtSecret ./jwt.txt \
  --p2p.sync \
  --p2p.checkPointSyncUrl https://rpc.mainnet.taiko.xyz
  --p2p.bootnodes enode://c263741b17759f3850d24d67d6c3cbc307c73e17d80c6b12a63a4792a10529d1125d00ecf7ef4c9b0dc51d28b94dfc1b8798fb524f61a1f93946748649f73b23@34.142.239.251:4001?discport=30304,enode://2f37c3affd83274b262fa2a259d32d41510dd5a48d6e916696efe7f1598cb3f905305f5989e7b6607aab50697fb2e52cb4b6904116ed67cc5fcea1e6d66ccaba@35.247.159.156:4001?discport=30304,enode://dd83dedeff622ecfca0c5edf320266506c811539a553ddd91589cdfcc9bbd74d0d620f251d8d5e1180f19a446abbdd8b6b5301e9aa6cbad35cfd9716f80f2416@34.126.90.255:4001?discport=30304,enode://0e917d0fd54e25cd9815aa552550c938dfccafb1b09e613d1b5f344236dc2a93cdac9508a9e570a4e1a315ca7762de51f41c4a90361519d972fdd6715bb3f4f3@51.210.195.167:4001?discport=30303 \
  --p2p.listen.ip 0.0.0.0 \
  --p2p.advertise.ip ${PUBLIC_IP} \
  --p2p.listen.tcp 4001 \
  --p2p.advertise.tcp 4001 \
  --p2p.listen.udp 30303 \
  --p2p.advertise.udp 30303 \
  --p2p.peerstore.path /node-keys/peerstore \
  --p2p.discovery.path /node-keys/discv5 \
  --preconfirmation.serverPort 9871 \
  --p2p.useragent taiko \
  --p2p.priv.raw "${WALLET_PRIV_KEY}"

Monitoring

Grafana Dashboard (Docker)

A Grafana dashboard runs at http://localhost:3001 (or your custom GRAFANA_PORT):

http://localhost:3001/d/L2ExecutionEngine/l2-execution-engine-overview

Docker CLI Reference

ActionCommand
Startdocker compose up -d
Stopdocker compose down
Restartdocker compose down && docker compose up -d
Updategit pull origin main && docker compose pull
Remove (with data)docker compose down -v
View all logsdocker compose logs -f
View execution logsdocker compose logs -f l2_execution_engine
View driver logsdocker compose logs -f taiko_client_driver
Resource usagedocker stats

Troubleshooting

ProblemCauseFix
Caught SIGILL in blst_cgo_initOlder CPU incompatible with blstSet CGO_CFLAGS="-O -D__BLST_PORTABLE__" and CGO_CFLAGS_ALLOW="-O -D__BLST_PORTABLE__"
beacon client not foundMissing or incorrect --l1.beacon flagSet L1_BEACON_HTTP in .env or pass --l1.beacon with a valid beacon endpoint
Dial tcp: lookup l2_execution_engine ... server misbehavingL1 node out of sync or rate-limitedVerify L1 sync status; run your own L1 node instead of a rate-limited provider
no service selectedOutdated simple-taiko-nodePull the latest version and set COMPOSE_PROFILES in .env
failed to check whether L1 chain has been reorgedBlockPi archive mode disabledEnable the Archive feature on BlockPi, or use your own L1 node
Looking for peers (stuck)P2P sync issueSet DISABLE_P2P_SYNC=true in .env and restart
Bind for 0.0.0.0:6060 failed: port is already allocatedPort conflictStop the conflicting service or change the port in .env
Required flag "l2.suggestedFeeRecipient" not setSpaces in .env valuesRemove all trailing spaces from .env fields
Unknown shorthand flag: 'd' in -dDocker Compose v1Upgrade to Docker Compose v2 or use docker-compose up -d (hyphenated)
/bin/sh: ... not found (Windows)Windows line endings (CRLF)Delete the repo, run git config --global core.autocrlf false, and re-clone
Dial tcp: connect: connection refusedFirewall blocking portsCheck firewall rules with sudo ufw status and allow the required ports
No contract code at given addressNode not synced or wrong networkWait for L1 to fully sync; verify you are on the correct network
Database contains incompatible genesisOld testnet dataRun docker compose down -v to remove old volumes
genesis header hash mismatchWrong docker-compose fileUse the correct file for your network (e.g., docker-compose-hoodi.yml for Hoodi)