Skip to content

Commit

Permalink
feat: Cudos config verification command (#393)
Browse files Browse the repository at this point in the history
  • Loading branch information
MissingNO57 authored Oct 10, 2024
1 parent d05a6bd commit 0be6e3d
Show file tree
Hide file tree
Showing 7 changed files with 360 additions and 180 deletions.
8 changes: 4 additions & 4 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ func getNetworkInfo(app *App, ctx sdk.Context, manifest *UpgradeManifest, expect
if app.cudosMigrationConfigPath != "" {
app.Logger().Info("cudos merge: loading network config", "file", app.cudosMigrationConfigPath, "expected sha256", app.cudosMigrationConfigSha256)

networkInfo, err = LoadNetworkConfigFromFile(app.cudosMigrationConfigPath, &app.cudosMigrationConfigSha256)
networkInfo, err = LoadAndVerifyNetworkConfigFromFile(app.cudosMigrationConfigPath, &app.cudosMigrationConfigSha256)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -776,7 +776,7 @@ func LoadAndParseMergeSourceInputFiles(app *App, ctx sdk.Context, manifest *Upgr

cudosConfig := NewCudosMergeConfig(networkInfo.CudosMerge)

genesisData, err := parseGenesisData(app, ctx, *cudosJsonData, cudosGenDoc, cudosConfig, manifest)
genesisData, err := ParseGenesisData(*cudosJsonData, cudosGenDoc, cudosConfig, manifest)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse genesis data: %w", err)
}
Expand All @@ -798,8 +798,8 @@ func (app *App) RegisterUpgradeHandlers(cfg module.Configurator) {
return nil, fmt.Errorf("cudos merge: %w", err)
}

manifest.DestinationChainBlockHeight = cudosGenesisData.blockHeight
manifest.DestinationChainID = cudosGenesisData.chainId
manifest.DestinationChainBlockHeight = cudosGenesisData.BlockHeight
manifest.DestinationChainID = cudosGenesisData.ChainId

manifest.SourceChainBlockHeight = ctx.BlockHeight()
manifest.MergeSourceChainID = ctx.ChainID()
Expand Down
222 changes: 112 additions & 110 deletions app/upgrade_cudos.go

Large diffs are not rendered by default.

110 changes: 55 additions & 55 deletions app/upgrade_cudos_distribution.go

Large diffs are not rendered by default.

32 changes: 21 additions & 11 deletions app/upgrade_v_11_4_network_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,24 +276,18 @@ type NetworkConfig struct {
CudosMerge *CudosMergeConfigJSON `json:"cudos_merge,omitempty"`
}

func LoadNetworkConfigFromFile(configFilePath string, expectedSha256Hex *string) (*NetworkConfig, error) {
func LoadNetworkConfigFromFile(configFilePath string) (*NetworkConfig, *[]byte, error) {
// Open the JSON file
file, err := os.Open(configFilePath)
if err != nil {
return nil, fmt.Errorf("failed to open config file: %v", err)
return nil, nil, fmt.Errorf("failed to open config file: %v", err)
}
defer file.Close()

// Read the file contents
byteValue, err := ioutil.ReadAll(file)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %v", err)
}

if isVerified, actualHashHex, err := VerifySha256(byteValue, expectedSha256Hex); err != nil {
return nil, err
} else if !isVerified {
return nil, fmt.Errorf("failed to verify sha256: NetworkConfig file \"%s\" hash \"%s\" does not match expected hash \"%s\"", configFilePath, actualHashHex, *expectedSha256Hex)
return nil, nil, fmt.Errorf("failed to read config file: %v", err)
}

// Initialize an empty struct to hold the JSON data
Expand All @@ -302,10 +296,26 @@ func LoadNetworkConfigFromFile(configFilePath string, expectedSha256Hex *string)
// Unmarshal the JSON data into the struct
err = json.Unmarshal(byteValue, &config)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON: %v", err)
return nil, nil, fmt.Errorf("failed to unmarshal JSON: %v", err)
}

return &config, &byteValue, nil
}

func LoadAndVerifyNetworkConfigFromFile(configFilePath string, expectedSha256Hex *string) (*NetworkConfig, error) {
config, byteValue, err := LoadNetworkConfigFromFile(configFilePath)

if err != nil {
return nil, err
}

if isVerified, actualHashHex, err := VerifySha256(*byteValue, expectedSha256Hex); err != nil {
return nil, err
} else if !isVerified {
return nil, fmt.Errorf("failed to verify sha256: NetworkConfig file \"%s\" hash \"%s\" does not match expected hash \"%s\"", configFilePath, actualHashHex, *expectedSha256Hex)
}

return &config, nil
return config, nil
}

type CudosMergeConfigJSON struct {
Expand Down
22 changes: 22 additions & 0 deletions app/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/cosmos/cosmos-sdk/types/bech32"
"io"
"os"
)
Expand Down Expand Up @@ -32,6 +33,14 @@ func GenerateSHA256FromFile(filePath string) (string, error) {
return hex.EncodeToString(hashSum), nil
}

func GenerateSha256Hex(dataToVerify []byte) (actualHashHex string) {
actualHash32 := sha256.Sum256(dataToVerify)
actualHash := actualHash32[:]
actualHashHex = hex.EncodeToString(actualHash)

return actualHashHex
}

func VerifySha256(dataToVerify []byte, expectedSha256Hex *string) (isVerified bool, actualHashHex string, err error) {
if expectedSha256Hex == nil {
return true, "", nil
Expand Down Expand Up @@ -59,3 +68,16 @@ func VerifySha256(dataToVerify []byte, expectedSha256Hex *string) (isVerified bo
}
return isVerified, actualHashHex, nil
}

func VerifyAddressPrefix(addr string, expectedPrefix string) error {
prefix, _, err := bech32.DecodeAndConvert(addr)
if err != nil {
return err
}

if prefix != expectedPrefix {
return fmt.Errorf("invalid address prefix: expected %s, got %s", expectedPrefix, prefix)
}

return nil
}
145 changes: 145 additions & 0 deletions cmd/fetchd/cmd/cudos_merge.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package cmd

import (
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/client"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/fetchai/fetchd/app"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -40,3 +44,144 @@ func AddCudosFlags(startCmd *cobra.Command) {
}

}

func utilNetworkMergeCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "network-merge",
Short: "Network merge commands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

cmdVerify := &cobra.Command{
Use: "verify-config [config_json_file_path]",
Short: "Verifies the configuration JSON file",
Long: "This command verifies the structure and content of the configuration JSON file. It checks if all required fields are present and validates their values against predefined rules.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := client.GetClientContextFromCmd(cmd)

configFilePath := args[0]
GenesisFilePath := args[1]

// Read and verify the JSON file
var err error
if err = VerifyConfigFile(configFilePath, GenesisFilePath, ctx); err != nil {
return err
}

return ctx.PrintString("Configuration is valid.\n")
},
}

cmd.AddCommand(cmdVerify)
return cmd
}

// VerifyConfigFile validates the content of a JSON configuration file.
func VerifyConfigFile(configFilePath string, GenesisFilePath string, ctx client.Context) error {
manifest := app.NewUpgradeManifest()

destinationChainPrefix := "fetch"

networkInfo, configBytes, err := app.LoadNetworkConfigFromFile(configFilePath)
if err != nil {
return err
}
err = ctx.PrintString(fmt.Sprintf("Config hash: %s\n", app.GenerateSha256Hex(*configBytes)))
if err != nil {
return err
}

_, GenDoc, err := genutiltypes.GenesisStateFromGenFile(GenesisFilePath)
if err != nil {
return fmt.Errorf("failed to unmarshal genesis state: %w", err)
}

// unmarshal the app state
var cudosJsonData map[string]interface{}
if err = json.Unmarshal(GenDoc.AppState, &cudosJsonData); err != nil {
return fmt.Errorf("failed to unmarshal app state: %w", err)
}
cudosConfig := app.NewCudosMergeConfig(networkInfo.CudosMerge)

genesisData, err := app.ParseGenesisData(cudosJsonData, GenDoc, cudosConfig, manifest)
if err != nil {
return fmt.Errorf("failed to parse genesis data: %w", err)
}

if networkInfo.MergeSourceChainID != genesisData.ChainId {
return fmt.Errorf("source chain id %s is different from config chain id %s", networkInfo.MergeSourceChainID, genesisData.ChainId)
}

// We don't have access to home folder here so we can't check
if networkInfo.DestinationChainID == "" {
return fmt.Errorf("destination chain id is empty")
}

// Verify addresses
err = app.VerifyAddressPrefix(networkInfo.CudosMerge.IbcTargetAddr, genesisData.Prefix)
if err != nil {
return fmt.Errorf("ibc targer address error: %v", err)
}

err = app.VerifyAddressPrefix(networkInfo.CudosMerge.RemainingStakingBalanceAddr, genesisData.Prefix)
if err != nil {
return fmt.Errorf("remaining staking balance address error: %v", err)
}

err = app.VerifyAddressPrefix(networkInfo.CudosMerge.RemainingGravityBalanceAddr, genesisData.Prefix)
if err != nil {
return fmt.Errorf("remaining gravity balance address error: %v", err)
}

err = app.VerifyAddressPrefix(networkInfo.CudosMerge.RemainingDistributionBalanceAddr, genesisData.Prefix)
if err != nil {
return fmt.Errorf("remaining distribution balance address error: %v", err)
}

err = app.VerifyAddressPrefix(networkInfo.CudosMerge.ContractDestinationFallbackAddr, genesisData.Prefix)
if err != nil {
return fmt.Errorf("contract destination fallback address error: %v", err)
}

// Community pool address is optional
if networkInfo.CudosMerge.CommunityPoolBalanceDestAddr != "" {
err = app.VerifyAddressPrefix(networkInfo.CudosMerge.CommunityPoolBalanceDestAddr, genesisData.Prefix)
if err != nil {
return fmt.Errorf("community pool balance destination address error: %v", err)
}
}

err = app.VerifyAddressPrefix(networkInfo.CudosMerge.CommissionFetchAddr, destinationChainPrefix)
if err != nil {
return fmt.Errorf("comission address error: %v", err)
}

err = app.VerifyAddressPrefix(networkInfo.CudosMerge.ExtraSupplyFetchAddr, destinationChainPrefix)
if err != nil {
return fmt.Errorf("extra supply address error: %v", err)
}

err = app.VerifyAddressPrefix(networkInfo.CudosMerge.VestingCollisionDestAddr, genesisData.Prefix)
if err != nil {
return fmt.Errorf("vesting collision destination address error: %v", err)
}

// Verify extra supply
bondDenomSourceTotalSupply := genesisData.TotalSupply.AmountOf(genesisData.BondDenom)
if networkInfo.CudosMerge.TotalCudosSupply.LT(bondDenomSourceTotalSupply) {
return fmt.Errorf("total supply %s from config is smaller than total supply %s in genesis", networkInfo.CudosMerge.TotalCudosSupply.String(), bondDenomSourceTotalSupply.String())
}

if len(networkInfo.CudosMerge.BalanceConversionConstants) == 0 {
return fmt.Errorf("list of conversion constants is empty")
}

if len(networkInfo.CudosMerge.BackupValidators) == 0 {
return fmt.Errorf("list of backup validators is empty")
}

return nil
}
1 change: 1 addition & 0 deletions cmd/fetchd/cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func utilCommand() *cobra.Command {
cmd.AddCommand(
utilJsonCommand(),
utilAddressCommand(),
utilNetworkMergeCommand(),
)

return cmd
Expand Down

0 comments on commit 0be6e3d

Please sign in to comment.