feat(hubl): cache bech32 prefix (#15954)

This commit is contained in:
Julien Robert 2023-04-26 18:34:56 +02:00 committed by GitHub
parent 6a8251aafa
commit 1179285bf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 89 additions and 71 deletions

View File

@ -1,6 +1,8 @@
package autocli
import (
"errors"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/client/v2/autocli/flag"
"cosmossdk.io/core/address"
@ -19,8 +21,8 @@ import (
// var autoCliOpts autocli.AppOptions
// err := depinject.Inject(appConfig, &encodingConfig.InterfaceRegistry, &autoCliOpts)
//
// If depinject isn't used, options can be provided manually or extracted from modules. One method for extracting autocli
// options is via the github.com/cosmos/cosmos-sdk/runtime/services.ExtractAutoCLIOptions function.
// If depinject isn't used, options can be provided manually or extracted from modules and the address codec can be provided by the auth keeper.
// One method for extracting autocli options is via the github.com/cosmos/cosmos-sdk/runtime/services.ExtractAutoCLIOptions function.
type AppOptions struct {
depinject.In
@ -34,8 +36,7 @@ type AppOptions struct {
ModuleOptions map[string]*autocliv1.ModuleOptions `optional:"true"`
// AddressCodec is the address codec to use for the app.
// If not provided the default address prefix will be fetched from the reflection client.
AddressCodec address.Codec `optional:"true"`
AddressCodec address.Codec
}
// EnhanceRootCommand enhances the provided root command with autocli AppOptions,
@ -57,9 +58,6 @@ func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error {
builder := &Builder{
Builder: flag.Builder{
AddressCodec: appOptions.AddressCodec,
GetClientConn: func() (grpc.ClientConnInterface, error) {
return client.GetClientQueryContext(rootCmd)
},
},
GetClientConn: func(cmd *cobra.Command) (grpc.ClientConnInterface, error) {
return client.GetClientQueryContext(cmd)
@ -72,6 +70,10 @@ func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error {
}
func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Command, builder *Builder) error {
if builder.AddressCodec == nil {
return errors.New("address codec is required in builder")
}
// extract any custom commands from modules
customQueryCmds, customMsgCmds := map[string]*cobra.Command{}, map[string]*cobra.Command{}
for name, module := range appOptions.Modules {

View File

@ -6,15 +6,17 @@ import (
"net"
"testing"
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
"cosmossdk.io/client/v2/autocli/flag"
"cosmossdk.io/client/v2/internal/testpb"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"gotest.tools/v3/assert"
"google.golang.org/grpc/credentials/insecure"
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"cosmossdk.io/client/v2/autocli/flag"
"cosmossdk.io/client/v2/internal/testpb"
)
func testExecCommon(t *testing.T, buildModuleCommand func(string, *Builder) (*cobra.Command, error), args ...string) *testClientConn {
@ -47,9 +49,7 @@ func testExecCommon(t *testing.T, buildModuleCommand func(string, *Builder) (*co
}
b := &Builder{
Builder: flag.Builder{
GetClientConn: func() (grpc.ClientConnInterface, error) {
return conn, nil
},
AddressCodec: addresscodec.NewBech32Codec("cosmos"),
},
GetClientConn: func(*cobra.Command) (grpc.ClientConnInterface, error) {
return conn, nil

View File

@ -4,33 +4,14 @@ import (
"context"
"fmt"
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
"cosmossdk.io/core/address"
"google.golang.org/protobuf/reflect/protoreflect"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"cosmossdk.io/core/address"
)
type addressStringType struct{}
func (a addressStringType) NewValue(ctx context.Context, b *Builder) Value {
if b.AddressCodec == nil {
conn, err := b.GetClientConn()
if err != nil {
panic(err)
}
reflectionClient := reflectionv2alpha1.NewReflectionServiceClient(conn)
resp, err := reflectionClient.GetConfigurationDescriptor(ctx, &reflectionv2alpha1.GetConfigurationDescriptorRequest{})
if err != nil {
panic(err)
}
if resp == nil || resp.Config == nil {
panic("bech32 account address prefix is not set")
}
b.AddressCodec = addresscodec.NewBech32Codec(resp.Config.Bech32AccountAddressPrefix)
}
return &addressValue{addressCodec: b.AddressCodec}
}

View File

@ -1,7 +1,6 @@
package flag
import (
"google.golang.org/grpc"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
@ -27,9 +26,6 @@ type Builder struct {
// AddressCodec is the address codec used for the address flag
AddressCodec address.Codec
// GetClientConn is the reflection client for the address flag
GetClientConn func() (grpc.ClientConnInterface, error)
}
func (b *Builder) init() {

View File

@ -1,6 +1,9 @@
package address
import (
"errors"
"strings"
"cosmossdk.io/core/address"
errorsmod "cosmossdk.io/errors"
@ -21,13 +24,17 @@ func NewBech32Codec(prefix string) address.Codec {
// StringToBytes encodes text to bytes
func (bc Bech32Codec) StringToBytes(text string) ([]byte, error) {
if len(strings.TrimSpace(text)) == 0 {
return []byte{}, errors.New("empty address string is not allowed")
}
hrp, bz, err := bech32.DecodeAndConvert(text)
if err != nil {
return nil, err
}
if hrp != bc.Bech32Prefix {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "hrp does not match bech32Prefix")
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "hrp does not match bech32 prefix: expected '%s' got '%s'", bc.Bech32Prefix, hrp)
}
if err := sdk.VerifyAddressFormat(bz); err != nil {

View File

@ -4,9 +4,10 @@ go 1.20
require (
cosmossdk.io/api v0.4.1
cosmossdk.io/client/v2 v2.0.0-20230320224637-dca0e7374a1d
cosmossdk.io/client/v2 v2.0.0-20230426154441-2037a26d1235
cosmossdk.io/errors v1.0.0-beta.7
github.com/cockroachdb/errors v1.9.1
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230426154441-2037a26d1235
github.com/hashicorp/go-multierror v1.1.1
github.com/manifoldco/promptui v0.9.0
github.com/pelletier/go-toml/v2 v2.0.7
@ -17,7 +18,7 @@ require (
require (
cosmossdk.io/collections v0.1.0 // indirect
cosmossdk.io/core v0.6.1 // indirect
cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4 // indirect
cosmossdk.io/depinject v1.0.0-alpha.3 // indirect
cosmossdk.io/log v1.0.0 // indirect
cosmossdk.io/math v1.0.0 // indirect
@ -42,7 +43,6 @@ require (
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-db v1.0.0-rc.1 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.3 // indirect
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230424095137-b73c17cb9cc8 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogoproto v1.4.8 // indirect
github.com/cosmos/iavl v0.21.0-beta.1 // indirect

View File

@ -37,12 +37,12 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cosmossdk.io/api v0.4.1 h1:0ikaYM6GyxTYYcfBiyR8YnLCfhNnhKpEFnaSepCTmqg=
cosmossdk.io/api v0.4.1/go.mod h1:jR7k5ok90LxW2lFUXvd8Vpo/dr4PpiyVegxdm7b1ZdE=
cosmossdk.io/client/v2 v2.0.0-20230320224637-dca0e7374a1d h1:9mBIeO0ZhCalqS3pJiZ1fs+Nn93E7rU4+Hv7QVINbNM=
cosmossdk.io/client/v2 v2.0.0-20230320224637-dca0e7374a1d/go.mod h1:qX4UABq4VI1ccJn4H4MIJx5/HvjRiaVaImovbnPXNXc=
cosmossdk.io/client/v2 v2.0.0-20230426154441-2037a26d1235 h1:6aGhtjUgmacucrKMC9ZdF9G96YoxZqkTC2ZyxaAg1GE=
cosmossdk.io/client/v2 v2.0.0-20230426154441-2037a26d1235/go.mod h1:ydI6QS3A+K2px6O8QpM0JtNaVV6lLeCJ5LVwtQXIMAg=
cosmossdk.io/collections v0.1.0 h1:nzJGeiq32KnZroSrhB6rPifw4I85Cgmzw/YAmr4luv8=
cosmossdk.io/collections v0.1.0/go.mod h1:xbauc0YsbUF8qKMVeBZl0pFCunxBIhKN/WlxpZ3lBuo=
cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s=
cosmossdk.io/core v0.6.1/go.mod h1:g3MMBCBXtxbDWBURDVnJE7XML4BG5qENhs0gzkcpuFA=
cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4 h1:l1scDTT2VX18ZuR6P0irvT/bAP0h4297D/Lka5nz2vE=
cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4/go.mod h1:J8R0E7soOpQFVqFiFd7EKepXCPpINa2n2t2EqbEsXnY=
cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw=
cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU=
cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w=
@ -146,8 +146,8 @@ github.com/cosmos/cosmos-db v1.0.0-rc.1 h1:SjnT8B6WKMW9WEIX32qMhnEEKcI7ZP0+G1Sa9
github.com/cosmos/cosmos-db v1.0.0-rc.1/go.mod h1:Dnmk3flSf5lkwCqvvjNpoxjpXzhxnCAFzKHlbaForso=
github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o=
github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I=
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230424095137-b73c17cb9cc8 h1:zIl1WnrW5ZP1VwhpbwVBZtCntkNKYNIkg4233/dZ3BU=
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230424095137-b73c17cb9cc8/go.mod h1:JicgV9n3SAu5uuoyDvQ2gSHYLyFvyRrIUYB5T2Q4HRw=
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230426154441-2037a26d1235 h1:EQM4Ewp62TpQ141W0IJL84qJ8zyvGeqA75r++81JKGc=
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230426154441-2037a26d1235/go.mod h1:1pnJEQxrWXGGijISBNKkisAuMlohZROsazmj+JYkBc0=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=

View File

@ -15,6 +15,7 @@ type Config struct {
type ChainConfig struct {
GRPCEndpoints []GRPCEndpoint `toml:"trusted-grpc-endpoints"`
Bech32Prefix string `toml:"bech32-prefix"`
}
type GRPCEndpoint struct {

View File

@ -7,8 +7,6 @@ import (
"os"
"path"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
"github.com/cockroachdb/errors"
"github.com/hashicorp/go-multierror"
"google.golang.org/grpc"
@ -18,6 +16,10 @@ import (
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
)
const DefaultConfigDirName = ".hubl"
@ -25,20 +27,21 @@ const DefaultConfigDirName = ".hubl"
type ChainInfo struct {
client *grpc.ClientConn
ConfigDir string
Chain string
ModuleOptions map[string]*autocliv1.ModuleOptions
Context context.Context
ConfigDir string
Chain string
Config *ChainConfig
ProtoFiles *protoregistry.Files
Context context.Context
Config *ChainConfig
ModuleOptions map[string]*autocliv1.ModuleOptions
}
func NewChainInfo(configDir, chain string, config *ChainConfig) *ChainInfo {
return &ChainInfo{
ConfigDir: configDir,
Chain: chain,
Config: config,
Context: context.Background(),
Config: config,
Chain: chain,
ConfigDir: configDir,
}
}
@ -123,22 +126,21 @@ func (c *ChainInfo) Load(reload bool) error {
}
autocliQueryClient := autocliv1.NewQueryClient(client)
appOptionsRes, err := autocliQueryClient.AppOptions(c.Context, &autocliv1.AppOptionsRequest{})
appOptsRes, err := autocliQueryClient.AppOptions(c.Context, &autocliv1.AppOptionsRequest{})
if err != nil {
appOptionsRes = guessAutocli(c.ProtoFiles)
appOptsRes = guessAutocli(c.ProtoFiles)
}
bz, err := proto.Marshal(appOptionsRes)
bz, err := proto.Marshal(appOptsRes)
if err != nil {
return err
}
err = os.WriteFile(appOptsFilename, bz, 0o600)
if err != nil {
if err := os.WriteFile(appOptsFilename, bz, 0o600); err != nil {
return err
}
c.ModuleOptions = appOptionsRes.ModuleOptions
c.ModuleOptions = appOptsRes.ModuleOptions
} else {
bz, err := os.ReadFile(appOptsFilename)
if err != nil {
@ -146,8 +148,7 @@ func (c *ChainInfo) Load(reload bool) error {
}
var appOptsRes autocliv1.AppOptionsResponse
err = proto.Unmarshal(bz, &appOptsRes)
if err != nil {
if err := proto.Unmarshal(bz, &appOptsRes); err != nil {
return err
}
@ -185,3 +186,18 @@ func (c *ChainInfo) OpenClient() (*grpc.ClientConn, error) {
return nil, errors.Wrapf(res, "error loading gRPC client")
}
// getAddressPrefix returns the address prefix of the chain.
func getAddressPrefix(ctx context.Context, conn grpc.ClientConnInterface) (string, error) {
reflectionClient := reflectionv2alpha1.NewReflectionServiceClient(conn)
resp, err := reflectionClient.GetConfigurationDescriptor(ctx, &reflectionv2alpha1.GetConfigurationDescriptorRequest{})
if err != nil {
return "", err
}
if resp == nil || resp.Config == nil || resp.Config.Bech32AccountAddressPrefix == "" {
return "", errors.New("bech32 account address prefix is not set")
}
return resp.Config.Bech32AccountAddressPrefix, nil
}

View File

@ -1,6 +1,7 @@
package internal
import (
"context"
"fmt"
"os"
"path"
@ -12,6 +13,8 @@ import (
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/dynamicpb"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"cosmossdk.io/client/v2/autocli"
"cosmossdk.io/client/v2/autocli/flag"
)
@ -91,22 +94,22 @@ func RemoteCommand(config *Config, configDir string) ([]*cobra.Command, error) {
builder := &autocli.Builder{
Builder: flag.Builder{
AddressCodec: addresscodec.NewBech32Codec(chainConfig.Bech32Prefix),
TypeResolver: &dynamicTypeResolver{chainInfo},
FileResolver: chainInfo.ProtoFiles,
GetClientConn: func() (grpc.ClientConnInterface, error) {
return chainInfo.OpenClient()
},
},
GetClientConn: func(command *cobra.Command) (grpc.ClientConnInterface, error) {
return chainInfo.OpenClient()
},
AddQueryConnFlags: func(command *cobra.Command) {},
}
var (
update bool
reconfig bool
insecure bool
)
chainCmd := &cobra.Command{
Use: chain,
Short: fmt.Sprintf("Commands for the %s chain", chain),
@ -177,7 +180,19 @@ func reconfigure(cmd *cobra.Command, config *Config, configDir, chain string) er
return err
}
client, err := chainInfo.OpenClient()
if err != nil {
return err
}
addressPrefix, err := getAddressPrefix(context.Background(), client)
if err != nil {
return err
}
chainConfig.Bech32Prefix = addressPrefix
config.Chains[chain] = chainConfig
if err := SaveConfig(configDir, config); err != nil {
return err
}

View File

@ -34,7 +34,7 @@ func (bc bech32Codec) StringToBytes(text string) ([]byte, error) {
}
if hrp != bc.bech32Prefix {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "hrp does not match bech32Prefix")
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "hrp does not match bech32 prefix: expected '%s' got '%s'", bc.bech32Prefix, hrp)
}
if err := sdk.VerifyAddressFormat(bz); err != nil {