From d5036d5aae0c26b0bb878316598fc2e60d7d8017 Mon Sep 17 00:00:00 2001 From: jonathansumner Date: Tue, 16 Apr 2024 19:30:04 +0100 Subject: [PATCH 1/4] feat: denom & denom metadata processing --- cmd/fetchd/cmd/genasiupgrade.go | 114 +++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/cmd/fetchd/cmd/genasiupgrade.go b/cmd/fetchd/cmd/genasiupgrade.go index c3d023c5..aa17f94a 100644 --- a/cmd/fetchd/cmd/genasiupgrade.go +++ b/cmd/fetchd/cmd/genasiupgrade.go @@ -1,8 +1,18 @@ package cmd import ( + "encoding/json" + "fmt" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/spf13/cobra" + "regexp" + "strings" ) const ( @@ -39,7 +49,39 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return nil + clientCtx := client.GetClientContextFromCmd(cmd) + cdc := clientCtx.Codec + + serverCtx := server.GetServerContextFromCmd(cmd) + config := serverCtx.Config + + config.SetRoot(clientCtx.HomeDir) + + genFile := config.GenesisFile() + + appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) + if err != nil { + return fmt.Errorf("failed to unmarshal genesis state: %w", err) + } + + // set denom metadata in bank module + err = ASIGenesisUpgradeReplaceDenomMetadata(cdc, &appState) + if err != nil { + return fmt.Errorf("failed to replace denom metadata: %w", err) + } + + appStateJSON, err := json.Marshal(appState) + if err != nil { + return fmt.Errorf("failed to marshal application genesis state: %w", err) + } + + appStateStr := string(appStateJSON) + + // replace denom across the genesis file + ASIGenesisUpgradeReplaceDenom(&appStateStr) + + genDoc.AppState = []byte(appStateStr) + return genutil.ExportGenesisFile(genDoc, genFile) }, } @@ -51,14 +93,80 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { return cmd } -func ASIGenesisUpgradeReplaceDenomMetadata() {} +func ASIGenesisUpgradeReplaceDenomMetadata(cdc codec.Codec, appState *map[string]json.RawMessage) error { + bankGenState := banktypes.GetGenesisStateFromAppState(cdc, *appState) + + OldBaseDenomUpper := strings.ToUpper(OldBaseDenom) + NewBaseDenomUpper := strings.ToUpper(NewBaseDenom) + + denomRegex := getRegex(OldDenom, NewDenom) + upperDenomRegex := getRegex(OldBaseDenomUpper, NewBaseDenomUpper) + exponentDenomRegex := getPartialRegexLeft(OldBaseDenom, NewBaseDenom) + + for _, metadata := range bankGenState.DenomMetadata { + replaceString(&metadata.Base, []*regexPair{denomRegex}) + if metadata.Name == OldBaseDenomUpper { + metadata.Description = NewDescription + metadata.Display = NewBaseDenomUpper + metadata.Name = NewBaseDenomUpper + metadata.Symbol = NewBaseDenomUpper + } + for _, unit := range metadata.DenomUnits { + replaceString(&unit.Denom, []*regexPair{upperDenomRegex}) + replaceString(&unit.Denom, []*regexPair{exponentDenomRegex}) + } + } + + bankGenStateBytes, err := cdc.MarshalJSON(bankGenState) + if err != nil { + return fmt.Errorf("failed to marshal auth genesis state: %w", err) + } + + (*appState)[banktypes.ModuleName] = bankGenStateBytes + return nil +} func ASIGenesisUpgradeReplaceChainID() {} -func ASIGenesisUpgradeReplaceDenom() {} +func ASIGenesisUpgradeReplaceDenom(jsonString *string) { + for _, target := range []string{"denom", "bond_denom", "mint_denom", "base_denom", "base"} { + re := regexp.MustCompile(fmt.Sprintf(`("%s"\s*:\s*)"%s"`, target, OldDenom)) + if re.MatchString(*jsonString) { + *jsonString = re.ReplaceAllString(*jsonString, fmt.Sprintf(`${1}"%s"`, NewDenom)) + } + } +} func ASIGenesisUpgradeReplaceAddresses() {} func ASIGenesisUpgradeWithdrawIBCChannelsBalances() {} func ASIGenesisUpgradeWithdrawReconciliationBalances() {} + +func getRegex(oldValue string, newValue string) *regexPair { + return ®exPair{ + pattern: fmt.Sprintf(`^%s$`, oldValue), + replacement: fmt.Sprintf(`%s`, newValue), + } +} + +func getPartialRegexLeft(oldValue string, newValue string) *regexPair { + return ®exPair{ + pattern: fmt.Sprintf(`(.*?)%s"`, oldValue), + replacement: fmt.Sprintf(`${1}%s"`, newValue), + } +} + +func replaceString(s *string, replacements []*regexPair) { + for _, pair := range replacements { + re := regexp.MustCompile(pair.pattern) + if re.MatchString(*s) { + *s = re.ReplaceAllString(*s, pair.replacement) + } + } +} + +type regexPair struct { + pattern string + replacement string +} From 11cc45bd0d3f35faba15d2b1c187a63e70c51f7c Mon Sep 17 00:00:00 2001 From: jonathansumner Date: Tue, 16 Apr 2024 19:43:16 +0100 Subject: [PATCH 2/4] fix: replace import --- cmd/fetchd/cmd/genasiupgrade.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd/fetchd/cmd/genasiupgrade.go b/cmd/fetchd/cmd/genasiupgrade.go index aabbe2d3..6c95275b 100644 --- a/cmd/fetchd/cmd/genasiupgrade.go +++ b/cmd/fetchd/cmd/genasiupgrade.go @@ -11,7 +11,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/spf13/cobra" + "github.com/tendermint/tendermint/types" "regexp" + "strings" ) const ( @@ -57,10 +59,10 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { config.SetRoot(clientCtx.HomeDir) genFile := config.GenesisFile() - - appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) - if err != nil { + appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) + + if err != nil { return fmt.Errorf("failed to unmarshal genesis state: %w", err) } @@ -81,10 +83,10 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { ASIGenesisUpgradeReplaceDenom(&appStateStr) genDoc.AppState = []byte(appStateStr) - + // replace chain-id ASIGenesisUpgradeReplaceChainID(genDoc) - + return genutil.ExportGenesisFile(genDoc, genFile) }, } From 52e653f9bb3b9286870dcdb883cec703601914f5 Mon Sep 17 00:00:00 2001 From: jonathansumner Date: Wed, 17 Apr 2024 15:11:33 +0100 Subject: [PATCH 3/4] refactor: cleanup --- cmd/fetchd/cmd/genasiupgrade.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cmd/fetchd/cmd/genasiupgrade.go b/cmd/fetchd/cmd/genasiupgrade.go index 6c95275b..dd3e2f3a 100644 --- a/cmd/fetchd/cmd/genasiupgrade.go +++ b/cmd/fetchd/cmd/genasiupgrade.go @@ -61,11 +61,13 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { genFile := config.GenesisFile() appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) - if err != nil { return fmt.Errorf("failed to unmarshal genesis state: %w", err) } + // replace chain-id + ASIGenesisUpgradeReplaceChainID(genDoc) + // set denom metadata in bank module err = ASIGenesisUpgradeReplaceDenomMetadata(cdc, &appState) if err != nil { @@ -82,11 +84,8 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { // replace denom across the genesis file ASIGenesisUpgradeReplaceDenom(&appStateStr) + // save the updated genesis file genDoc.AppState = []byte(appStateStr) - - // replace chain-id - ASIGenesisUpgradeReplaceChainID(genDoc) - return genutil.ExportGenesisFile(genDoc, genFile) }, } From ada96486d5bfccd3c012b69a6afaa06e33ad4eee Mon Sep 17 00:00:00 2001 From: jonathansumner Date: Thu, 18 Apr 2024 13:37:32 +0100 Subject: [PATCH 4/4] feat: use recursive crawlJson function to avoid regex --- cmd/fetchd/cmd/genasiupgrade.go | 124 +++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 42 deletions(-) diff --git a/cmd/fetchd/cmd/genasiupgrade.go b/cmd/fetchd/cmd/genasiupgrade.go index dd3e2f3a..cd512514 100644 --- a/cmd/fetchd/cmd/genasiupgrade.go +++ b/cmd/fetchd/cmd/genasiupgrade.go @@ -12,7 +12,6 @@ import ( genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/spf13/cobra" "github.com/tendermint/tendermint/types" - "regexp" "strings" ) @@ -104,21 +103,48 @@ func ASIGenesisUpgradeReplaceDenomMetadata(cdc codec.Codec, appState *map[string OldBaseDenomUpper := strings.ToUpper(OldBaseDenom) NewBaseDenomUpper := strings.ToUpper(NewBaseDenom) - denomRegex := getRegex(OldDenom, NewDenom) - upperDenomRegex := getRegex(OldBaseDenomUpper, NewBaseDenomUpper) - exponentDenomRegex := getPartialRegexLeft(OldBaseDenom, NewBaseDenom) + newMetadata := banktypes.Metadata{ + Base: NewDenom, + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: NewBaseDenomUpper, + Exponent: 18, + }, + { + Denom: fmt.Sprintf("m%s", NewBaseDenom), + Exponent: 15, + }, + { + Denom: fmt.Sprintf("u%s", NewBaseDenom), + Exponent: 12, + }, + { + Denom: fmt.Sprintf("n%s", NewBaseDenom), + Exponent: 9, + }, + { + Denom: fmt.Sprintf("p%s", NewBaseDenom), + Exponent: 6, + }, + { + Denom: fmt.Sprintf("f%s", NewBaseDenom), + Exponent: 3, + }, + { + Denom: fmt.Sprintf("a%s", NewBaseDenom), + Exponent: 0, + }, + }, + Description: NewDescription, + Display: NewBaseDenomUpper, + Name: NewBaseDenomUpper, + Symbol: NewBaseDenomUpper, + } - for _, metadata := range bankGenState.DenomMetadata { - replaceString(&metadata.Base, []*regexPair{denomRegex}) + for i, metadata := range bankGenState.DenomMetadata { if metadata.Name == OldBaseDenomUpper { - metadata.Description = NewDescription - metadata.Display = NewBaseDenomUpper - metadata.Name = NewBaseDenomUpper - metadata.Symbol = NewBaseDenomUpper - } - for _, unit := range metadata.DenomUnits { - replaceString(&unit.Denom, []*regexPair{upperDenomRegex}) - replaceString(&unit.Denom, []*regexPair{exponentDenomRegex}) + (*bankGenState).DenomMetadata[i] = newMetadata + break } } @@ -136,12 +162,35 @@ func ASIGenesisUpgradeReplaceChainID(genesisData *types.GenesisDoc) { } func ASIGenesisUpgradeReplaceDenom(jsonString *string) { - for _, target := range []string{"denom", "bond_denom", "mint_denom", "base_denom", "base"} { - re := regexp.MustCompile(fmt.Sprintf(`("%s"\s*:\s*)"%s"`, target, OldDenom)) - if re.MatchString(*jsonString) { - *jsonString = re.ReplaceAllString(*jsonString, fmt.Sprintf(`${1}"%s"`, NewDenom)) + var jsonData map[string]interface{} + err := json.Unmarshal([]byte(*jsonString), &jsonData) + if err != nil { + panic(err) + } + + keyIsInTarget := func(target string) bool { + for _, key := range []string{"denom", "bond_denom", "mint_denom", "base_denom", "base"} { + if target == key { + return true + } } + return false } + + modifiedGenesisJson := crawlJson(nil, jsonData, func(key interface{}, value interface{}) interface{} { + if str, ok := value.(string); ok { + if str == OldDenom && keyIsInTarget(key.(string)) { + return NewDenom + } + } + return value + }) + + modifiedJSON, err := json.Marshal(modifiedGenesisJson) + if err != nil { + panic(err) + } + *jsonString = string(modifiedJSON) } func ASIGenesisUpgradeReplaceAddresses() {} @@ -150,30 +199,21 @@ func ASIGenesisUpgradeWithdrawIBCChannelsBalances() {} func ASIGenesisUpgradeWithdrawReconciliationBalances() {} -func getRegex(oldValue string, newValue string) *regexPair { - return ®exPair{ - pattern: fmt.Sprintf(`^%s$`, oldValue), - replacement: fmt.Sprintf(`%s`, newValue), - } -} - -func getPartialRegexLeft(oldValue string, newValue string) *regexPair { - return ®exPair{ - pattern: fmt.Sprintf(`(.*?)%s"`, oldValue), - replacement: fmt.Sprintf(`${1}%s"`, newValue), - } -} - -func replaceString(s *string, replacements []*regexPair) { - for _, pair := range replacements { - re := regexp.MustCompile(pair.pattern) - if re.MatchString(*s) { - *s = re.ReplaceAllString(*s, pair.replacement) +func crawlJson(key interface{}, value interface{}, strHandler func(interface{}, interface{}) interface{}) interface{} { + switch val := value.(type) { + case string: + if strHandler != nil { + return strHandler(key, val) + } + case []interface{}: + for i := range val { + val[i] = crawlJson(nil, val[i], strHandler) + } + case map[string]interface{}: + for k := range val { + val[k] = crawlJson(k, val[k], strHandler) } + default: } -} - -type regexPair struct { - pattern string - replacement string + return value }