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:
Adam Bozanich
2020-05-08 10:30:55 +02:00
committed by GitHub
parent c8c47786da
commit 4e328d75db
4 changed files with 69 additions and 28 deletions
+37 -10
View File
@@ -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
}
+8 -5
View File
@@ -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") })
}