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

refactor(client): use address codec #17503

Merged
merged 15 commits into from
Aug 23, 2023
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

* (client) [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503) Add `client.Context{}.WithAddressCodec`, `WithValidatorAddressCodec`, `WithConsensusAddressCodec` to provide address codecs to the client context. See the [UPGRADING.md](./UPGRADING.md) for more details.
* (crypto/keyring) [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503) Simplify keyring interfaces to use `[]byte` instead of `sdk.Address` for addresses.
* (all) [#16537](https://github.com/cosmos/cosmos-sdk/pull/16537) Properly propagated `fmt.Errorf` errors and using `errors.New` where appropriate.

### Bug Fixes
Expand All @@ -52,6 +54,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### API Breaking Changes

* (client/keys) [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503) `clientkeys.NewKeyOutput`, `MkConsKeyOutput`, `MkValKeyOutput`, `MkAccKeyOutput`, `MkAccKeysOutput` now take their corresponding address codec instead of using the global SDK config.
* (x/staking) [#17336](https://github.com/cosmos/cosmos-sdk/pull/17336) Use collections for `RedelegationByValDstIndexKey`:
* remove from `types`: `GetREDByValDstIndexKey`, `GetREDsToValDstIndexKey`
* (x/staking) [#17332](https://github.com/cosmos/cosmos-sdk/pull/17332) Use collections for `RedelegationByValSrcIndexKey`:
Expand Down
31 changes: 30 additions & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,34 @@ Note, always read the **SimApp** section for more information on application wir

## [Unreleased]

### Migration to Collections
### SimApp

In this section we describe the changes made in Cosmos SDK' SimApp.
**These changes are directly applicable to your application wiring.**

#### Client (`root.go`)

The `client` package has been refactored to make use of the address codecs (address, validator address, consensus address, etc.).
This is part of the work of abstracting the SDK from the global bech32 config.

This means the address codecs must be provided in the `client.Context` in the application client (usually `root.go`).

```diff
clientCtx = clientCtx.
+ WithAddressCodec(addressCodec).
+ WithValidatorAddressCodec(validatorAddressCodec).
+ WithConsensusAddressCodec(consensusAddressCodec)
```

**When using `depinject` / `app v2`, the client codecs can be provided directly from application config.**

Refer to SimApp `root_v2.go` and `root.go` for an example with an app v2 and a legacy app.

### Modules

#### `**all**`

##### Migration to Collections

Most of Cosmos SDK modules have migrated to [collections](https://docs.cosmos.network/main/packages/collections).
Many functions have been removed due to this changes as the API can be smaller thanks to collections.
Expand Down Expand Up @@ -78,9 +105,11 @@ for more info.
#### Upgrade

**Users using `depinject` / app v2 do not need any changes, this is abstracted for them.**

```diff
+ app.BaseApp.SetMigrationModuleManager(app.ModuleManager)
```

BaseApp added `SetMigrationModuleManager` for apps to set their ModuleManager which implements `RunMigrationBeginBlock`. This is essential for BaseApp to run `BeginBlock` of upgrade module and inject `ConsensusParams` to context for `beginBlocker` during `beginBlock`.

#### Events
Expand Down
4 changes: 2 additions & 2 deletions client/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, err
payer, _ := flagSet.GetString(flags.FlagFeePayer)

if payer != "" {
payerAcc, err := sdk.AccAddressFromBech32(payer)
payerAcc, err := clientCtx.AddressCodec.StringToBytes(payer)
if err != nil {
return clientCtx, err
}
Expand All @@ -264,7 +264,7 @@ func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, err
granter, _ := flagSet.GetString(flags.FlagFeeGranter)

if granter != "" {
granterAcc, err := sdk.AccAddressFromBech32(granter)
granterAcc, err := clientCtx.AddressCodec.StringToBytes(granter)
if err != nil {
return clientCtx, err
}
Expand Down
29 changes: 27 additions & 2 deletions client/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"google.golang.org/grpc"
"sigs.k8s.io/yaml"

"cosmossdk.io/core/address"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
Expand Down Expand Up @@ -65,6 +67,11 @@ type Context struct {

// CmdContext is the context.Context from the Cobra command.
CmdContext context.Context

// Address codecs
AddressCodec address.Codec
ValidatorAddressCodec address.Codec
ConsensusAddressCodec address.Codec
}

// WithCmdContext returns a copy of the context with an updated context.Context,
Expand Down Expand Up @@ -292,6 +299,24 @@ func (ctx Context) WithPreprocessTxHook(preprocessFn PreprocessTxFn) Context {
return ctx
}

// WithAddressCodec returns the context with the provided address codec.
func (ctx Context) WithAddressCodec(addressCodec address.Codec) Context {
ctx.AddressCodec = addressCodec
return ctx
}

// WithValidatorAddressCodec returns the context with the provided validator address codec.
func (ctx Context) WithValidatorAddressCodec(validatorAddressCodec address.Codec) Context {
ctx.ValidatorAddressCodec = validatorAddressCodec
return ctx
}

// WithConsensusAddressCodec returns the context with the provided consensus address codec.
func (ctx Context) WithConsensusAddressCodec(consensusAddressCodec address.Codec) Context {
ctx.ConsensusAddressCodec = consensusAddressCodec
return ctx
}

// PrintString prints the raw string to ctx.Output if it's defined, otherwise to os.Stdout
func (ctx Context) PrintString(str string) error {
return ctx.PrintBytes([]byte(str))
Expand Down Expand Up @@ -365,11 +390,11 @@ func GetFromFields(clientCtx Context, kr keyring.Keyring, from string) (sdk.AccA
return nil, "", 0, nil
}

addr, err := sdk.AccAddressFromBech32(from)
addr, err := clientCtx.AddressCodec.StringToBytes(from)
switch {
case clientCtx.Simulate:
if err != nil {
return nil, "", 0, fmt.Errorf("a valid bech32 address must be provided in simulation mode: %w", err)
return nil, "", 0, fmt.Errorf("a valid address must be provided in simulation mode: %w", err)
}

return addr, "", 0, nil
Expand Down
28 changes: 16 additions & 12 deletions client/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"encoding/json"
"os"
"strings"
"testing"

"github.com/spf13/viper"
Expand All @@ -13,6 +12,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
Expand Down Expand Up @@ -108,6 +108,7 @@ func TestGetFromFields(t *testing.T) {
expectedErr string
}{
{
clientCtx: client.Context{}.WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
kb := keyring.NewInMemory(cfg.Codec)

Expand All @@ -119,6 +120,7 @@ func TestGetFromFields(t *testing.T) {
from: "alice",
},
{
clientCtx: client.Context{}.WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, cfg.Codec)
require.NoError(t, err)
Expand All @@ -131,13 +133,15 @@ func TestGetFromFields(t *testing.T) {
from: "alice",
},
{
clientCtx: client.Context{}.WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
expectedErr: "key with address cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5 not found: key not found",
expectedErr: "key with given address not found: key not found",
},
{
clientCtx: client.Context{}.WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, cfg.Codec)
require.NoError(t, err)
Expand All @@ -147,36 +151,37 @@ func TestGetFromFields(t *testing.T) {
expectedErr: "alice.info: key not found",
},
{
clientCtx: client.Context{}.WithSimulation(true).WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
clientCtx: client.Context{}.WithSimulation(true),
from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
},
{
clientCtx: client.Context{}.WithSimulation(true).WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "alice",
clientCtx: client.Context{}.WithSimulation(true),
expectedErr: "a valid bech32 address must be provided in simulation mode",
expectedErr: "a valid address must be provided in simulation mode",
},
{
clientCtx: client.Context{}.WithGenerateOnly(true).WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
clientCtx: client.Context{}.WithGenerateOnly(true),
from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
},
{
clientCtx: client.Context{}.WithGenerateOnly(true).WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "alice",
clientCtx: client.Context{}.WithGenerateOnly(true),
expectedErr: "alice.info: key not found",
},
{
clientCtx: client.Context{}.WithGenerateOnly(true).WithAddressCodec(addresscodec.NewBech32Codec("cosmos")),
keyring: func() keyring.Keyring {
kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, cfg.Codec)
require.NoError(t, err)
Expand All @@ -186,8 +191,7 @@ func TestGetFromFields(t *testing.T) {

return kb
},
clientCtx: client.Context{}.WithGenerateOnly(true),
from: "alice",
from: "alice",
},
}

Expand All @@ -196,7 +200,7 @@ func TestGetFromFields(t *testing.T) {
if tc.expectedErr == "" {
require.NoError(t, err)
} else {
require.True(t, strings.HasPrefix(err.Error(), tc.expectedErr))
require.ErrorContains(t, err, tc.expectedErr)
}
}
}
27 changes: 13 additions & 14 deletions client/debug/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,27 +193,26 @@ $ %s debug pubkey-raw cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg

func AddrCmd() *cobra.Command {
return &cobra.Command{
Use: "addr [address]",
Short: "Convert an address between hex and bech32",
Long: fmt.Sprintf(`Convert an address between hex encoding and bech32.

Example:
$ %s debug addr cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg
`, version.AppName),
Args: cobra.ExactArgs(1),
Use: "addr [address]",
Short: "Convert an address between hex and bech32",
Example: fmt.Sprintf("%s debug addr cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg", version.AppName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
addrString := args[0]
var addr []byte
clientCtx := client.GetClientContextFromCmd(cmd)

addrString := args[0]
// try hex, then bech32
var err error
var (
addr []byte
err error
)
addr, err = hex.DecodeString(addrString)
if err != nil {
var err2 error
addr, err2 = sdk.AccAddressFromBech32(addrString)
addr, err2 = clientCtx.AddressCodec.StringToBytes(addrString)
if err2 != nil {
var err3 error
addr, err3 = sdk.ValAddressFromBech32(addrString)
addr, err3 = clientCtx.ValidatorAddressCodec.StringToBytes(addrString)

if err3 != nil {
return fmt.Errorf("expected hex or bech32. Got errors: hex: %v, bech32 acc: %v, bech32 val: %v", err, err2, err3)
Expand Down Expand Up @@ -264,7 +263,7 @@ func PrefixesCmd() *cobra.Command {
return &cobra.Command{
Use: "prefixes",
Short: "List prefixes used for Human-Readable Part (HRP) in Bech32",
Long: "List prefixes used in Bech32 addresses.",
Long: "List prefixes used in Bech32 addresses. NOTE, if the chain does not use the Cosmos SDK global config, this will not be accurate.",
Example: fmt.Sprintf("$ %s debug prefixes", version.AppName),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.Printf("Bech32 Acc: %s\n", sdk.GetConfig().GetBech32AccountAddrPrefix())
Expand Down
19 changes: 12 additions & 7 deletions client/keys/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
return err
}

return printCreate(cmd, k, false, "", outputFormat)
return printCreate(ctx, cmd, k, false, "", outputFormat)
}
}

Expand All @@ -200,7 +200,7 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
return err
}

return printCreate(cmd, k, false, "", outputFormat)
return printCreate(ctx, cmd, k, false, "", outputFormat)
}

coinType, _ := cmd.Flags().GetUint32(flagCoinType)
Expand All @@ -223,7 +223,7 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
return err
}

return printCreate(cmd, k, false, "", outputFormat)
return printCreate(ctx, cmd, k, false, "", outputFormat)
}

// Get bip39 mnemonic
Expand Down Expand Up @@ -297,14 +297,19 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
mnemonic = ""
}

return printCreate(cmd, k, showMnemonic, mnemonic, outputFormat)
return printCreate(ctx, cmd, k, showMnemonic, mnemonic, outputFormat)
}

func printCreate(cmd *cobra.Command, k *keyring.Record, showMnemonic bool, mnemonic, outputFormat string) error {
func printCreate(ctx client.Context, cmd *cobra.Command, k *keyring.Record, showMnemonic bool, mnemonic, outputFormat string) error {
switch outputFormat {
case flags.OutputFormatText:
cmd.PrintErrln()
if err := printKeyringRecord(cmd.OutOrStdout(), k, MkAccKeyOutput, outputFormat); err != nil {
ko, err := MkAccKeyOutput(k, ctx.AddressCodec)
if err != nil {
return err
}

if err := printKeyringRecord(cmd.OutOrStdout(), ko, outputFormat); err != nil {
return err
}

Expand All @@ -315,7 +320,7 @@ func printCreate(cmd *cobra.Command, k *keyring.Record, showMnemonic bool, mnemo
}
}
case flags.OutputFormatJSON:
out, err := MkAccKeyOutput(k)
out, err := MkAccKeyOutput(k, ctx.AddressCodec)
if err != nil {
return err
}
Expand Down
9 changes: 8 additions & 1 deletion client/keys/add_ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/testutil"
Expand Down Expand Up @@ -44,7 +45,13 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) {
kbHome := t.TempDir()

cdc := moduletestutil.MakeTestEncodingConfig().Codec
clientCtx := client.Context{}.WithKeyringDir(kbHome).WithCodec(cdc)
clientCtx := client.Context{}.
WithKeyringDir(kbHome).
WithCodec(cdc).
WithAddressCodec(addresscodec.NewBech32Codec("cosmos")).
WithValidatorAddressCodec(addresscodec.NewBech32Codec("cosmosvaloper")).
WithConsensusAddressCodec(addresscodec.NewBech32Codec("cosmosvalcons"))

ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)

cmd.SetArgs([]string{
Expand Down
Loading
Loading