From 62a16a9f42a2096e94ff9b2345d22b59ab130f43 Mon Sep 17 00:00:00 2001 From: jonathansumner Date: Thu, 18 Apr 2024 14:20:05 +0100 Subject: [PATCH 1/4] feat: update bridge contract admin --- cmd/fetchd/cmd/genasiupgrade.go | 43 +++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/cmd/fetchd/cmd/genasiupgrade.go b/cmd/fetchd/cmd/genasiupgrade.go index 372649c8..270f0b14 100644 --- a/cmd/fetchd/cmd/genasiupgrade.go +++ b/cmd/fetchd/cmd/genasiupgrade.go @@ -1,9 +1,12 @@ package cmd import ( + "encoding/json" "fmt" + "github.com/CosmWasm/wasmd/x/wasm" "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" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" @@ -12,6 +15,9 @@ import ( ) const ( + BridgeContractAddress = "fetch1qxxlalvsdjd07p07y3rc5fu6ll8k4tmetpha8n" + NewBridgeContractAdmin = "fetch15p3rl5aavw9rtu86tna5lgxfkz67zzr6ed4yhw" + flagNewDescription = "new-description" Bech32Chars = "023456789acdefghjklmnpqrstuvwxyz" AddrDataLength = 32 @@ -49,18 +55,31 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config + cdc := clientCtx.Codec config.SetRoot(clientCtx.HomeDir) genFile := config.GenesisFile() - _, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) + appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) if err != nil { return fmt.Errorf("failed to unmarshal genesis state: %w", err) } // replace chain-id ASIGenesisUpgradeReplaceChainID(genDoc) + + // replace bridge contract admin + if err = ASIGenesisUpgradeReplaceBridgeAdmin(&cdc, &appState); err != nil { + return fmt.Errorf("failed to replace bridge contract admin: %w", err) + } + + var modifiedGenState json.RawMessage + if modifiedGenState, err = json.Marshal(appState); err != nil { + return fmt.Errorf("failed to marshal app state: %w", err) + } + + (*genDoc).AppState = modifiedGenState return genutil.ExportGenesisFile(genDoc, genFile) }, } @@ -79,7 +98,27 @@ func ASIGenesisUpgradeReplaceChainID(genesisData *types.GenesisDoc) { genesisData.ChainID = NewChainId } -func ASIGenesisUpgradeReplaceBridgeAdmin() {} +func ASIGenesisUpgradeReplaceBridgeAdmin(cdc *codec.Codec, appState *map[string]json.RawMessage) error { + var wasmGenState wasm.GenesisState + if err := (*cdc).UnmarshalJSON((*appState)[wasm.ModuleName], &wasmGenState); err != nil { + return fmt.Errorf("failed to unmarshal wasm genesis state: %w", err) + } + + for i, contract := range wasmGenState.Contracts { + if contract.ContractAddress == BridgeContractAddress { + wasmGenState.Contracts[i].ContractInfo.Admin = NewBridgeContractAdmin + break + } + } + + wasmGenStateBytes, err := (*cdc).MarshalJSON(&wasmGenState) + if err != nil { + return fmt.Errorf("failed to marshal auth genesis state: %w", err) + } + + (*appState)[wasm.ModuleName] = wasmGenStateBytes + return nil +} func ASIGenesisUpgradeReplaceDenom() {} From 5e1937b9c66bdd02e07cba447ee12cea1b96ca88 Mon Sep 17 00:00:00 2001 From: jonathansumner Date: Thu, 18 Apr 2024 19:05:13 +0100 Subject: [PATCH 2/4] refactor: use json indexing instead of genesis structs --- cmd/fetchd/cmd/genasiupgrade.go | 197 +++++++++++++++++++++++++++----- go.mod | 2 + go.sum | 1 + 3 files changed, 171 insertions(+), 29 deletions(-) diff --git a/cmd/fetchd/cmd/genasiupgrade.go b/cmd/fetchd/cmd/genasiupgrade.go index 270f0b14..9326c4e6 100644 --- a/cmd/fetchd/cmd/genasiupgrade.go +++ b/cmd/fetchd/cmd/genasiupgrade.go @@ -3,15 +3,17 @@ package cmd import ( "encoding/json" "fmt" - "github.com/CosmWasm/wasmd/x/wasm" + "github.com/btcsuite/btcutil/bech32" "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" + sdk "github.com/cosmos/cosmos-sdk/types" "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 ( @@ -55,31 +57,45 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config - cdc := clientCtx.Codec config.SetRoot(clientCtx.HomeDir) genFile := config.GenesisFile() - appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) + _, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) if err != nil { return fmt.Errorf("failed to unmarshal genesis state: %w", err) } - // replace chain-id - ASIGenesisUpgradeReplaceChainID(genDoc) + var jsonData map[string]interface{} + if err = json.Unmarshal(genDoc.AppState, &jsonData); err != nil { + return fmt.Errorf("failed to unmarshal app state: %w", err) + } // replace bridge contract admin - if err = ASIGenesisUpgradeReplaceBridgeAdmin(&cdc, &appState); err != nil { - return fmt.Errorf("failed to replace bridge contract admin: %w", err) + ASIGenesisUpgradeReplaceBridgeAdmin(jsonData) + + // replace addresses across the genesis file + ASIGenesisUpgradeReplaceAddresses(jsonData) + + // set denom metadata in bank module + err = ASIGenesisUpgradeReplaceDenomMetadata(jsonData) + if err != nil { + return fmt.Errorf("failed to replace denom metadata: %w", err) } - var modifiedGenState json.RawMessage - if modifiedGenState, err = json.Marshal(appState); err != nil { - return fmt.Errorf("failed to marshal app state: %w", err) + // replace denom across the genesis file + ASIGenesisUpgradeReplaceDenom(jsonData) + + // replace chain-id + ASIGenesisUpgradeReplaceChainID(genDoc) + + var encodedAppState []byte + if encodedAppState, err = json.Marshal(jsonData); err != nil { + return err } - (*genDoc).AppState = modifiedGenState + genDoc.AppState = encodedAppState return genutil.ExportGenesisFile(genDoc, genFile) }, } @@ -92,38 +108,161 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { return cmd } -func ASIGenesisUpgradeReplaceDenomMetadata() {} +func ASIGenesisUpgradeReplaceDenomMetadata(jsonData map[string]interface{}) error { + type jsonMap map[string]interface{} + + NewBaseDenomUpper := strings.ToUpper(NewBaseDenom) + + newMetadata := jsonMap{ + "base": NewDenom, + "denom_units": []jsonMap{ + { + "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, + } + + bank := jsonData["bank"].(map[string]interface{}) + denomMetadata := bank["denom_metadata"].([]interface{}) + + for i, metadata := range denomMetadata { + denomUnit := metadata.(map[string]interface{}) + if denomUnit["base"] == OldDenom { + denomMetadata[i] = newMetadata + break + } + } + return nil +} func ASIGenesisUpgradeReplaceChainID(genesisData *types.GenesisDoc) { genesisData.ChainID = NewChainId } -func ASIGenesisUpgradeReplaceBridgeAdmin(cdc *codec.Codec, appState *map[string]json.RawMessage) error { - var wasmGenState wasm.GenesisState - if err := (*cdc).UnmarshalJSON((*appState)[wasm.ModuleName], &wasmGenState); err != nil { - return fmt.Errorf("failed to unmarshal wasm genesis state: %w", err) - } +func ASIGenesisUpgradeReplaceBridgeAdmin(jsonData map[string]interface{}) { + contracts := jsonData["wasm"].(map[string]interface{})["contracts"].([]interface{}) - for i, contract := range wasmGenState.Contracts { - if contract.ContractAddress == BridgeContractAddress { - wasmGenState.Contracts[i].ContractInfo.Admin = NewBridgeContractAdmin + for i, contract := range contracts { + c := contract.(map[string]interface{}) + if c["contract_address"] == BridgeContractAddress { + contractInfo := c["contract_info"].(map[string]interface{}) + contractInfo["admin"] = NewBridgeContractAdmin + contracts[i] = c break } } +} - wasmGenStateBytes, err := (*cdc).MarshalJSON(&wasmGenState) - if err != nil { - return fmt.Errorf("failed to marshal auth genesis state: %w", err) - } +func ASIGenesisUpgradeReplaceDenom(jsonData map[string]interface{}) { + targets := map[string]struct{}{"denom": {}, "bond_denom": {}, "mint_denom": {}, "base_denom": {}, "base": {}} - (*appState)[wasm.ModuleName] = wasmGenStateBytes - return nil + crawlJson("", jsonData, -1, func(key string, value interface{}, idx int) interface{} { + if str, ok := value.(string); ok { + _, isInTargets := targets[key] + if str == OldDenom && isInTargets { + return NewDenom + } + } + return value + }) } -func ASIGenesisUpgradeReplaceDenom() {} +func ASIGenesisUpgradeReplaceAddresses(jsonData map[string]interface{}) { + // account addresses + replaceAddresses(AccAddressPrefix, jsonData, AddrDataLength+AddrChecksumLength) + // validator addresses + replaceAddresses(ValAddressPrefix, jsonData, AddrDataLength+AddrChecksumLength) + // consensus addresses + replaceAddresses(ConsAddressPrefix, jsonData, AddrDataLength+AddrChecksumLength) + // contract addresses + replaceAddresses(AccAddressPrefix, jsonData, WasmDataLength+AddrChecksumLength) +} -func ASIGenesisUpgradeReplaceAddresses() {} +func replaceAddresses(addressTypePrefix string, jsonData map[string]interface{}, dataLength int) { + re := regexp.MustCompile(fmt.Sprintf(`^%s%s1([%s]{%d})$`, OldAddrPrefix, addressTypePrefix, Bech32Chars, dataLength)) + + crawlJson("", jsonData, -1, func(key string, value interface{}, idx int) interface{} { + if str, ok := value.(string); ok { + if !re.MatchString(str) { + return value + } + newAddress, err := convertAddressToASI(str, addressTypePrefix) + if err != nil { + panic(err) + } + + return newAddress + } + return value + }) +} func ASIGenesisUpgradeWithdrawIBCChannelsBalances() {} func ASIGenesisUpgradeWithdrawReconciliationBalances() {} + +func crawlJson(key string, value interface{}, idx int, strHandler func(string, interface{}, int) interface{}) interface{} { + switch val := value.(type) { + case string: + if strHandler != nil { + return strHandler(key, val, idx) + } + case []interface{}: + for i := range val { + val[i] = crawlJson("", val[i], i, strHandler) + } + case map[string]interface{}: + for k, v := range val { + val[k] = crawlJson(k, v, -1, strHandler) + } + } + return value +} + +func convertAddressToASI(addr string, addressTypePrefix string) (string, error) { + _, decodedAddrData, err := bech32.Decode(addr) + if err != nil { + return "", fmt.Errorf("failed to decode address: %w", err) + } + + err = sdk.VerifyAddressFormat(decodedAddrData) + if err != nil { + return "", fmt.Errorf("failed to verify address format: %w", err) + } + + newAddress, err := bech32.Encode(NewAddrPrefix+addressTypePrefix, decodedAddrData) + if err != nil { + return "", fmt.Errorf("failed to encode new address: %w", err) + } + + return newAddress, nil +} diff --git a/go.mod b/go.mod index 32d3950a..b446d809 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,8 @@ require ( github.com/tendermint/tm-db v0.6.7 ) +require github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce + require ( filippo.io/edwards25519 v1.0.0-beta.2 // indirect github.com/99designs/keyring v1.1.6 // indirect diff --git a/go.sum b/go.sum index a83afb2d..6467bd8d 100644 --- a/go.sum +++ b/go.sum @@ -122,6 +122,7 @@ github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+q github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= From b740c22ade213e759271dd4e9ce591912e275190 Mon Sep 17 00:00:00 2001 From: Peter Bukva Date: Thu, 18 Apr 2024 19:20:31 +0100 Subject: [PATCH 3/4] fix: bech32 charset --- cmd/fetchd/cmd/genasiupgrade.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/fetchd/cmd/genasiupgrade.go b/cmd/fetchd/cmd/genasiupgrade.go index 9326c4e6..8bffa55d 100644 --- a/cmd/fetchd/cmd/genasiupgrade.go +++ b/cmd/fetchd/cmd/genasiupgrade.go @@ -21,7 +21,7 @@ const ( NewBridgeContractAdmin = "fetch15p3rl5aavw9rtu86tna5lgxfkz67zzr6ed4yhw" flagNewDescription = "new-description" - Bech32Chars = "023456789acdefghjklmnpqrstuvwxyz" + Bech32Chars = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" AddrDataLength = 32 WasmDataLength = 52 AddrChecksumLength = 6 From 79ae8df3cdb5921d761dd0f1df901a555c3de6e6 Mon Sep 17 00:00:00 2001 From: jonathansumner Date: Fri, 19 Apr 2024 14:10:04 +0100 Subject: [PATCH 4/4] chore: remove unnecessary error handling --- cmd/fetchd/cmd/genasiupgrade.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cmd/fetchd/cmd/genasiupgrade.go b/cmd/fetchd/cmd/genasiupgrade.go index 7c888799..a387a295 100644 --- a/cmd/fetchd/cmd/genasiupgrade.go +++ b/cmd/fetchd/cmd/genasiupgrade.go @@ -82,10 +82,7 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { ASIGenesisUpgradeReplaceDenom(jsonData) // set denom metadata in bank module - err = ASIGenesisUpgradeReplaceDenomMetadata(jsonData) - if err != nil { - return fmt.Errorf("failed to replace denom metadata: %w", err) - } + ASIGenesisUpgradeReplaceDenomMetadata(jsonData) // replace addresses across the genesis file ASIGenesisUpgradeReplaceAddresses(jsonData) @@ -108,7 +105,7 @@ func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command { return cmd } -func ASIGenesisUpgradeReplaceDenomMetadata(jsonData map[string]interface{}) error { +func ASIGenesisUpgradeReplaceDenomMetadata(jsonData map[string]interface{}) { type jsonMap map[string]interface{} NewBaseDenomUpper := strings.ToUpper(NewBaseDenom) @@ -161,7 +158,6 @@ func ASIGenesisUpgradeReplaceDenomMetadata(jsonData map[string]interface{}) erro break } } - return nil } func ASIGenesisUpgradeReplaceChainID(genesisData *types.GenesisDoc) {