> ## Documentation Index
> Fetch the complete documentation index at: https://docs.story.foundation/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

> Guide to running a validator node on the Story Network

## Quick Links

<CardGroup cols={2}>
  <Card title="Story Geth Releases" icon="github" href="https://github.com/piplabs/story-geth/releases">
    Download the latest Story Geth client releases
  </Card>

  <Card title="Story Releases" icon="github" href="https://github.com/piplabs/story/releases/">
    Download the latest Story consensus client releases
  </Card>
</CardGroup>

# Overview

This section will guide you through how you can run your own validator. Validator operations may be done via the `story` consensus client.

<Note>
  The below operations do not require running a node! However, if you would like
  to participate in staking rewards, you must run a validator node.
</Note>

Before proceeding, it is important to familiarize yourself with the difference between a delegator and a validator:

* A **validator** is a full node that participates in consensus whose signed key resides in the `priv_validator_key.json` file under your `story` data directory. To print out your validator key details you may refer to the [validator key export section](/network/become-a-validator#validator-key-export)
* A **delegator** refers to an account operator that holds `IP` and wishes to participate in consensus rewards but without needing to run a validator themselves.

In the same folder as where your `story` binary resides, add a `.env` file with a `PRIVATE_KEY` whose account has `IP` funded. **We recommend using your delegator account for all below operations.**

<Note>
  You may also issue transactions as the validator itself. To get the EVM
  private key corresponding to your validator, please refer to the [Validator
  Key Export](#validator-key-export) section. From **Story v1.2.0**, user must
  use `.env` for all operations.
</Note>

The `.env` file should look like the following *(make sure not to add a 0x prefix):*

```bash theme={null}
# ~/.env
PRIVATE_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

With this, you are all set to perform different validator operations! Below, we will guide you through all of those supported via the CLI:

## Validator Key Export

By default, when you run `./story init` a validator key is created for you. To view your validator key, run the following command:

```bash theme={null}
./story validator export [flags]
```

This will print out your validator public key file in compressed and uncompressed formats. By default, we use the hex-encoded compressed key for public identification.

```text theme={null}
Compressed Public Key (hex): 03bdc7b8940babe9226d52d7fa299a1faf3d64a82f809889256c8f146958a63984
Compressed Public Key (base64): A73HuJQLq+kibVLX+imaH689ZKgvgJiJJWyPFGlYpjmE
Uncompressed Public Key (hex): 04bdc7b8940babe9226d52d7fa299a1faf3d64a82f809889256c8f146958a6398496b9e2af0a3a1d199c3cc1d09ee899336a530c185df6b46a9735b25e79a493af
EVM Address: 0x9EacBe2C3B1eb0a9FC14106d97bd3A1F89efdDCc
Validator Address: storyvaloper1p470h0jtph4n5hztallp8vznq8ehylsw9vpddx
Delegator Address: story1p470h0jtph4n5hztallp8vznq8ehylswtr4vxd
```

**Available Flags:**

* `--export-evm-key`: (bool) Exports the derived EVM private key of your validator into the default data config directory
* `--export-evm-key-path`: (string) Specifies a different download location for the derived EVM private key of your validator
* `--keyfile`: (string) Path to the Tendermint key file (default "/home/ubuntu/.story/story/config/priv\_validator\_key.json")

<Tip>
  If you would like to issue transactions as your validator, and not as a
  delegator, you may export the key to your `.env` file and ensure it has IP
  sent to it, e.g. via `./story validator export --export-evm-key --evm-key-path
      .env`
</Tip>

## Validator Creation

To create a new validator, run the following command:

```bash Locked token node theme={null}
./story validator create
       --stake ${AMOUNT_TO_STAKE_IN_WEI} \
       --moniker ${VALIDATOR_NAME} \
       --rpc ${rpc} \
       --chain-id ${chain_id} \
       --commission-rate ${rate} \
       --unlocked=false
```

```Text Unlocked token node theme={null}
./story validator create
       --stake ${AMOUNT_TO_STAKE_IN_WEI} \
       --moniker ${VALIDATOR_NAME} \
       --rpc ${rpc} \
       --chain-id ${chain_id} \
       --commission-rate ${rate} \
```

This will create the validator corresponding to your validator key saved in `priv_validator_key.json`, providing the validator with `{$AMOUNT_TO_STAKE_IN_WEI}` IP to self-stake.

<Note>
  To participate in consensus, at least 1024 IP must be staked (equivalent to
  `1024000000000000000000 wei`)!
</Note>

Below is a list of optional flags to further customize your validator setup:

**Available Flags:**

* `--stake`: Sets the amount the validator will self-delegate in wei (default is `1024000000000000000000` wei).
* `--moniker`: Defines a custom name for the validator, visible to users on the network.
* `--chain-id`: Specifies the Chain ID for the transaction. By default, this is set to `1516`.
* `--commission-rate`: Sets the validator's commission rate in bips (1% = 100 bips). For instance, `1000` represents a 10% commission (default is `1000`).
* `--explorer`: Specifies the URL of the blockchain explorer (default: [https://www.storyscan.io](https://www.storyscan.io)).
* `--keyfile`: Points to the path of the Tendermint key file (default: `$HOME/.story/story/config/priv_validator_key.json`).
* `--max-commission-change-rate`: Sets the maximum rate at which the validator's commission can change, in bips. For example, `100` represents a maximum change of 1% (default is `1000`).
* `--max-commission-rate`: Defines the maximum commission rate the validator can charge, in bips. For instance, `5000` allows a 50% maximum rate (default is `5000`).
* `--rpc`: Sets the RPC URL to connect to the network (default: [https://mainnet.storyrpc.io](https://mainnet.storyrpc.io)).
* `--unlocked`: Determines if unlocked token staking is supported (`true` for unlocked staking, `false` for locked staking). By default, this is set to `true`.
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

### Example creation command use

```bash theme={null}
story validator create
  --stake 1024000000000000000000
  --moniker "timtimtim"
  --commission-rate 700
  --validator-pubkey "<validator_pubkey>" # if you dont have a .env
  --rpc "https://mainnet.storyrpc.io"
  --chain-id 1514
```

### Verifying your validator

Once created, please use the `Explorer URL` to confirm the transaction. If successful, you should see your validator pub key (*found in your`priv_validator_key.json` file)* listed as part of the following endpoint:

```bash theme={null}
curl https://testnet.storyrpc.io/validators | jq .
```

Congratulations, you are now one of Story’s very first IP validators!

## Validator Staking

To stake to an existing validator, run the following command:

```bash theme={null}
./story validator stake \
   --validator-pubkey ${VALIDATOR_PUB_KEY_IN_HEX} \
   --stake ${AMOUNT_TO_STAKE_IN_WEI}
   --staking-period ${STAKING_PERIOD}
```

* Note that your own `${VALIDATOR_PUB_KEY_IN_HEX}`may be found by running the `./story validator export` command as the `Compressed Public Key (hex)`.
* You must stake at least 1024 IP worth (`*1024000000000000000000 wei`) for the transaction to be valid

Once staked, you may use the `Explorer URL` to confirm the transaction. As mentioned earlier, you may use our [validator endpoint](https://mainnet.storyrpc.io/validators) to confirm the new voting power of the validator.

**Available Flags:**

* `--validator-pubkey`: (string) The public key of the validator to stake to
* `--stake`: (string) The amount of IP to stake in wei
* `--chain-id`: (int) Chain ID to use for the transaction (default: 1514)
* `--explorer`: (string) URL of the blockchain explorer
* `--help`, `-h`: Display help information for stake command
* `--rpc`: (string) RPC URL to connect to the network
* `--staking-period`: (stakingPeriod) Staking period (options: "flexible", "short", "medium", "long") (default: flexible)
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

### Example staking command use

```bash theme={null}
./story validator stake \
  --validator-pubkey 03bdc7b8940babe9226d52d7fa299a1faf3d64a82f809889256c8f146958a63984 \
  --stake 1024000000000000000000
  --staking-period "short"
```

## Validator Unstaking

To unstake from a validator, run the following command:

```bash theme={null}
./story validator unstake \
  --validator-pubkey ${VALIDATOR_PUB_KEY_IN_HEX} \
  --unstake ${AMOUNT_TO_UNSTAKE_IN_WEI} \
  --delegation-id ${ID_STAKING_PERIOD}
```

This will unstake `${AMOUNT_TO_UNSTAKE_IN_WEI}` IP from the selected validator. You must unstake at least 1024 IP worth (`*1024000000000000000000 wei`) for the transaction to be valid.

Like in the staking operation, please use the `Explorer URL` to confirm the transaction and our [validator endpoint](https://mainnet.storyrpc.io/validators) to double-check the newly reduced voting power of the validator.

**Available Flags:**

* `--chain-id`: (int) Chain ID to use for the transaction (default: 1514)
* `--delegation-id`: (uint32) The delegation ID (0 for flexible staking)
* `--explorer`: (string) URL of the blockchain explorer (default: "[https://www.storyscan.io](https://www.storyscan.io)")
* `--help`, `-h`: Help for unstake command
* `--rpc`: (string) RPC URL to connect to the network (default: "[https://mainnet.storyrpc.io](https://mainnet.storyrpc.io)")
* `--unstake`: (string) Amount to unstake in wei
* `--validator-pubkey`: (string) Validator's hex-encoded compressed 33-byte secp256k1 public key
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

### Example unstaking command use

```bash theme={null}
./story validator unstake \
   --validator-pubkey 03bdc7b8940babe9226d52d7fa299a1faf3d64a82f809889256c8f146958a63984 \
   --unstake 1024000000000000000000 \
   --delegation-id 1
```

## Validator Stake-on-behalf

To stake on behalf of another delegator, run the following command:

```bash theme={null}
./story validator stake-on-behalf \
  --delegator-address ${DELEGATOR_EVM} \
  --validator-pubkey ${VALIDATOR_PUB_KEY_IN_HEX} \
  --stake ${AMOUNT_TO_STAKE_IN_WEI} \
  --staking-period ${STAKING_PERIOD} \
  --rpc
  --chain-id
```

This will stake `${AMOUNT_TO_STAKE_IN_WEI}` IP to the validator on behalf of the provided delegator. You must stake at least 1024 IP worth (`*1024000000000000000000 wei`) for the transaction to be valid.

Like in the other staking operations, please use the `Explorer URL` to confirm the transaction and our [validator endpoint](https://mainnet.storyrpc.io/validators) to double-check the increased voting power of the validator.

**Available Flags:**

* `--chain-id`: (int) Chain ID to use for the transaction (default: 1514)
* `--delegator-address`: (string) Delegator's EVM address
* `--explorer`: (string) URL of the blockchain explorer (default: "[https://www.storyscan.io](https://www.storyscan.io)")
* `--help`, `-h`: Help for stake-on-behalf command
* `--rpc`: (string) RPC URL to connect to the network (default: "[https://mainnet.storyrpc.io](https://mainnet.storyrpc.io)")
* `--stake`: (string) Amount for the validator to self-delegate in wei
* `--staking-period`: (stakingPeriod) Staking period (options: "flexible", "short", "medium", "long") (default: flexible)
* `--validator-pubkey`: (string) Validator's hex-encoded compressed 33-byte secp256k1 public key
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

### Example Stake-on-behalf command use

```bash theme={null}
./story validator stake-on-behalf \
   --delegator-address 0xF84ce113FCEe12d78Eb41590c273498157c91520 \
   --validator-pubkey 03e42b4d778cda2f3612c85161ba7c0aad1550a872f3279d99e028a1dfa7854930 \
   --stake 1024000000000000000000 \
   --staking-period "short" \
   --rpc \
   --chain-id
```

## Validator Unstake-on-behalf

You may also unstake on behalf of delegators. However, to do so, you must be registered as an authorized operator for that delegator. To unstake on behalf of another delegator as an operator, run the following command:

```bash theme={null}
./story validator unstake-on-behalf \
  --delegator-address ${DELEGATOR_PUB_KEY_IN_HEX} \
  --validator-pubkey ${VALIDATOR_PUB_KEY_IN_HEX} \
  --unstake ${AMOUNT_TO_STAKE_IN_WEI} \
  --rpc \
  --chain-id
```

This will unstake `${AMOUNT_TO_STAKE_IN_WEI}` IP from the validator on behalf of the delegator, assuming you are a registered operator for that delegator. You must unstake at least 1024 IP worth (`*1024000000000000000000 wei`) for the transaction to be valid.

Like in the other staking operations, please use the `Explorer URL` to confirm the transaction and our [validator endpoint](https://mainnet.storyrpc.io/validators) to double-check the decreased voting power of the validator.

**Available Flags:**

* `--chain-id`: (int) Chain ID to use for the transaction (default: 1514)
* `--delegator-address`: (string) Delegator's EVM address
* `--explorer`: (string) URL of the blockchain explorer (default: "[https://www.storyscan.io](https://www.storyscan.io)")
* `--help`, `-h`: Help for unstake-on-behalf command
* `--rpc`: (string) RPC URL to connect to the network (default: "[https://mainnet.storyrpc.io](https://mainnet.storyrpc.io)")
* `--unstake`: (string) Amount to unstake in wei
* `--validator-pubkey`: (string) Validator's hex-encoded compressed 33-byte secp256k1 public key
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

### Example Unstake-on-behalf command use

```bash theme={null}
./story validator unstake-on-behalf \
   --delegator-address 0xF84ce113FCEe12d78Eb41590c273498157c91520 \
   --validator-pubkey 03e42b4d778cda2f3612c85161ba7c0aad1550a872f3279d99e028a1dfa7854930 \
   --unstake 1024000000000000000000 \
   --rpc \
   --chain-id
```

## Validator Unjail

In case a validator becomes jailed, for example if it experiences substantial downtime, you may use the following command to unjail the targeted validator:

```Text Bash theme={null}
./story validator unjail \
  --rpc
  --chain-id
```

Note that you will need at least 1 IP in the wallet submitting the transaction for the transaction to be valid.

**Available Flags:**

* `--chain-id`: (int) Chain ID to use for the transaction
* `--explorer`: (string) URL of the blockchain explorer
* `--rpc`: (string) RPC URL to connect to the network
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

### Example unjail command use

```bash theme={null}
./story validator unjail \
  --rpc \
  --chain-id
```

## Validator Unjail-on-behalf

If you are an authorized operator, you may unjail a validator on their behalf using the following command:

```bash theme={null}
./story validator unjail-on-behalf \
  --validator-pubkey ${VALIDATOR_PUB_KEY_IN_HEX} \
  --rpc \
  --chain-id
```

**Available Flags:**

* `--chain-id`: (int) Chain ID to use for the transaction
* `--explorer`: (string) URL of the blockchain explorer
* `--rpc`: (string) RPC URL to connect to the network
* `--validator-pubkey`: (string) Validator's hex-encoded compressed 33-byte secp256k1 public key
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

### Example unjail-on-behalf command use

```bash theme={null}
./story validator unjail-on-behalf \
  --rpc \
  --chain-id
```

## Validator rollback

<Warning>
  The snapshot must be taken from a node that has already been upgraded. That
  means the snapshot node has to do the rewind.
</Warning>

Recovery Options for Nodes Stuck in Long Rewind After Upgrade：

Wait for resync: Let the node catch up naturally. This may take time depending on the rewind depth and network bandwidth.
Apply a snapshot: Use a snapshot from a node that has already been upgraded to Pectra. You can generate your own or obtain one from trusted community providers.

```bash theme={null}
./story validator rollback \
  --rpc \
  --chain-id
```

\*\* Avaliable Flages:\*\*

* `--api-address`: (string) The API server address to listen on (default "\***\*\*\*\***:1317")
* `--api-enable`: (bool) Define if the API server should be enabled
* `--api-enable-unsafe-cors`: (bool) Enable unsafe CORS for API server
* `--api-idle-timeout`: (uint) Define the API server idle timeout (in seconds) (default 10)
* `--api-max-header-bytes`: (uint) Define the API server max header (in bytes) (default 8192)
* `--api-read-header-timeout`: (uint) Define the API server read header timeout (in seconds) (default 10)
* `--api-read-timeout`: (uint) Define the API server read timeout (in seconds) (default 10)
* `--api-write-timeout`: (uint) Define the API server write timeout (in seconds) (default 10)
* `--app-db-backend`: (string) The type of database for application and snapshots databases (default "goleveldb")
* `--engine-endpoint`: (string) An EVM execution client Engine API http endpoint (default "[http://localhost:8551](http://localhost:8551)")
* `--engine-jwt-file`: (string) The path to the Engine API JWT file
* `--evm-build-delay`: (duration) Minimum delay between triggering and fetching a EVM payload build (default 600ms)
* `--evm-build-optimistic`: (bool) Enables optimistic building of EVM payloads on previous block finalize (default true)
* `--help`: (bool) help for rollback
* `--home`: (string) The application home directory containing config and data (default "/home/timothyshen/.story/story")
* `--log-color`: (string) Log color (only applicable to console format); auto, force, disable (default "auto")
* `--log-format`: (string) Log format; console, json (default "console")
* `--log-level`: (string) Log level; debug, info, warn, error (default "info")
* `--min-retain-blocks`: (uint) Minimum block height offset during ABCI commit to prune CometBFT blocks
* `--network`: (string) Story network to participate in: story, odyssey, aeneid or local
* `--number`: (uint) number of blocks to rollback (default 1)
* `--pruning`: (string) Pruning strategy (default|nothing|everything) (default "nothing")
* `--snapshot-interval`: (uint) State sync snapshot interval (default 1000)
* `--snapshot-keep-recent`: (uint) State sync snapshot to keep (default 2)
* `--tracing-endpoint`: (string) Tracing OTLP endpoint
* `--tracing-headers`: (string) Tracing OTLP headers

### Example rollback command use

```bash theme={null}
./story validator rollback \
  --rpc \
  --chain-id
```

## Validator Redelegate

To redelegate from one validator to another, run the following command:

```bash theme={null}
./story validator redelegate \
  --validator-src-pubkey ${VALIDATOR_SRC_PUB_KEY_IN_HEX} \
  --validator-dst-pubkey ${VALIDATOR_DST_PUB_KEY_IN_HEX} \
  --redelegate ${AMOUNT_TO_REDELEGATE_IN_WEI}
  --rpc \
  --chain-id
```

**Available Flags:**

* `--chain-id`: (int) Chain ID to use for the transaction (default 1514)
* `--delegation-id`: (uint32) The delegation ID (0 for flexible staking)
* `--explorer`: (string) URL of the blockchain explorer (default "[https://www.storyscan.io](https://www.storyscan.io)")
* `--help`, `-h`: Help for redelegate command
* `--redelegate`: (string) Amount to redelegate in wei
* `--rpc`: (string) RPC URL to connect to the network (default "[https://mainnet.storyrpc.io](https://mainnet.storyrpc.io)")
* `--validator-dst-pubkey`: (string) Dst validator's hex-encoded compressed 33-byte secp256k1 public key
* `--validator-src-pubkey`: (string) Src validator's hex-encoded compressed 33-byte secp256k1 public key
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

≈

```bash theme={null}
./story validator redelegate \
  --validator-src-pubkey 03bdc7b8940babe9226d52d7fa299a1faf3d64a82f809889256c8f146958a63984 \
  --validator-dst-pubkey 02ed58a9319aba87f60fe08e87bc31658dda6bfd7931686790a2ff803846d4e59c \
  --redelegate 1024000000000000000000 \
  --rpc \
  --chain-id
```

## Validator Redelegate-on-behalf

If you are an authorized operator, you may redelegate from one validator to another on behalf of a delegator using the following command:

```bash theme={null}
./story validator redelegate-on-behalf \
  --delegator-address ${DELEGATOR_EVM_ADDRESS} \
  --validator-src-pubkey ${VALIDATOR_SRC_PUB_KEY_IN_HEX} \
  --validator-dst-pubkey ${VALIDATOR_DST_PUB_KEY_IN_HEX} \
  --redelegate ${AMOUNT_TO_REDELEGATE_IN_WEI} \
  --rpc \
  --chain-id
```

**Available Flags:**

* `--chain-id`: (int) Chain ID to use for the transaction (default 1514)
* `--delegation-id`: (uint32) The delegation ID (0 for flexible staking)
* `--delegator-address`: (string) Delegator's EVM address
* `--explorer`: (string) URL of the blockchain explorer (default "[https://www.storyscan.io](https://www.storyscan.io)")
* `--help`, `-h`: Help for redelegate-on-behalf command
* `--redelegate`: (string) Amount to redelegate in wei
* `--rpc`: (string) RPC URL to connect to the network (default "[https://mainnet.storyrpc.io](https://mainnet.storyrpc.io)")
* `--validator-dst-pubkey`: (string) Dst validator's hex-encoded compressed 33-byte secp256k1 public key
* `--validator-src-pubkey`: (string) Src validator's hex-encoded compressed 33-byte secp256k1 public key
* `--story-api`: Prevent potential fund losses. By default, you should set `http://localhost:1317`as the value

### Example redelegate-on-behalf command use

```bash theme={null}
./story validator redelegate-on-behalf \
  --delegator-address 0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab \
  --validator-src-pubkey 03bdc7b8940babe9226d52d7fa299a1faf3d64a82f809889256c8f146958a63984 \
  --validator-dst-pubkey 02ed58a9319aba87f60fe08e87bc31658dda6bfd7931686790a2ff803846d4e59c \
  --redelegate 1024000000000000000000 \
  --rpc \
  --chain-id
```

## Set Operator

Delegators may add operators to unstake or redelegate on their behalf. To add an operator, run the following command:

* `--chain-id` int Chain ID to use for the transaction (default 1514)
* `--explorer` string URL of the blockchain explorer (default "[https://www.storyscan.io](https://www.storyscan.io)")
* `--operator` string Sets an operator to your delegator
* `--rpc` string RPC URL to connect to the network (default "[https://mainnet.storyrpc.io](https://mainnet.storyrpc.io)")

```bash theme={null}
./story validator set-operator \
  --operator ${OPERATOR_EVM_ADDRESS} \
  --rpc \
  --chain-id \
  --story-api ${STORY_API_URL}
```

Note that you will need at least 1 IP in the wallet submitting the transaction for the transaction to be valid.

### Example add operator command use

```bash theme={null}
./story validator set-operator \
  --operator 0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab \
  --rpc \
  --chain-id \
  --story-api http://localhost:1317
```

## Unset Operator

To remove an operator, run the following command:

```bash theme={null}
./story validator unset-operator \
  --operator ${OPERATOR_EVM_ADDRESS} \
  --rpc \
  --chain-id \
  --story-api ${STORY_API_URL}
```

### Example Remove Operator command use

```bash theme={null}
./story validator remove-operator \
  --operator 0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab \
  --rpc \
  --chain-id \
  --story-api http://localhost:1317
```

## Set Rewards Address

To change the address that your delegator receives staking and withdrawal rewards from, you can run the following:

```bash theme={null}
./story validator set-rewards-address \
  --rewards-address ${OPERATOR_EVM_ADDRESS} \
  --story-api ${STORY_API_URL}
```

Note that you will need at least 1 IP in the wallet submitting the transaction for the transaction to be valid.

### Example Set Withdrawal Address command use

```bash theme={null}
./story validator set-rewards-address \
  --rewards-address 0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab
  --story-api http://localhost:1317
```

## Set Withdrawal Address

To change the address that your delegator receives staking and withdrawal rewards from, you can run the following:

```bash theme={null}
./story validator set-withdrawal-address \
  --withdrawal-address ${OPERATOR_EVM_ADDRESS} \
  --story-api ${STORY_API_URL}
```

Note that you will need at least 1 IP in the wallet submitting the transaction for the transaction to be valid.

### Example Set Withdrawal Address command use

```bash theme={null}
./story validator set-withdrawal-address \
  --withdrawal-address 0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab
  --story-api http://localhost:1317
```

## Update Validator Commission

To change the commission rate for your validator, you can run the following:

```
./story validator update-validator-commission \
    --commission-rate ${NEW_COMMISSION}
```

### Example Update Validator Commission

```
./story validator update-validator-commission \
    --commission-rate 5000
```

## Enabling Story API

Prerequisites:

1. Ensure your full node is synced and caught up with latest blocks

Steps to enable:

1. Navigate to `${STORY_DATA_ROOT}/config/story.toml`
2. Set `enable = true` under the `[api]` section
3. Restart the node

Then you could use `http://localhost:1317` as the `-story-api` value

## Migrating a validator to another machine

<Warning>
  Before migrating your validator node to a new machine, make sure the current
  node is fully shut down. Attempting to restore an active validator could
  result in "double signing," a critical error that may lead to the slashing of
  your delegated shares.
</Warning>

1. Begin by configuring a new environment for your validator. Ensure that the new full node is fully synced to the latest block on the network.
2. To avoid accidental double-signing, it’s essential to fully shut down the original validator node before activating the new instance. We recommend deleting the Story service file to prevent it from automatically restarting after a system reboot. Additionally, back up both `priv_validator_key.json` and `priv_validator_state.json` and remove it from the current server running the active validator. Skipping these steps could result in missed blocks or other penalties.

```bash theme={null}
# Step 1: Stop the original validator node
sudo systemctl stop <your_service_file_name>.service

# Step 2: Disable the Story service to prevent automatic restarts
sudo systemctl disable <your_service_file_name>.service

# Step 3: Delete the Story service file to prevent it from starting on reboot
sudo rm /etc/systemd/system/<your_service_file_name>.service

# Step 4: Back up the `priv_validator_key.json` file securely, e.g., using SFTP:
# Use an SFTP client or a secure method to download the file without displaying it in the terminal
# If needed for verification purposes only, you may view it with the following command:
cat ~/.story/story/config/priv_validator_key.json

# Step 5: Remove the `priv_validator_key.json` file from the current server
rm ~/.story/story/config/priv_validator_key.json
```

3. Locate `priv_validator_key.json` and `priv_validator_state.json` in the `~/.story/story/config/` directory on your new machine. Replace this file with the backup copy from your old validator.

<Warning>
  Before proceeding, shut down the old validator on the original server and do
  not restart it!
</Warning>

4. After transferring the private key file, restart the validator node on your new setup. This will reintegrate your validator with the network, enabling it to resume its validation role.

## Private Key Encryption for Validators

This feature allows operators to securely generate, store, and manage private keys in encrypted form through CLI commands—including encrypting keys during setup, migrating unencrypted keys, and safely accessing them for validator operations.

### Overview of Private Key Encryption

Private key encryption is a critical security measure that encrypts sensitive cryptographic keys with a user-defined password. In the context of validator operations, this means that even if a private key file is exposed or accessed by unauthorized parties, it remains unusable without the correct password. Story CLI helps operators enforce stronger security controls while maintaining ease of use by integrating encryption directly into the validator workflow. This feature is designed to mitigate common attack vectors, such as accidental key leaks or unauthorized server access, by preventing private keys from being stored or used in plaintext.

### Initializing a Validator with Private Key Encryption

When setting up a new validator using the Story CLI, operators can generate and encrypt the validator’s private key in one step. By adding the `--encrypt-priv-key` flag during initialization, the CLI will prompt the operator to create a password, which is used to encrypt the generated private key. This encrypted key is then securely stored at `story/config/priv_validator_key.enc`.

Through this enhancement, private keys are never written to disk in plaintext during initialization, significantly reducing the risk of accidental exposure. Once encrypted, the key remains protected, and password decryption is required before any validator-related actions can be performed.

**Example usage:**

```bash theme={null}
./story init --encrypt-priv-key --network local
```

In this example, the validator is initialized on the local network, automatically triggering the private key encryption process. During this step, the operator is prompted to input and confirm a password. The resulting encrypted key file becomes the foundation for all validator operations.

### Using the Encrypted Private Key

Once a private key is encrypted, decryption is required for any key-dependent validator operation. The Story CLI will automatically detect the encrypted key file and prompt for a password when running a validator node. For validator-related CLI commands, however, the path of the encrypted key file should be specified. If no key file path is provided, the CLI will fall back to the private key in the .env file.

The password prompt appears interactively via the CLI, blocking execution if the wrong password is provided. As a result, only authorized operators with the correct password can unlock and use the private key, adding protection against unauthorized access.

This workflow integrates with typical validator commands, preserving the developer experience while strengthening security. For environments that require automation, additional tooling (e.g., password managers or secure key vaults) can be used to manage passwords securely. Still, caution is advised to avoid undermining the purpose of encryption.

**Example:**

```bash theme={null}
./story validator start
# CLI will prompt: "Enter password to decrypt private key:"
```

This behavior applies consistently across all validator commands requiring private key access.

### Encrypting an Existing Private Key

For operators already running validators with unencrypted private keys, Story CLI now provides a simple migration path to adopt encrypted key storage. Using the encrypt command, you can securely encrypt the existing private key (typically defined in the .env file).

Once the command is executed, the CLI will prompt you to set a password. The private key will be encrypted and stored at a specified path using the --enc-key-file flag. The encrypted key becomes the default for validator operations, allowing the original key in the .env file to be manually removed for better security. This does not apply to validator-related CLI commands, which still require explicit key input.

**Example usage:**

```bash theme={null}
./story encrypt --encrypt-priv-key
```

This enables existing validators to benefit from the enhanced security of encrypted key management without requiring re-initialization. It’s recommended that the password and encrypted key file be securely backed up before deleting the plaintext key from the `.env` file.

### Viewing the Encrypted Private Key

Story CLI introduces a show command to give operators transparency and control over their encrypted keys. This command decrypts the encrypted private key file—specified via the `--enc-key-file` flag—and displays essential information such as the public key and validator address. It mirrors the functionality of the traditional export command but supports encrypted keys.

Operators will be prompted for the encryption password before revealing key details, protecting sensitive information from unauthorized access. For advanced users, the optional `--show-private` flag will reveal the hex-encoded private key. However, this should be used cautiously as it defeats the purpose of encryption and exposes the key to potential compromise.

**Example usage:**

```bash theme={null}
# View public information (e.g., public key, address)
./story key show-encrypted --encrypt-key-file <encrypted-key-file-path>
# View public information and the raw private key (use with caution)
./story key show-encrypted --show-private --enc-key-file <encrypted-key-file-path>
```

It is recommended that `--show-private` be used only in secure environments and for exceptional operational needs, such as recovery or migration to other systems.
