Run a Node
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 ofgo-ethereumthat 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 drivestaiko-geththrough 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
| Component | Responsibility |
|---|---|
driver | Tracks L1 proposals and finalized proposal ranges, derives L2 blocks, and feeds them into the execution engine |
proposer | Collects transactions and submits Shasta proposals to the L1 inbox, including lookahead data when preconfirmations are enabled |
prover | Generates and submits validity proofs that finalize consecutive proposal ranges |
Chain synchronization
At a high level, sync works like this:
- Read the latest finalized proposal state from the L1 inbox
- Attempt to catch up to the network tip via P2P preconfirmation peers
- If needed, replay finalized L2 blocks through the Engine API
- Listen for new
Proposedevents on L1 - Reconstruct and execute the corresponding L2 blocks from proposal data and forced inclusions
- 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-clientandtaiko-geth
This is what allows most Ethereum tooling to work against Taiko with minimal changes.
Prerequisites
Hardware
| Resource | Minimum |
|---|---|
| CPU | 4 cores |
| RAM | 16 GB |
| Storage | 2 TB SSD |
Storage requirements grow over time. Plan accordingly.
Software
| Dependency | Version | Check |
|---|---|---|
| Git | 2+ | git --version |
| Docker | 24+ (Docker method) | docker --version |
| Go | 1.21+ (source method) | go version |
| Make | 4+ (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-nodeOn Windows, also run git config core.autocrlf false after cloning.
Copy the sample environment file
cp .env.sample .envConfigure 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>:5052Set compose profiles
In .env, set COMPOSE_PROFILES to the services you want to run:
COMPOSE_PROFILES=l2_execution_engineAdd 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:
-
Set
ENABLE_PRECONFS_P2P=true. -
Set
PUBLIC_IPto your machine's external IP. If left blank, NAT traversal (PMP/UPnP) is used automatically, but manual configuration is preferred. -
Open these ports on your firewall/router so they are reachable from the internet:
- TCP
4001(or your customP2P_TCP_PORT) - UDP
30303(or your customP2P_UDP_PORT)
- TCP
-
Set a private key for your P2P peer identity. Use either:
PRIV_RAW— hex-encoded private key in plaintextPRIV_FILE— filename of a key file in thescript/directory
Start the node
docker compose up -dYou 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 -fVerify 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 gethBuild 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 buildCreate a JWT secret
taiko-geth and taiko-client communicate over the Engine API, secured by a shared secret:
openssl rand -hex 32 > jwt.txtCopy jwt.txt into both the taiko-geth and taiko-client directories.
Start taiko-geth
./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=pathStart 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>./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-overviewDocker CLI Reference
| Action | Command |
|---|---|
| Start | docker compose up -d |
| Stop | docker compose down |
| Restart | docker compose down && docker compose up -d |
| Update | git pull origin main && docker compose pull |
| Remove (with data) | docker compose down -v |
| View all logs | docker compose logs -f |
| View execution logs | docker compose logs -f l2_execution_engine |
| View driver logs | docker compose logs -f taiko_client_driver |
| Resource usage | docker stats |
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
Caught SIGILL in blst_cgo_init | Older CPU incompatible with blst | Set CGO_CFLAGS="-O -D__BLST_PORTABLE__" and CGO_CFLAGS_ALLOW="-O -D__BLST_PORTABLE__" |
beacon client not found | Missing or incorrect --l1.beacon flag | Set L1_BEACON_HTTP in .env or pass --l1.beacon with a valid beacon endpoint |
Dial tcp: lookup l2_execution_engine ... server misbehaving | L1 node out of sync or rate-limited | Verify L1 sync status; run your own L1 node instead of a rate-limited provider |
no service selected | Outdated simple-taiko-node | Pull the latest version and set COMPOSE_PROFILES in .env |
failed to check whether L1 chain has been reorged | BlockPi archive mode disabled | Enable the Archive feature on BlockPi, or use your own L1 node |
Looking for peers (stuck) | P2P sync issue | Set DISABLE_P2P_SYNC=true in .env and restart |
Bind for 0.0.0.0:6060 failed: port is already allocated | Port conflict | Stop the conflicting service or change the port in .env |
Required flag "l2.suggestedFeeRecipient" not set | Spaces in .env values | Remove all trailing spaces from .env fields |
Unknown shorthand flag: 'd' in -d | Docker Compose v1 | Upgrade 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 refused | Firewall blocking ports | Check firewall rules with sudo ufw status and allow the required ports |
No contract code at given address | Node not synced or wrong network | Wait for L1 to fully sync; verify you are on the correct network |
Database contains incompatible genesis | Old testnet data | Run docker compose down -v to remove old volumes |
genesis header hash mismatch | Wrong docker-compose file | Use the correct file for your network (e.g., docker-compose-hoodi.yml for Hoodi) |