AENEID VALIDATOR

Aeneid Story Node Setup

Complete guide to deploying and managing a high-performance Story Protocol validator node on the Aeneid testnet

NETWORK STATUS: ACTIVE

System Requirements

Component Minimum Recommended
OS Ubuntu 20.04 Ubuntu 22.04 LTS
CPU 4 Cores 8+ Cores
RAM 8GB 16GB+
Storage 500GB SSD/NVMe 1TB SSD/NVMe
Network 10Mbps 100Mbps+

Manual Installation

Step 1: Install Dependencies

bash
sudo apt update && sudo apt upgrade -y
sudo apt install curl git wget htop tmux build-essential jq make lz4 gcc unzip -y

Step 2: Install Go

bash
cd $HOME
VER="1.22.5"
wget "https://golang.org/dl/go$VER.linux-amd64.tar.gz"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go$VER.linux-amd64.tar.gz"
rm "go$VER.linux-amd64.tar.gz"
[ ! -f ~/.bash_profile ] && touch ~/.bash_profile
echo "export PATH=$PATH:/usr/local/go/bin:~/go/bin" >> ~/.bash_profile
source $HOME/.bash_profile
[ ! -d ~/go/bin ] && mkdir -p ~/go/bin

Step 3: Set Environment Variables

bash
echo "export MONIKER=\"Your_Node_Name\"" >> $HOME/.bash_profile
echo "export STORY_CHAIN_ID=\"aeneid\"" >> $HOME/.bash_profile
echo "export STORY_PORT=\"56\"" >> $HOME/.bash_profile
source $HOME/.bash_profile

Step 4: Install Story Node

bash
cd $HOME
rm -rf story-geth
git clone https://github.com/piplabs/story-geth.git
cd story-geth
git checkout v1.0.2
make geth
mv build/bin/geth $HOME/go/bin/
[ ! -d "$HOME/.story/story" ] && mkdir -p "$HOME/.story/story"
[ ! -d "$HOME/.story/geth" ] && mkdir -p "$HOME/.story/geth"

cd $HOME
rm -rf story
git clone https://github.com/piplabs/story
cd story
git checkout v1.3.0
go build -o story ./client 
mkdir -p $HOME/go/bin/
mv $HOME/story/story $HOME/go/bin/

story init --moniker $MONIKER --network $STORY_CHAIN_ID

Node Configuration

Configure Peers and Ports

bash
SEEDS="46b7995b0b77515380000b7601e6fc21f783e16f@story-testnet-seed.itrocket.net:52656"
PEERS="01f8a2148a94f0267af919d2eab78452c90d9864@story-testnet-peer.itrocket.net:52656,b66b0df0720b38f9405f8a5c50511365ec621b2a@135.181.181.59:62656,9308260b6cb4ca1faa9f3025bac0bc2636c4b020@185.232.68.94:26656,db6791a8e35dee076de75aebae3c89df8bba3374@65.109.50.22:56656,a8d01e154197d799637eca4f0f369dc215db6b70@144.76.111.9:26656,311cd3903e25ab85e5a26c44510fbc747ab61760@152.53.87.97:36656,9d34ab3819aa8baa75589f99138318acfa0045f5@95.217.119.251:30900,5eb1d392045c1159a94bdb49916341ac4a787500@157.180.93.155:52656,34c910cde040e983f076195175ed2fe7d447b486@152.53.102.226:26656,dfb96be7e47cd76762c1dd45a5f76e536be47faa@65.108.45.34:32655,381b10bd04853b375f9a1d42983a0fbfa753e4aa@37.59.22.162:26656"
sed -i -e "/^\[p2p\]/,/^\[/{s/^[[:space:]]*seeds *=.*/seeds = \"$SEEDS\"/}" \
       -e "/^\[p2p\]/,/^\[/{s/^[[:space:]]*persistent_peers *=.*/persistent_peers = \"$PEERS\"/}" $HOME/.story/story/config/config.toml

# Set custom ports
sed -i.bak -e "s%:1317%:${STORY_PORT}317%g;
s%:8551%:${STORY_PORT}551%g" $HOME/.story/story/config/story.toml

sed -i.bak -e "s%:26658%:${STORY_PORT}658%g;
s%:26657%:${STORY_PORT}657%g;
s%:26656%:${STORY_PORT}656%g;
s%^external_address = \"\"%external_address = \"$(wget -qO- eth0.me):${STORY_PORT}656\"%;
s%:26660%:${STORY_PORT}660%g" $HOME/.story/story/config/config.toml

# Enable prometheus and disable indexing
sed -i -e "s/prometheus = false/prometheus = true/" $HOME/.story/story/config/config.toml
sed -i -e "s/^indexer *=.*/indexer = \"null\"/" $HOME/.story/story/config/config.toml

Create Service Files

bash
# Create geth service file
sudo tee /etc/systemd/system/story-geth.service > /dev/null <<'EOF'
[Unit]
Description=Story Geth daemon
After=network-online.target

[Service]
User=$USER
ExecStart=$HOME/go/bin/geth --aeneid --syncmode full --http --http.api eth,net,web3,engine --http.vhosts '*' --http.addr 0.0.0.0 --http.port ${STORY_PORT}545 --authrpc.port ${STORY_PORT}551 --ws --ws.api eth,web3,net,txpool --ws.addr 0.0.0.0 --ws.port ${STORY_PORT}546
Restart=on-failure
RestartSec=3
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

# Create story service file
sudo tee /etc/systemd/system/story.service > /dev/null <<'EOF'
[Unit]
Description=Story Service
After=network.target

[Service]
User=$USER
WorkingDirectory=$HOME/.story/story
ExecStart=$(which story) run

Restart=on-failure
RestartSec=5
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF

Sync from Snapshot

Download and Install Snapshot

bash
# Backup priv_validator_state.json
cp $HOME/.story/story/data/priv_validator_state.json $HOME/.story/story/priv_validator_state.json.backup

# Remove old data and unpack Story snapshot
rm -rf $HOME/.story/story/data
curl https://server-3.itrocket.net/testnet/story/story_2025-06-27_6011823_snap.tar.lz4 | lz4 -dc - | tar -xf - -C $HOME/.story/story

# Restore priv_validator_state.json
mv $HOME/.story/story/priv_validator_state.json.backup $HOME/.story/story/data/priv_validator_state.json

# Delete geth data and unpack Geth snapshot
rm -rf $HOME/.story/geth/aeneid/geth/chaindata
mkdir -p $HOME/.story/geth/aeneid/geth
curl https://server-3.itrocket.net/testnet/story/geth_story_2025-06-27_6011823_snap.tar.lz4 | lz4 -dc - | tar -xf - -C $HOME/.story/geth/aeneid/geth

Start Services

bash
sudo systemctl daemon-reload
sudo systemctl enable story story-geth
sudo systemctl restart story-geth && sleep 5 && sudo systemctl restart story

Essential Commands

Check Sync Status

bash
journalctl -u story -u story-geth -f -o cat

Check Node Info

bash
curl localhost:$(sed -n '/\[rpc\]/,/laddr/ { /laddr/ {s/.*://; s/".*//; p} }' $HOME/.story/story/config/config.toml)/status | jq

Check Peer Info

bash
echo "$(curl localhost:$(sed -n '/\[rpc\]/,/laddr/ { /laddr/ {s/.*://; s/".*//; p} }' $HOME/.story/story/config/config.toml)/status | jq -r '.result.node_info.id')@$(wget -qO- eth0.me):$(sed -n '/Address to listen for incoming connection/{n;p;}' $HOME/.story/story/config/config.toml | sed 's/.*://; s/".*//')"

Upgrade Binary

Upgrade Story Node

bash
cd $HOME
rm -rf story
git clone https://github.com/piplabs/story
cd story
git checkout v1.3.0
go build -o story ./client 
sudo systemctl stop story-geth
wget -O $(which geth) https://github.com/piplabs/story-geth/releases/download/v1.1.0/geth-linux-amd64
chmod +x $(which geth)
sudo systemctl start story-geth
sudo mv $HOME/story/story $(which story)
sudo systemctl restart story && sudo journalctl -u story -f

Verify Version

bash
story version

Should return: v1.3.0

Sync/Snapshot

Sync Using Snapshot

bash
# Install dependencies and disable statesync
sudo apt install curl tmux jq lz4 unzip -y
sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1false|" $HOME/.story/story/config/config.toml

# Stop node and backup priv_validator_state.json
sudo systemctl stop story story-geth
cp $HOME/.story/story/data/priv_validator_state.json $HOME/.story/story/priv_validator_state.json.backup

# Remove old data and unpack Story snapshot
rm -rf $HOME/.story/story/data
curl https://server-3.itrocket.net/testnet/story/story_2025-06-27_6011823_snap.tar.lz4 | lz4 -dc - | tar -xf - -C $HOME/.story/story

# Restore priv_validator_state.json
mv $HOME/.story/story/priv_validator_state.json.backup $HOME/.story/story/data/priv_validator_state.json

# Delete geth data and unpack Geth snapshot
rm -rf $HOME/.story/geth/aeneid/geth/chaindata
curl https://server-3.itrocket.net/testnet/story/geth_story_2025-06-27_6011823_snap.tar.lz4 | lz4 -dc - | tar -xf - -C $HOME/.story/geth/aeneid/geth

# Restart node and check logs
sudo systemctl restart story story-geth
sudo journalctl -u story-geth -u story -f

Public API/RPC Endpoints

Public RPC Endpoints

bash
https://rpc-evm-story-aeneid.onenov.xyz
https://api-story-aeneid.onenov.xyz
https://rpc-story-aeneid.onenov.xyz
https://grpc-story-aeneid.onenov.xyz
wss-story-aeneid.onenov.xyz
wss-evm-story-aeneid.onenov.xyz

Local RPC

bash
http://localhost:5657

CLI Cheatsheet

Service Operations

bash
# Check logs
sudo journalctl -u story -f

# Start service
sudo systemctl start story

# Stop service
sudo systemctl stop story

# Restart service
sudo systemctl restart story

# Check service status
sudo systemctl status story

# Reload services
sudo systemctl daemon-reload

# Enable Service
sudo systemctl enable story

# Disable Service
sudo systemctl disable story

Node Information

bash
# Node info
curl localhost:$(sed -n '/\[rpc\]/,/laddr/ { /laddr/ {s/.*://; s/".*//; p} }' $HOME/.story/story/config/config.toml)/status | jq

# Your node peer
echo "$(curl localhost:$(sed -n '/\[rpc\]/,/laddr/ { /laddr/ {s/.*://; s/".*//; p} }' $HOME/.story/story/config/config.toml)/status | jq -r '.result.node_info.id')@$(wget -qO- eth0.me):$(sed -n '/Address to listen for incoming connection/{n;p;}' $HOME/.story/story/config/config.toml | sed 's/.*://; s/".*//')"

# Your enode
geth --exec "admin.nodeInfo.enode" attach ~/.story/geth/aeneid/geth.ipc

Staking Operations

bash
# Delegate to yourself
story validator stake --chain-id 1315 --validator-pubkey $(story validator export | grep "Compressed Public Key (hex)" | awk '{print $NF}') --stake 1000000000000000000 --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2}')

# Delegate
story validator stake --chain-id 1315 --validator-pubkey  --stake 1000000000000000000 --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2}')

# Delegate on behalf of other delegator
story validator stake-on-behalf --chain-id 1315 --validator-pubkey  --delegator-pubkey  --stake 1000000000000000000 --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2}')

# Add operator
story validator add-operator --chain-id 1315 --operator  --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2})

# Unstake from yourself
story validator unstake --chain-id 1315 --validator-pubkey $(story validator export | grep "Compressed Public Key (hex)" | awk '{print $NF}') --unstake 1000000000000000000 --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2})

# Unstake
story validator unstake --chain-id 1315 --validator-pubkey  --unstake 1000000000000000000 --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2})

# Unstake on behalf of other delegator
story validator unstake-on-behalf --chain-id 1315 --validator-pubkey  --delegator-pubkey  --unstake 1000000000000000000 --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2})

# Remove operator
story validator remove-operator --operator  --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2})

# Set or change withdrawal address
story validator set-withdrawal-address --withdrawal-address  --private-key $(cat $HOME/.story/story/config/private_key.txt | grep "PRIVATE_KEY" | awk -F'=' '{print $2})