simd. Substitute your chain’s binary. Examples use ~/.node for the existing node’s home and ~/.rotation-node for the new one; those paths, the key name val, and host addresses are the only values to adjust.
Prerequisites
- The chain runs Cosmos SDK 0.55 and CometBFT 0.40 or later, and allows your target key type. See Enable ML-DSA keys.
- jq and curl for the verification steps.
- A running validator you operate, and a second machine (or spare ports on the same host) for the new node, with the chain’s binary installed on it.
- No rotation in the current unbonding period. Only one rotation is allowed per unbonding period.
- The operator account holds enough funds for two separate charges: the rotation fee, which is burned, and the ordinary gas fee for the transaction itself. Check the rotation fee:
key_rotation_fee field shows the fee amount.
1. Start a second node with the new key
Initialize a fresh node home. The init command generates a new consensus key inpriv_validator_key.json:
--p2p.laddr, --rpc.laddr, and --grpc.address, and set a distinct pprof_laddr in its config.toml. Otherwise the new node logs a harmless address already in use error for the default pprof port and keeps running. Until the rotation applies, the node follows the chain as a non-signing full node.
On a chain with history, a fresh node takes days to sync from genesis. Use state sync or a snapshot to reach the chain head quickly. See State sync.
Never copy the old
priv_validator_key.json to the new node. Two nodes signing with the same consensus key is a double sign, which tombstones the validator. The new node must have its own freshly generated key.2. Confirm both nodes are healthy
Before you submit, the old node must still be signing and the new node must be caught up to the chain head. If the new node is still syncing when the rotation applies, the validator will miss blocks until it catches up. Check sync status:--rpc.laddr port you gave it, not 26657). Both must report false.
3. Submit the rotation
The rotation message carries the new node’s public key, read directly from that node’s home:--fees (or --gas-prices) to meet the chain’s minimum gas price; without it the node rejects the transaction with insufficient fees. This gas fee is separate from the burned rotation fee. The command reads the operator key and chain ID from your client config; add --chain-id, --keyring-backend, and --home if that config does not already supply them.
4. Verify the new key is signing
The rotation applies two heights after the message executes, so the new key can appear within seconds on a fast chain. A successful broadcast confirms only that the chain accepted the transaction; confirm the validator set actually carries the new key:value matches the key shown by simd comet show-validator --home ~/.rotation-node, and the old key is gone. If the set still shows the old key, wait a few blocks and check again. Watch the new node’s logs to see it signing votes.
5. Retire the old node
Stop the old node and decommission it. Its consensus key holds no power, but it remains slashable for past behavior until the unbonding period ends. Store its key material securely rather than leaving it on shared infrastructure.What can go wrong
- The transaction is rejected with a rotation limit error: a rotation already happened this unbonding period. Wait out the window.
- The transaction is rejected for an unsupported key type: the target type is not in the chain’s consensus params. See Enable ML-DSA keys.
- The fee cannot be paid: fund the operator account with at least
key_rotation_fee. - The validator misses blocks after the rotation applies: the new node was not caught up. It resumes signing once synced.
Next steps
- Understand the mechanics behind each step. See Key rotation.
- Check what key types the chain allows. See Enable ML-DSA keys.
- Look up the message and parameters. See the x/staking module reference.