Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Cudos config verification command #393

Merged
merged 6 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading