client/keys/parse: honor config changes (#6172)
`keys parse` uses the global configuration before before client applications have had a chance to apply their settings. This change adds a `GetSealedConfig()` helper that waits for the config to be sealed before returning it. fixes #5091 addresses #5283
This commit is contained in:
parent
c8c47786da
commit
4e328d75db
@ -1,6 +1,7 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -18,14 +19,15 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var config = sdk.GetConfig()
|
||||
var bech32Prefixes = []string{
|
||||
config.GetBech32AccountAddrPrefix(),
|
||||
config.GetBech32AccountPubPrefix(),
|
||||
config.GetBech32ValidatorAddrPrefix(),
|
||||
config.GetBech32ValidatorPubPrefix(),
|
||||
config.GetBech32ConsensusAddrPrefix(),
|
||||
config.GetBech32ConsensusPubPrefix(),
|
||||
func bech32Prefixes(config *sdk.Config) []string {
|
||||
return []string{
|
||||
config.GetBech32AccountAddrPrefix(),
|
||||
config.GetBech32AccountPubPrefix(),
|
||||
config.GetBech32ValidatorAddrPrefix(),
|
||||
config.GetBech32ValidatorPubPrefix(),
|
||||
config.GetBech32ConsensusAddrPrefix(),
|
||||
config.GetBech32ConsensusPubPrefix(),
|
||||
}
|
||||
}
|
||||
|
||||
type hexOutput struct {
|
||||
@ -45,7 +47,8 @@ type bech32Output struct {
|
||||
Formats []string `json:"formats"`
|
||||
}
|
||||
|
||||
func newBech32Output(bs []byte) bech32Output {
|
||||
func newBech32Output(config *sdk.Config, bs []byte) bech32Output {
|
||||
bech32Prefixes := bech32Prefixes(config)
|
||||
out := bech32Output{Formats: make([]string, len(bech32Prefixes))}
|
||||
|
||||
for i, prefix := range bech32Prefixes {
|
||||
@ -87,6 +90,11 @@ hexadecimal into bech32 cosmos prefixed format and vice versa.
|
||||
}
|
||||
|
||||
func parseKey(cmd *cobra.Command, args []string) error {
|
||||
config, _ := sdk.GetSealedConfig(context.Background())
|
||||
return doParseKey(cmd, config, args)
|
||||
}
|
||||
|
||||
func doParseKey(cmd *cobra.Command, config *sdk.Config, args []string) error {
|
||||
addr := strings.TrimSpace(args[0])
|
||||
outstream := cmd.OutOrStdout()
|
||||
|
||||
@ -94,7 +102,7 @@ func parseKey(cmd *cobra.Command, args []string) error {
|
||||
return errors.New("couldn't parse empty input")
|
||||
}
|
||||
|
||||
if !(runFromBech32(outstream, addr) || runFromHex(outstream, addr)) {
|
||||
if !(runFromBech32(outstream, addr) || runFromHex(config, outstream, addr)) {
|
||||
return errors.New("couldn't find valid bech32 nor hex data")
|
||||
}
|
||||
|
||||
@ -114,13 +122,13 @@ func runFromBech32(w io.Writer, bech32str string) bool {
|
||||
}
|
||||
|
||||
// print info from hex
|
||||
func runFromHex(w io.Writer, hexstr string) bool {
|
||||
func runFromHex(config *sdk.Config, w io.Writer, hexstr string) bool {
|
||||
bz, err := hex.DecodeString(hexstr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
displayParseKeyInfo(w, newBech32Output(bz))
|
||||
displayParseKeyInfo(w, newBech32Output(config, bz))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package keys
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@ -10,6 +11,8 @@ func TestParseKey(t *testing.T) {
|
||||
bech32str := "cosmos104ytdpvrx9284zd50v9ep8c6j7pua7dkk0x3ek"
|
||||
hexstr := "EB5AE9872103497EC092EF901027049E4F39200C60040D3562CD7F104A39F62E6E5A39A818F4"
|
||||
|
||||
config := sdk.NewConfig()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
@ -23,7 +26,7 @@ func TestParseKey(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.wantErr, parseKey(ParseKeyStringCommand(), tt.args) != nil)
|
||||
require.Equal(t, tt.wantErr, doParseKey(ParseKeyStringCommand(), config, tt.args) != nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
@ -19,19 +20,19 @@ type Config struct {
|
||||
mtx sync.RWMutex
|
||||
coinType uint32
|
||||
sealed bool
|
||||
sealedch chan struct{}
|
||||
}
|
||||
|
||||
// cosmos-sdk wide global singleton
|
||||
var sdkConfig *Config
|
||||
var (
|
||||
sdkConfig *Config
|
||||
initConfig sync.Once
|
||||
)
|
||||
|
||||
// GetConfig returns the config instance for the SDK.
|
||||
func GetConfig() *Config {
|
||||
if sdkConfig != nil {
|
||||
return sdkConfig
|
||||
}
|
||||
|
||||
sdkConfig = &Config{
|
||||
sealed: false,
|
||||
// New returns a new Config with default values.
|
||||
func NewConfig() *Config {
|
||||
return &Config{
|
||||
sealedch: make(chan struct{}),
|
||||
bech32AddressPrefix: map[string]string{
|
||||
"account_addr": Bech32PrefixAccAddr,
|
||||
"validator_addr": Bech32PrefixValAddr,
|
||||
@ -44,9 +45,27 @@ func GetConfig() *Config {
|
||||
fullFundraiserPath: FullFundraiserPath,
|
||||
txEncoder: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// GetConfig returns the config instance for the SDK.
|
||||
func GetConfig() *Config {
|
||||
initConfig.Do(func() {
|
||||
sdkConfig = NewConfig()
|
||||
})
|
||||
return sdkConfig
|
||||
}
|
||||
|
||||
// GetSealedConfig returns the config instance for the SDK if/once it is sealed.
|
||||
func GetSealedConfig(ctx context.Context) (*Config, error) {
|
||||
config := GetConfig()
|
||||
select {
|
||||
case <-config.sealedch:
|
||||
return config, nil
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (config *Config) assertNotSealed() {
|
||||
config.mtx.Lock()
|
||||
defer config.mtx.Unlock()
|
||||
@ -108,9 +127,17 @@ func (config *Config) SetFullFundraiserPath(fullFundraiserPath string) {
|
||||
// Seal seals the config such that the config state could not be modified further
|
||||
func (config *Config) Seal() *Config {
|
||||
config.mtx.Lock()
|
||||
defer config.mtx.Unlock()
|
||||
|
||||
if config.sealed {
|
||||
config.mtx.Unlock()
|
||||
return config
|
||||
}
|
||||
|
||||
// signal sealed after state exposed/unlocked
|
||||
config.sealed = true
|
||||
config.mtx.Unlock()
|
||||
close(config.sealedch)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
|
||||
@ -10,8 +10,9 @@ import (
|
||||
)
|
||||
|
||||
func TestConfig_SetCoinType(t *testing.T) {
|
||||
config := &sdk.Config{}
|
||||
require.Equal(t, uint32(0), config.GetCoinType())
|
||||
config := sdk.NewConfig()
|
||||
config.SetCoinType(1)
|
||||
require.Equal(t, uint32(1), config.GetCoinType())
|
||||
config.SetCoinType(99)
|
||||
require.Equal(t, uint32(99), config.GetCoinType())
|
||||
|
||||
@ -21,7 +22,7 @@ func TestConfig_SetCoinType(t *testing.T) {
|
||||
|
||||
func TestConfig_SetTxEncoder(t *testing.T) {
|
||||
mockErr := errors.New("test")
|
||||
config := &sdk.Config{}
|
||||
config := sdk.NewConfig()
|
||||
require.Nil(t, config.GetTxEncoder())
|
||||
encFunc := sdk.TxEncoder(func(tx sdk.Tx) ([]byte, error) { return nil, nil })
|
||||
config.SetTxEncoder(encFunc)
|
||||
@ -33,11 +34,13 @@ func TestConfig_SetTxEncoder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfig_SetFullFundraiserPath(t *testing.T) {
|
||||
config := &sdk.Config{}
|
||||
require.Equal(t, "", config.GetFullFundraiserPath())
|
||||
config := sdk.NewConfig()
|
||||
config.SetFullFundraiserPath("test/path")
|
||||
require.Equal(t, "test/path", config.GetFullFundraiserPath())
|
||||
|
||||
config.SetFullFundraiserPath("test/poth")
|
||||
require.Equal(t, "test/poth", config.GetFullFundraiserPath())
|
||||
|
||||
config.Seal()
|
||||
require.Panics(t, func() { config.SetFullFundraiserPath("x/test/path") })
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user