How Starship Automates Blockchain Upgrades with Cosmovisor
Starship automates Cosmos SDK blockchain upgrades by embedding Cosmovisor into validator containers, pre-building genesis and upgrade binaries, and enabling zero-downtime binary switches at scheduled block heights without manual pod restarts.
Starship, developed by hyperweb-io/starship, eliminates manual intervention during blockchain upgrades by integrating Cosmovisor directly into its Kubernetes-native infrastructure. This automation allows Cosmos SDK chains to transition between protocol versions seamlessly through governance proposals, handling binary compilation, distribution, and execution within the container orchestration layer.
Understanding the Starship Upgrade Architecture
Starship’s upgrade mechanism operates through three tightly coupled layers: configuration management, binary preparation, and runtime orchestration. Each layer maps to specific source files in the repository that handle distinct responsibilities in the upgrade lifecycle.
Configuration Layer: The Upgrade Struct
User-defined upgrade parameters are unmarshalled into the Upgrade struct defined in starship/cmd/starship/model.go. This struct captures the genesis version and future upgrade paths specified in Helm values.
The configuration requires upgrade.enabled: true alongside specific version tags:
upgrade:
enabled: true
genesis: v7.0.0
upgrades:
- name: v8.0.0
version: v8.0.0
- name: v9.0.0
version: v9.0.0
When the generator processes this configuration, it triggers the CosmosValidatorStatefulSetGenerator to inject additional init containers into the validator StatefulSet manifest.
Build and Installation Process
The CosmosValidatorStatefulSetGenerator (located in packages/generator/src/builders/chains/cosmos/validator.ts) programmatically adds an init-build-images container when chain.upgrade.enabled evaluates to true. This container handles two critical tasks:
-
Cosmovisor Installation: Executes
go install github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor@v1.0.0to place the binary in the container’s$GOBIN. -
Binary Compilation: Iterates through the upgrade list, invoking
build-chain.shwithUPGRADE_NAMEandCODE_TAGenvironment variables for each version.
The build-chain.sh script (found in charts/devnet/scripts/default/build-chain.sh) checks out the specified source code tags, compiles binaries using make install, and organizes them into Cosmovisor’s expected directory hierarchy:
if [[ $UPGRADE_NAME == "genesis" ]]; then
mkdir -p $UPGRADE_DIR/genesis/bin
cp $GOBIN/$CHAIN_BIN $UPGRADE_DIR/genesis/bin
else
mkdir -p $UPGRADE_DIR/upgrades/$UPGRADE_NAME/bin
cp $GOBIN/$CHAIN_BIN $UPGRADE_DIR/upgrades/$UPGRADE_NAME/bin
fi
Runtime Execution and Binary Switching
The validator pod defined in charts/devnet/templates/chains/cosmos/validator.yaml uses specialized init containers to prepare the runtime environment. The init-validator and init-config containers copy the genesis binary from $CHAIN_DIR/cosmovisor/genesis/bin/$CHAIN_BIN to /usr/bin, establishing Cosmovisor as the entry point.
When a governance proposal triggers an on-chain upgrade at a specific block height, Cosmovisor detects the matching directory under $UPGRADE_DIR/upgrades/<upgrade-name>/bin, swaps the active binary, and restarts the process automatically. This occurs without pod recreation or manual intervention, as demonstrated in the upgrade test suite.
Step-by-Step Implementation Guide
Implementing automated upgrades requires configuring the Helm values, ensuring proper binary placement, and submitting governance proposals.
1. Enable Upgrades in Helm Configuration
Define the upgrade path in your values.yaml by specifying the genesis version and all subsequent upgrades:
chains:
- id: persistencecore
name: persistencecore
image: ghcr.io/cosmology-tech/persistencecore:latest
upgrade:
enabled: true
genesis: v7.0.0
upgrades:
- name: v8.0.0
version: v8.0.0
- name: v9.0.0
version: v9.0.0
2. Verify Init Container Generation
Starship generates the init-build-images container automatically. The generated manifest includes commands to build each binary version:
initContainers:
- name: init-build-images
image: ghcr.io/cosmology-tech/starship/builder:latest
command:
- bash
- -c
- |
go install github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor@v1.0.0
UPGRADE_NAME=genesis CODE_TAG=v7.0.0 bash -e /scripts/build-chain.sh
UPGRADE_NAME=v8.0.0 CODE_TAG=v8.0.0 bash -e /scripts/build-chain.sh
3. Submit Governance Proposal
Use the chain’s governance module to schedule the upgrade. The test in examples/upgrade-test/upgrade_test.go demonstrates the complete flow:
plan := upgradetypes.Plan{
Name: "v8.0.0",
Height: upgradeHeight,
}
msg := &gov.MsgSubmitProposal{}
msg.SetContent(upgradetypes.NewSoftwareUpgradeProposal(
"Software upgrade",
"software upgrade",
plan,
))
res, err := chain.SendMsg(ctx, msg, "Software upgrade proposal")
4. Monitor Upgrade Execution
Wait for the chain to reach the specified upgrade height, then verify the upgrade applied successfully:
s.WaitForHeight(chain, upgradeHeight+1)
upgradeClient := upgradetypes.NewQueryClient(chain.Client)
planRes, _ := upgradeClient.AppliedPlan(ctx, &upgradetypes.QueryAppliedPlanRequest{Name: "v8.0.0"})
At the target height, Cosmovisor automatically switches to the new binary located in $UPGRADE_DIR/upgrades/v8.0.0/bin/.
Code Examples for Production Use
Validator Init Container Configuration
The validator template handles binary placement through conditional copy operations:
- name: init-validator
image: {{ $chain.image }}
command:
- bash
- -c
- |
if [[ -f $CHAIN_DIR/cosmovisor/genesis/bin/$CHAIN_BIN ]]; then
cp $CHAIN_DIR/cosmovisor/genesis/bin/$CHAIN_BIN /usr/bin
fi
# Additional validator initialization...
Complete Upgrade Test Workflow
This Go test validates the end-to-end upgrade process, including proposal submission and state verification:
package upgradetest
import (
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
gov "github.com/cosmos/cosmos-sdk/x/gov/types"
)
func TestSoftwareUpgrade(t *testing.T) {
plan := upgradetypes.Plan{
Name: "v8.0.0",
Height: 100,
}
msg := &gov.MsgSubmitProposal{}
msg.SetContent(upgradetypes.NewSoftwareUpgradeProposal(
"Software upgrade",
"Upgrade to v8.0.0",
plan,
))
res, err := chain.SendMsg(ctx, msg)
require.NoError(t, err)
// Wait for upgrade height
s.WaitForHeight(chain, 101)
// Verify upgrade applied
client := upgradetypes.NewQueryClient(chain.Client)
applied, _ := client.AppliedPlan(ctx, &upgradetypes.QueryAppliedPlanRequest{Name: "v8.0.0"})
require.Equal(t, int64(100), applied.Height)
}
Summary
- Configuration-driven upgrades: The
Upgradestruct instarship/cmd/starship/model.goparses Helm values to define genesis and future binary versions. - Automated binary preparation: The
CosmosValidatorStatefulSetGeneratorinjectsinit-build-imagescontainers that executebuild-chain.shto compile and organize binaries in Cosmovisor’s directory structure. - Zero-downtime execution: Cosmovisor manages binary switching at the scheduled block height without requiring pod restarts or manual intervention, as implemented in
charts/devnet/templates/chains/cosmos/validator.yaml. - Governance integration: Upgrade proposals submitted through the SDK’s
upgrademodule trigger automatic binary swaps when the specified height is reached.
Frequently Asked Questions
What version of Cosmovisor does Starship install?
Starship installs Cosmovisor v1.0.0 by default, as specified in the init-build-images container command (go install github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor@v1.0.0). You can modify this version in the generator code at packages/generator/src/builders/chains/cosmos/validator.ts if your chain requires a specific Cosmovisor release.
How does Starship handle binary storage for multiple upgrade versions?
Starship organizes binaries using Cosmovisor’s standard directory layout. The build-chain.sh script places the genesis binary in $UPGRADE_DIR/genesis/bin/ and subsequent upgrade binaries in $UPGRADE_DIR/upgrades/<name>/bin/. This structure allows Cosmovisor to locate and switch binaries automatically when upgrade heights are reached.
Can I perform upgrades without restarting the validator pods?
Yes. Starship’s architecture eliminates the need for manual pod restarts. Once the init-build-images container completes the initial binary setup, Cosmovisor manages the runtime process. When an upgrade proposal executes at the specified block height, Cosmovisor swaps the binary and restarts the process internally within the same pod, maintaining chain continuity.
Where is the Cosmovisor binary located in the runtime container?
The Cosmovisor binary resides in the Starship runner image defined in docker/starship/runner/Dockerfile. This image serves as the base for validator containers, ensuring Cosmovisor is available at runtime to manage the chain binary lifecycle. The genesis binary is copied to /usr/bin during initialization to serve as Cosmovisor’s launch target.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →