cosmos-sdk/tools/hubl/internal/load.go
dependabot[bot] 533ee7a552
build(deps): Bump github.com/cometbft/cometbft from 0.38.0-alpha.1 to 0.38.0-alpha.2 (#16280)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Julien Robert <julien@rbrt.fr>
2023-05-24 23:36:25 +00:00

204 lines
4.8 KiB
Go

package internal
import (
"context"
"crypto/tls"
"errors"
"fmt"
"os"
"path"
cockroachdberrors "github.com/cockroachdb/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/proto"
"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"
type ChainInfo struct {
client *grpc.ClientConn
Context context.Context
ConfigDir string
Chain string
Config *ChainConfig
ProtoFiles *protoregistry.Files
ModuleOptions map[string]*autocliv1.ModuleOptions
}
func NewChainInfo(configDir, chain string, config *ChainConfig) *ChainInfo {
return &ChainInfo{
Context: context.Background(),
Config: config,
Chain: chain,
ConfigDir: configDir,
}
}
func (c *ChainInfo) getCacheDir() (string, error) {
cacheDir := path.Join(c.ConfigDir, "cache")
return cacheDir, os.MkdirAll(cacheDir, 0o755)
}
func (c *ChainInfo) fdsCacheFilename() (string, error) {
cacheDir, err := c.getCacheDir()
if err != nil {
return "", err
}
return path.Join(cacheDir, fmt.Sprintf("%s.fds", c.Chain)), nil
}
func (c *ChainInfo) appOptsCacheFilename() (string, error) {
cacheDir, err := c.getCacheDir()
if err != nil {
return "", err
}
return path.Join(cacheDir, fmt.Sprintf("%s.autocli", c.Chain)), nil
}
func (c *ChainInfo) Load(reload bool) error {
fdSet := &descriptorpb.FileDescriptorSet{}
fdsFilename, err := c.fdsCacheFilename()
if err != nil {
return err
}
if _, err := os.Stat(fdsFilename); os.IsNotExist(err) || reload {
client, err := c.OpenClient()
if err != nil {
return err
}
reflectionClient := reflectionv1.NewReflectionServiceClient(client)
fdRes, err := reflectionClient.FileDescriptors(c.Context, &reflectionv1.FileDescriptorsRequest{})
if err != nil {
fdSet, err = loadFileDescriptorsGRPCReflection(c.Context, client)
if err != nil {
return err
}
} else {
fdSet = &descriptorpb.FileDescriptorSet{File: fdRes.Files}
}
bz, err := proto.Marshal(fdSet)
if err != nil {
return err
}
if err = os.WriteFile(fdsFilename, bz, 0o600); err != nil {
return err
}
} else {
bz, err := os.ReadFile(fdsFilename)
if err != nil {
return err
}
if err = proto.Unmarshal(bz, fdSet); err != nil {
return err
}
}
c.ProtoFiles, err = protodesc.FileOptions{AllowUnresolvable: true}.NewFiles(fdSet)
if err != nil {
return fmt.Errorf("error building protoregistry.Files: %w", err)
}
appOptsFilename, err := c.appOptsCacheFilename()
if err != nil {
return err
}
if _, err := os.Stat(appOptsFilename); os.IsNotExist(err) || reload {
client, err := c.OpenClient()
if err != nil {
return err
}
autocliQueryClient := autocliv1.NewQueryClient(client)
appOptsRes, err := autocliQueryClient.AppOptions(c.Context, &autocliv1.AppOptionsRequest{})
if err != nil {
appOptsRes = guessAutocli(c.ProtoFiles)
}
bz, err := proto.Marshal(appOptsRes)
if err != nil {
return err
}
if err := os.WriteFile(appOptsFilename, bz, 0o600); err != nil {
return err
}
c.ModuleOptions = appOptsRes.ModuleOptions
} else {
bz, err := os.ReadFile(appOptsFilename)
if err != nil {
return err
}
var appOptsRes autocliv1.AppOptionsResponse
if err := proto.Unmarshal(bz, &appOptsRes); err != nil {
return err
}
c.ModuleOptions = appOptsRes.ModuleOptions
}
return nil
}
func (c *ChainInfo) OpenClient() (*grpc.ClientConn, error) {
if c.client != nil {
return c.client, nil
}
var res error
for _, endpoint := range c.Config.GRPCEndpoints {
var creds credentials.TransportCredentials
if endpoint.Insecure {
creds = insecure.NewCredentials()
} else {
creds = credentials.NewTLS(&tls.Config{
MinVersion: tls.VersionTLS12,
})
}
var err error
c.client, err = grpc.Dial(endpoint.Endpoint, grpc.WithTransportCredentials(creds))
if err != nil {
res = errors.Join(res, err)
continue
}
return c.client, nil
}
return nil, cockroachdberrors.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 "", cockroachdberrors.New("bech32 account address prefix is not set")
}
return resp.Config.Bech32AccountAddressPrefix, nil
}