Skip to content

Commit

Permalink
feat: reading upgrade-info from file (#67)
Browse files Browse the repository at this point in the history
* feat: reading upgrade-info from file

* chore: fixed broken tests, add new ones

* chore: add more tests
  • Loading branch information
freak12techno authored Jan 4, 2025
1 parent 2bfd7c1 commit 498f239
Show file tree
Hide file tree
Showing 16 changed files with 668 additions and 107 deletions.
1 change: 1 addition & 0 deletions assets/cosmovisor-upgrade-info-not-found.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No upgrade info found at /home/validator/.stride/data/upgrade-info.json
1 change: 1 addition & 0 deletions assets/cosmovisor-upgrade-info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name":"v999","time":"0001-01-01T00:00:00Z","height":999}
57 changes: 57 additions & 0 deletions pkg/clients/cosmovisor/cosmovisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"os"
"strings"

upgradeTypes "cosmossdk.io/x/upgrade/types"

"go.opentelemetry.io/otel/trace"

"github.com/rs/zerolog"
Expand Down Expand Up @@ -195,3 +197,58 @@ func (c *Cosmovisor) GetUpgrades(ctx context.Context) (*types.UpgradesPresent, q

return &upgrades, cosmovisorGetUpgradesQueryInfo, nil
}

func (c *Cosmovisor) GetUpgradeInfo(ctx context.Context) (*upgradeTypes.Plan, query_info.QueryInfo, error) {
_, span := c.Tracer.Start(
ctx,
"Fetching cosmovisor upgrade info",
)
defer span.End()

queryInfo := query_info.QueryInfo{
Module: constants.ModuleCosmovisor,
Action: constants.ActionCosmovisorGetCosmovisorUpgradeInfo,
Success: false,
}

env := append(
os.Environ(),
"DAEMON_NAME="+c.Config.ChainBinaryName,
"DAEMON_HOME="+c.Config.ChainFolder,
)

out, err := c.CommandExecutor.RunWithEnv(
c.Config.CosmovisorPath,
[]string{"show-upgrade-info"},
env,
)
if err != nil {
c.Logger.Error().
Err(err).
Str("output", utils.DecolorifyString(string(out))).
Msg("Could not get Cosmovisor upgrade info")
span.RecordError(err)
return nil, queryInfo, err
}

if strings.Contains(string(out), "No upgrade info found") {
c.Logger.Trace().Msg("Cosmovisor reports that there is no upgrade info present")
queryInfo.Success = true
return nil, queryInfo, nil
}

jsonOutput := getJsonString(string(out))

var upgradePlan *upgradeTypes.Plan
if unmarshalErr := json.Unmarshal([]byte(jsonOutput), &upgradePlan); unmarshalErr != nil {
c.Logger.Error().
Err(unmarshalErr).
Str("output", jsonOutput).
Msg("Could not unmarshall upgrade info")
span.RecordError(unmarshalErr)
return upgradePlan, queryInfo, unmarshalErr
}

queryInfo.Success = true
return upgradePlan, queryInfo, nil
}
87 changes: 87 additions & 0 deletions pkg/clients/cosmovisor/cosmovisor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,90 @@ func TestCosmovisorGetUpgradesGetFileOk(t *testing.T) {
assert.True(t, queryInfo.Success)
assert.True(t, upgrades.HasUpgrade("v15"))
}

func TestCosmovisorGetUpgradeInfoFail(t *testing.T) {
t.Parallel()

config := configPkg.CosmovisorConfig{
Enabled: null.BoolFrom(true),
ChainBinaryName: "gaiad",
ChainFolder: "/home/validator/.gaia",
CosmovisorPath: "/home/validator/go/bin/cosmovisor",
}
logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
client := NewCosmovisor(config, *logger, tracer)
client.CommandExecutor = &exec.TestCommandExecutor{Fail: true}

upgradeInfo, queryInfo, err := client.GetUpgradeInfo(context.Background())
require.Error(t, err)
assert.False(t, queryInfo.Success)
assert.Empty(t, upgradeInfo)
}

func TestCosmovisorGetUpgradeInfoNotPresent(t *testing.T) {
t.Parallel()

config := configPkg.CosmovisorConfig{
Enabled: null.BoolFrom(true),
ChainBinaryName: "gaiad",
ChainFolder: "/home/validator/.gaia",
CosmovisorPath: "/home/validator/go/bin/cosmovisor",
}
logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
client := NewCosmovisor(config, *logger, tracer)

content := assets.GetBytesOrPanic("cosmovisor-upgrade-info-not-found.txt")
client.CommandExecutor = &exec.TestCommandExecutor{Expected: content}

upgradeInfo, queryInfo, err := client.GetUpgradeInfo(context.Background())
require.NoError(t, err)
assert.True(t, queryInfo.Success)
assert.Empty(t, upgradeInfo)
}

func TestCosmovisorGetUpgradeInfoInvalid(t *testing.T) {
t.Parallel()

config := configPkg.CosmovisorConfig{
Enabled: null.BoolFrom(true),
ChainBinaryName: "gaiad",
ChainFolder: "/home/validator/.gaia",
CosmovisorPath: "/home/validator/go/bin/cosmovisor",
}
logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
client := NewCosmovisor(config, *logger, tracer)

content := assets.GetBytesOrPanic("cosmovisor-version-ok.txt")
client.CommandExecutor = &exec.TestCommandExecutor{Expected: content}

upgradeInfo, queryInfo, err := client.GetUpgradeInfo(context.Background())
require.Error(t, err)
assert.False(t, queryInfo.Success)
assert.Empty(t, upgradeInfo)
}

func TestCosmovisorGetUpgradeInfoOk(t *testing.T) {
t.Parallel()

config := configPkg.CosmovisorConfig{
Enabled: null.BoolFrom(true),
ChainBinaryName: "gaiad",
ChainFolder: "/home/validator/.gaia",
CosmovisorPath: "/home/validator/go/bin/cosmovisor",
}
logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
client := NewCosmovisor(config, *logger, tracer)

content := assets.GetBytesOrPanic("cosmovisor-upgrade-info.txt")
client.CommandExecutor = &exec.TestCommandExecutor{Expected: content}

upgradeInfo, queryInfo, err := client.GetUpgradeInfo(context.Background())
require.NoError(t, err)
assert.True(t, queryInfo.Success)
assert.NotEmpty(t, upgradeInfo)
assert.Equal(t, int64(999), upgradeInfo.Height)
}
47 changes: 26 additions & 21 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,32 @@ const (
ModuleGit Module = "git"
ModuleGrpc Module = "grpc"

ActionCosmovisorGetVersion Action = "get_version"
ActionCosmovisorGetCosmovisorVersion Action = "get_cosmovisor_version"
ActionCosmovisorGetUpgrades Action = "get_upgrades"
ActionGitGetLatestRelease Action = "get_latest_release"
ActionTendermintGetNodeStatus Action = "get_node_status"
ActionTendermintGetUpgradePlan Action = "get_upgrade_plan"
ActionTendermintGetBlockTime Action = "get_block_time"
ActionGrpcGetNodeConfig Action = "get_node_config"
ActionGrpcGetNodeInfo Action = "get_node_info"

FetcherNameNodeStatus FetcherName = "node_status"
FetcherNameCosmovisorVersion FetcherName = "cosmovisor_version"
FetcherNameNodeConfig FetcherName = "node_config"
FetcherNameNodeInfo FetcherName = "node_info"
FetcherNameUptime FetcherName = "uptime"
FetcherNameAppVersion FetcherName = "app_version"
FetcherNameRemoteVersion FetcherName = "remote_version"
FetcherNameLocalVersion FetcherName = "local_version"
FetcherNameUpgrades FetcherName = "upgrades"
FetcherNameBlockTime FetcherName = "block_time"
FetcherNameCosmovisorUpgrades FetcherName = "cosmovisor_upgrades"
ActionCosmovisorGetVersion Action = "get_version"
ActionCosmovisorGetCosmovisorVersion Action = "get_cosmovisor_version"
ActionCosmovisorGetCosmovisorUpgradeInfo Action = "get_cosmovisor_upgrade_info"
ActionCosmovisorGetUpgrades Action = "get_upgrades"
ActionGitGetLatestRelease Action = "get_latest_release"
ActionTendermintGetNodeStatus Action = "get_node_status"
ActionTendermintGetUpgradePlan Action = "get_upgrade_plan"
ActionTendermintGetBlockTime Action = "get_block_time"
ActionGrpcGetNodeConfig Action = "get_node_config"
ActionGrpcGetNodeInfo Action = "get_node_info"

FetcherNameNodeStatus FetcherName = "node_status"
FetcherNameCosmovisorVersion FetcherName = "cosmovisor_version"
FetcherNameCosmovisorUpgradeInfo FetcherName = "cosmovisor_upgrade_info"
FetcherNameNodeConfig FetcherName = "node_config"
FetcherNameNodeInfo FetcherName = "node_info"
FetcherNameUptime FetcherName = "uptime"
FetcherNameAppVersion FetcherName = "app_version"
FetcherNameRemoteVersion FetcherName = "remote_version"
FetcherNameLocalVersion FetcherName = "local_version"
FetcherNameUpgrades FetcherName = "upgrades"
FetcherNameBlockTime FetcherName = "block_time"
FetcherNameCosmovisorUpgrades FetcherName = "cosmovisor_upgrades"

UpgradeSourceGovernance string = "governance"
UpgradeSourceUpgradeInfo string = "upgrade-info"
)

var (
Expand Down
16 changes: 5 additions & 11 deletions pkg/fetchers/block_time_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,19 @@ func (n *BlockTimeFetcher) Name() constants.FetcherName {
func (n *BlockTimeFetcher) Dependencies() []constants.FetcherName {
return []constants.FetcherName{
constants.FetcherNameUpgrades,
constants.FetcherNameCosmovisorUpgradeInfo,
}
}

func (n *BlockTimeFetcher) Get(ctx context.Context, data ...interface{}) (interface{}, []query_info.QueryInfo) {
if len(data) < 1 {
if len(data) < 2 {
panic("data is empty")
}

if data[0] == nil {
n.Logger.Trace().Msg("Upgrade plan is empty, not fetching block time.")
return nil, []query_info.QueryInfo{}
}
_, governanceUpgradePlanConverted := Convert[*types.Plan](data[0])
_, upgradeInfoJSONConverted := Convert[*types.Plan](data[1])

// upgrade-info was not fetched
upgradePlan, ok := data[0].(*types.Plan)
if !ok {
panic("expected upgrade plan to be *types.Plan")
}
if upgradePlan == nil {
if !governanceUpgradePlanConverted && !upgradeInfoJSONConverted {
n.Logger.Trace().Msg("Upgrade plan is empty, not fetching block time.")
return nil, []query_info.QueryInfo{}
}
Expand Down
15 changes: 9 additions & 6 deletions pkg/fetchers/block_time_fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ func TestBlockTimeFetcherBase(t *testing.T) {
client := tendermint.NewRPC(config, *logger, tracer)
fetcher := NewBlockTimeFetcher(*logger, client, tracer)
assert.True(t, fetcher.Enabled())
assert.Equal(t, []constants.FetcherName{constants.FetcherNameUpgrades}, fetcher.Dependencies())
assert.Equal(t, []constants.FetcherName{
constants.FetcherNameUpgrades,
constants.FetcherNameCosmovisorUpgradeInfo,
}, fetcher.Dependencies())
assert.Equal(t, constants.FetcherNameBlockTime, fetcher.Name())
}

Expand Down Expand Up @@ -60,7 +63,7 @@ func TestBlockTimeFetcherDataNil(t *testing.T) {

var upgradePlan *types.Plan

data, queryInfos := fetcher.Get(context.Background(), upgradePlan)
data, queryInfos := fetcher.Get(context.Background(), upgradePlan, upgradePlan)
assert.Empty(t, queryInfos)
assert.Nil(t, data)
}
Expand Down Expand Up @@ -99,7 +102,7 @@ func TestBlockTimeFetcherTendermintFailBlock(t *testing.T) {
client := tendermint.NewRPC(config, *logger, tracer)
fetcher := NewBlockTimeFetcher(*logger, client, tracer)

data, queryInfos := fetcher.Get(context.Background(), &types.Plan{})
data, queryInfos := fetcher.Get(context.Background(), &types.Plan{}, &types.Plan{})
assert.Len(t, queryInfos, 1)
assert.False(t, queryInfos[0].Success)
assert.Nil(t, data)
Expand Down Expand Up @@ -128,7 +131,7 @@ func TestBlockTimeFetcherTendermintFailOlderBlock(t *testing.T) {
client := tendermint.NewRPC(config, *logger, tracer)
fetcher := NewBlockTimeFetcher(*logger, client, tracer)

data, queryInfos := fetcher.Get(context.Background(), &types.Plan{})
data, queryInfos := fetcher.Get(context.Background(), &types.Plan{}, &types.Plan{})
assert.Len(t, queryInfos, 1)
assert.False(t, queryInfos[0].Success)
assert.Nil(t, data)
Expand All @@ -147,7 +150,7 @@ func TestBlockTimeFetcherNoUpgrade(t *testing.T) {

var upgradePlan *types.Plan

data, queryInfos := fetcher.Get(context.Background(), upgradePlan)
data, queryInfos := fetcher.Get(context.Background(), upgradePlan, upgradePlan)
assert.Empty(t, queryInfos)
assert.Nil(t, data)
}
Expand Down Expand Up @@ -175,7 +178,7 @@ func TestBlockTimeFetcherTendermintOk(t *testing.T) {
client := tendermint.NewRPC(config, *logger, tracer)
fetcher := NewBlockTimeFetcher(*logger, client, tracer)

data, queryInfos := fetcher.Get(context.Background(), &types.Plan{})
data, queryInfos := fetcher.Get(context.Background(), &types.Plan{}, &types.Plan{})
assert.Len(t, queryInfos, 1)
assert.True(t, queryInfos[0].Success)
assert.NotNil(t, data)
Expand Down
12 changes: 9 additions & 3 deletions pkg/fetchers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,22 @@ func StateGet[T any](state State, fetcherName constants.FetcherName) (T, bool) {
return zero, false
}

if dataRaw == nil {
return Convert[T](dataRaw)
}

func Convert[T any](input interface{}) (T, bool) {
var zero T

if input == nil {
return zero, false
}

data, converted := dataRaw.(T)
data, converted := input.(T)
if !converted {
panic(fmt.Sprintf(
"Error converting data: expected %s, got %s",
reflect.TypeOf(zero).String(),
reflect.TypeOf(dataRaw).String(),
reflect.TypeOf(input).String(),
))
}

Expand Down
Loading

0 comments on commit 498f239

Please sign in to comment.