Merge PR #2040: Refactor Validator Account Types/Bech32 Prefixing

* Add new account bech32 prefixes with godocs

* Restructure spacing of existing account code

* Update account godocs

* More account godoc updates + new tm pub/addr helpers

* Update validator type to use new account types/bech32 prefixes

* Fix account documentation errors

* Update Bech32 prefix for consensus nodes

* Update Bech32 spec doc

* Fix account type tests

* Add missing account consensus functions, clear up godocs, and fix tests

* Add to TestRandBech32PubkeyConsistency check

* Update initialization of validator public keys

* Update query signing info command

* Implement new ConsAddress type with associated unit tests

* [WIP] Update stake and slashing parameters

* Update all calls to MustBech32ifyValPub

* [WIP] Validator operator API updates

* [WIP] Fix and update unit tests

* Fix gov logs (helping to debug failing tests)

* Fix gov tally

* Fix all broken x/ unit tests

* Update gaia app genesis address logic

* Fix linting errors

* Fix broken LCD tests

* Fix broken CLI tests

* Implement command to get validator address and pubkey from key name

* Add support for getting validator key information via REST endpoint

* Update PENDING log

* Update docs

* Revert GaiaGenTx.PubKey bech32 prefix

* Fix broken docs and cli tests

* Update genesis to use correct Bech32 (cons) prefix for pubkeys

* Update docs and unit tests to reflect new cosmos account bech32 prefix

* minor formatting
This commit is contained in:
Alexander Bezobchuk
2018-08-31 00:06:44 -04:00
committed by Rigel
parent dc0f13214d
commit 2d92803b9f
66 changed files with 1315 additions and 835 deletions
+2 -1
View File
@@ -128,7 +128,8 @@ func printCreate(info keys.Info, seed string) {
output := viper.Get(cli.OutputFlag)
switch output {
case "text":
printInfo(info)
printKeyInfo(info, Bech32KeyOutput)
// print seed unless requested not to.
if !viper.GetBool(client.FlagUseLedger) && !viper.GetBool(flagNoBackup) {
fmt.Println("**Important** write this seed phrase in a safe place.")
+1 -1
View File
@@ -21,7 +21,7 @@ func Commands() *cobra.Command {
cmd.AddCommand(
addKeyCommand(),
listKeysCmd,
showKeysCmd,
showKeysCmd(),
client.LineBreak,
deleteKeyCommand(),
updateKeyCommand(),
+74 -36
View File
@@ -2,6 +2,7 @@ package keys
import (
"encoding/json"
"fmt"
"net/http"
"github.com/cosmos/cosmos-sdk/crypto/keys"
@@ -18,46 +19,69 @@ const (
FlagAddress = "address"
// FlagPublicKey represents the user's public key on the command line.
FlagPublicKey = "pubkey"
// FlagBechPrefix defines a desired Bech32 prefix encoding for a key
FlagBechPrefix = "bech"
)
var showKeysCmd = &cobra.Command{
Use: "show <name>",
Short: "Show key info for the given name",
Long: `Return public details of one local key.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
info, err := getKey(name)
if err != nil {
return err
}
func showKeysCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "show [name]",
Short: "Show key info for the given name",
Long: `Return public details of one local key.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
info, err := getKey(name)
if err != nil {
return err
}
showAddress := viper.GetBool(FlagAddress)
showPublicKey := viper.GetBool(FlagPublicKey)
outputSet := cmd.Flag(cli.OutputFlag).Changed
if showAddress && showPublicKey {
return errors.New("cannot use both --address and --pubkey at once")
}
if outputSet && (showAddress || showPublicKey) {
return errors.New("cannot use --output with --address or --pubkey")
}
if showAddress {
printKeyAddress(info)
return nil
}
if showPublicKey {
printPubKey(info)
return nil
}
showAddress := viper.GetBool(FlagAddress)
showPublicKey := viper.GetBool(FlagPublicKey)
outputSet := cmd.Flag(cli.OutputFlag).Changed
printInfo(info)
return nil
},
if showAddress && showPublicKey {
return errors.New("cannot use both --address and --pubkey at once")
}
if outputSet && (showAddress || showPublicKey) {
return errors.New("cannot use --output with --address or --pubkey")
}
bechKeyOut, err := getBechKeyOut(viper.GetString(FlagBechPrefix))
if err != nil {
return err
}
switch {
case showAddress:
printKeyAddress(info, bechKeyOut)
case showPublicKey:
printPubKey(info, bechKeyOut)
default:
printKeyInfo(info, bechKeyOut)
}
return nil
},
}
cmd.Flags().String(FlagBechPrefix, "acc", "The Bech32 prefix encoding for a key (acc|val|cons)")
cmd.Flags().Bool(FlagAddress, false, "output the address only (overrides --output)")
cmd.Flags().Bool(FlagPublicKey, false, "output the public key only (overrides --output)")
return cmd
}
func init() {
showKeysCmd.Flags().Bool(FlagAddress, false, "output the address only (overrides --output)")
showKeysCmd.Flags().Bool(FlagPublicKey, false, "output the public key only (overrides --output)")
func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
switch bechPrefix {
case "acc":
return Bech32KeyOutput, nil
case "val":
return Bech32ValKeyOutput, nil
case "cons":
return Bech32ConsKeyOutput, nil
}
return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix)
}
func getKey(name string) (keys.Info, error) {
@@ -76,21 +100,35 @@ func getKey(name string) (keys.Info, error) {
func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]
bechPrefix := r.URL.Query().Get(FlagBechPrefix)
if bechPrefix == "" {
bechPrefix = "acc"
}
bechKeyOut, err := getBechKeyOut(bechPrefix)
if err != nil {
w.WriteHeader(400)
w.Write([]byte(err.Error()))
return
}
info, err := getKey(name)
// TODO check for the error if key actually does not exist, instead of assuming this as the reason
// TODO: check for the error if key actually does not exist, instead of
// assuming this as the reason
if err != nil {
w.WriteHeader(404)
w.Write([]byte(err.Error()))
return
}
keyOutput, err := Bech32KeyOutput(info)
keyOutput, err := bechKeyOut(info)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := json.MarshalIndent(keyOutput, "", " ")
if err != nil {
w.WriteHeader(500)
+56 -14
View File
@@ -21,6 +21,8 @@ const KeyDBName = "keys"
// keybase is used to make GetKeyBase a singleton
var keybase keys.Keybase
type bechKeyOutFn func(keyInfo keys.Info) (KeyOutput, error)
// TODO make keybase take a database not load from the directory
// initialize a keybase based on the configuration
@@ -97,11 +99,11 @@ func SetKeyBase(kb keys.Keybase) {
// used for outputting keys.Info over REST
type KeyOutput struct {
Name string `json:"name"`
Type string `json:"type"`
Address sdk.AccAddress `json:"address"`
PubKey string `json:"pub_key"`
Seed string `json:"seed,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
Address string `json:"address"`
PubKey string `json:"pub_key"`
Seed string `json:"seed,omitempty"`
}
// create a list of KeyOutput in bech32 format
@@ -119,24 +121,61 @@ func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) {
// create a KeyOutput in bech32 format
func Bech32KeyOutput(info keys.Info) (KeyOutput, error) {
account := sdk.AccAddress(info.GetPubKey().Address().Bytes())
accAddr := sdk.AccAddress(info.GetPubKey().Address().Bytes())
bechPubKey, err := sdk.Bech32ifyAccPub(info.GetPubKey())
if err != nil {
return KeyOutput{}, err
}
return KeyOutput{
Name: info.GetName(),
Type: info.GetType().String(),
Address: account,
Address: accAddr.String(),
PubKey: bechPubKey,
}, nil
}
func printInfo(info keys.Info) {
ko, err := Bech32KeyOutput(info)
// Bech32ConsKeyOutput returns key output for a consensus node's key
// information.
func Bech32ConsKeyOutput(keyInfo keys.Info) (KeyOutput, error) {
consAddr := sdk.ConsAddress(keyInfo.GetPubKey().Address().Bytes())
bechPubKey, err := sdk.Bech32ifyConsPub(keyInfo.GetPubKey())
if err != nil {
return KeyOutput{}, err
}
return KeyOutput{
Name: keyInfo.GetName(),
Type: keyInfo.GetType().String(),
Address: consAddr.String(),
PubKey: bechPubKey,
}, nil
}
// Bech32ValKeyOutput returns key output for a validator's key information.
func Bech32ValKeyOutput(keyInfo keys.Info) (KeyOutput, error) {
valAddr := sdk.ValAddress(keyInfo.GetPubKey().Address().Bytes())
bechPubKey, err := sdk.Bech32ifyValPub(keyInfo.GetPubKey())
if err != nil {
return KeyOutput{}, err
}
return KeyOutput{
Name: keyInfo.GetName(),
Type: keyInfo.GetType().String(),
Address: valAddr.String(),
PubKey: bechPubKey,
}, nil
}
func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(keyInfo)
if err != nil {
panic(err)
}
switch viper.Get(cli.OutputFlag) {
case "text":
fmt.Printf("NAME:\tTYPE:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
@@ -146,6 +185,7 @@ func printInfo(info keys.Info) {
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
}
@@ -174,18 +214,20 @@ func printKeyOutput(ko KeyOutput) {
fmt.Printf("%s\t%s\t%s\t%s\n", ko.Name, ko.Type, ko.Address, ko.PubKey)
}
func printKeyAddress(info keys.Info) {
ko, err := Bech32KeyOutput(info)
func printKeyAddress(info keys.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(info)
if err != nil {
panic(err)
}
fmt.Println(ko.Address.String())
fmt.Println(ko.Address)
}
func printPubKey(info keys.Info) {
ko, err := Bech32KeyOutput(info)
func printPubKey(info keys.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(info)
if err != nil {
panic(err)
}
fmt.Println(ko.PubKey)
}
+33 -31
View File
@@ -62,7 +62,7 @@ func TestKeys(t *testing.T) {
err = wire.Cdc.UnmarshalJSON([]byte(body), &resp)
require.Nil(t, err, body)
addr2Bech32 := resp.Address.String()
addr2Bech32 := resp.Address
_, err = sdk.AccAddressFromBech32(addr2Bech32)
require.NoError(t, err, "Failed to return a correct bech32 address")
@@ -81,9 +81,9 @@ func TestKeys(t *testing.T) {
addrBech32 := addr.String()
require.Equal(t, name, m[0].Name, "Did not serve keys name correctly")
require.Equal(t, addrBech32, m[0].Address.String(), "Did not serve keys Address correctly")
require.Equal(t, addrBech32, m[0].Address, "Did not serve keys Address correctly")
require.Equal(t, newName, m[1].Name, "Did not serve keys name correctly")
require.Equal(t, addr2Bech32, m[1].Address.String(), "Did not serve keys Address correctly")
require.Equal(t, addr2Bech32, m[1].Address, "Did not serve keys Address correctly")
// select key
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
@@ -94,7 +94,7 @@ func TestKeys(t *testing.T) {
require.Nil(t, err)
require.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
require.Equal(t, addr2Bech32, m2.Address.String(), "Did not serve keys Address correctly")
require.Equal(t, addr2Bech32, m2.Address, "Did not serve keys Address correctly")
// update key
jsonStr = []byte(fmt.Sprintf(`{
@@ -204,8 +204,8 @@ func TestValidators(t *testing.T) {
require.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosvaladdr")
require.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub")
require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosval")
require.Contains(t, resultVals.Validators[0].PubKey, "cosmosconspub")
// --
@@ -313,7 +313,7 @@ func TestTxs(t *testing.T) {
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
// query empty
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3"), nil)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmos1jawd35d9aq4u76sr3fjalmcqc8hqygs90d0g0v"), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.Equal(t, "[]", body)
@@ -407,7 +407,7 @@ func TestValidatorsQuery(t *testing.T) {
// make sure all the validators were found (order unknown because sorted by operator addr)
foundVal := false
pkBech := sdk.MustBech32ifyValPub(pks[0])
pkBech := sdk.MustBech32ifyConsPub(pks[0])
if validators[0].PubKey == pkBech {
foundVal = true
}
@@ -419,7 +419,7 @@ func TestValidatorQuery(t *testing.T) {
defer cleanup()
require.Equal(t, 1, len(pks))
validator1Operator := sdk.AccAddress(pks[0].Address())
validator1Operator := sdk.ValAddress(pks[0].Address())
validator := getValidator(t, port, validator1Operator)
assert.Equal(t, validator.Operator, validator1Operator, "The returned validator does not hold the correct data")
}
@@ -430,7 +430,7 @@ func TestBonding(t *testing.T) {
cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
validator1Operator := sdk.AccAddress(pks[0].Address())
validator1Operator := sdk.ValAddress(pks[0].Address())
validator := getValidator(t, port, validator1Operator)
// create bond TX
@@ -611,7 +611,7 @@ func TestUnjail(t *testing.T) {
// XXX: any less than this and it fails
tests.WaitForHeight(3, port)
pkString, _ := sdk.Bech32ifyValPub(pks[0])
pkString, _ := sdk.Bech32ifyConsPub(pks[0])
signingInfo := getSigningInfo(t, port, pkString)
tests.WaitForHeight(4, port)
require.Equal(t, true, signingInfo.IndexOffset > 0)
@@ -817,8 +817,8 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.
// ============= Stake Module ================
func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) rest.DelegationWithoutRat {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil)
func getDelegation(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) rest.DelegationWithoutRat {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bond rest.DelegationWithoutRat
@@ -829,8 +829,8 @@ func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.A
return bond
}
func getUndelegations(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) []stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil)
func getUndelegations(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) []stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var unbondings []stake.UnbondingDelegation
@@ -884,8 +884,8 @@ func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddr
return bondedValidators
}
func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) stake.BechValidator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delegatorAddr, validatorAddr), nil)
func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.BechValidator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bondedValidator stake.BechValidator
@@ -895,8 +895,10 @@ func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddre
return bondedValidator
}
func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delegatorAddr)
func doDelegate(t *testing.T, port, seed, name, password string,
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
@@ -918,9 +920,9 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr,
"complete_unbondings": [],
"begin_redelegates": [],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, "steak", amount))
}`, name, password, accnum, sequence, chainID, delAddr, valAddr, "steak", amount))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@@ -931,9 +933,9 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr,
}
func doBeginUnbonding(t *testing.T, port, seed, name, password string,
delegatorAddr, validatorAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delegatorAddr)
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
@@ -955,9 +957,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
"complete_unbondings": [],
"begin_redelegates": [],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, amount))
}`, name, password, accnum, sequence, chainID, delAddr, valAddr, amount))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@@ -968,9 +970,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
}
func doBeginRedelegation(t *testing.T, port, seed, name, password string,
delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) {
delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delegatorAddr)
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
@@ -994,9 +996,9 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
}
],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delegatorAddr, validatorSrcAddr, validatorDstAddr))
}`, name, password, accnum, sequence, chainID, delAddr, valSrcAddr, valDstAddr))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@@ -1015,8 +1017,8 @@ func getValidators(t *testing.T, port string) []stake.BechValidator {
return validators
}
func getValidator(t *testing.T, port string, validatorAddr sdk.AccAddress) stake.BechValidator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", validatorAddr.String()), nil)
func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.BechValidator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", valAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var validator stake.BechValidator
err := cdc.UnmarshalJSON([]byte(body), &validator)
+1 -1
View File
@@ -45,7 +45,7 @@ type ResultValidatorsOutput struct {
}
func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) {
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
bechValPubkey, err := sdk.Bech32ifyConsPub(validator.PubKey)
if err != nil {
return ValidatorOutput{}, err
}