From 04c2071824bcb9c78b1d306d23f8ee70aed2f38e Mon Sep 17 00:00:00 2001 From: Sherry Ma Date: Fri, 22 Jun 2018 17:48:52 +0800 Subject: [PATCH 01/53] Change the value of tag --address-validator When doing gaiacli stake delegate/unbond/delegation, --address-validator should get the address of the validator, not the validator pubkey. --- cmd/gaia/testnets/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/gaia/testnets/README.md b/cmd/gaia/testnets/README.md index 5b6df83ad3..8cce4822cb 100644 --- a/cmd/gaia/testnets/README.md +++ b/cmd/gaia/testnets/README.md @@ -320,7 +320,7 @@ On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond t gaiacli stake delegate \ --amount=10steak \ --address-delegator= \ - --address-validator=$(gaiad tendermint show_validator) \ + --address-validator= \ --name= \ --chain-id=gaia-6002 ``` @@ -336,7 +336,7 @@ If for any reason the validator misbehaves, or you want to unbond a certain amou ```bash gaiacli stake unbond \ --address-delegator= \ - --address-validator=$(gaiad tendermint show_validator) \ + --address-validator= \ --shares=MAX \ --name= \ --chain-id=gaia-6002 @@ -349,7 +349,7 @@ gaiacli account gaiacli stake delegation \ --address-delegator= \ - --address-validator=$(gaiad tendermint show_validator) \ + --address-validator= \ --chain-id=gaia-6002 ``` From 1a67dc5d7cdc9d02a29038b96e4c7c7e3fcf34d1 Mon Sep 17 00:00:00 2001 From: Sherry Ma Date: Fri, 22 Jun 2018 18:37:15 +0800 Subject: [PATCH 02/53] Changed decode delegator address function In delegation query, the function to decode the address of delegator should be using Bech32 but not Hex --- x/stake/client/cli/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 727cddcde2..9ec1edc254 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -117,7 +117,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { return err } - delAddr, err := sdk.GetValAddressHex(viper.GetString(FlagAddressDelegator)) + delAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator)) if err != nil { return err } From 94a3ce4c83afeaa5e3fcc069e889ffcf67b4f321 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 10:45:11 -0700 Subject: [PATCH 03/53] docs: Explain the expected return type within the store (#1452) --- x/stake/keeper/key.go | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 667f5f681e..3be009e220 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -35,30 +35,35 @@ var ( const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch -// get the key for the validator with address +// get the key for the validator with address. +// the value at this key is of type stake/types.Validator func GetValidatorKey(ownerAddr sdk.Address) []byte { return append(ValidatorsKey, ownerAddr.Bytes()...) } -// get the key for the validator with pubkey +// get the key for the validator with pubkey. +// the value at this key should the address for a stake/types.Validator func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...) } -// get the key for the current validator group, ordered like tendermint +// get the key for the current validator group, ordered like tendermint. +// the value at this key is the address of the owner of a validator func GetValidatorsBondedIndexKey(ownerAddr sdk.Address) []byte { return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...) } -// get the power which is the key for the validator used in the power-store +// get the validator by power index. power index is the key used in the power-store, +// and represents the relative power ranking of the validator. +// the value at this key is of type address, the address being the Address +// of the corresponding validator. func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { - // NOTE the address doesn't need to be stored because counter bytes must always be different - return GetValidatorPowerRank(validator, pool) + return getValidatorPowerRank(validator, pool) } -// get the power of a validator -func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { +// get the power ranking of a validator +func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { power := validator.EquivalentBondedShares(pool) powerBytes := []byte(power.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) @@ -71,7 +76,7 @@ func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { revokedBytes[0] = byte(0x00) } - // TODO ensure that the key will be a readable string.. probably should add seperators and have + // TODO ensure that the key will be a readable string.. probably should add separators and have // heightBytes and counterBytes represent strings like powerBytes does heightBytes := make([]byte, binary.MaxVarintLen64) binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first) @@ -84,14 +89,16 @@ func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { append(heightBytes, counterBytes...)...)...)...) } -// get the key for the accumulated update validators +// get the key for the accumulated update validators. +// The value at this key is of type stake/types.Validator func GetTendermintUpdatesKey(ownerAddr sdk.Address) []byte { return append(TendermintUpdatesKey, ownerAddr.Bytes()...) } //________________________________________________________________________________ -// get the key for delegator bond with validator +// get the key for delegator bond with validator. +// The value at this key is of type stake/types.Delegation func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { return append(GetDelegationsKey(delegatorAddr, cdc), validatorAddr.Bytes()...) } @@ -104,12 +111,14 @@ func GetDelegationsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { //________________________________________________________________________________ -// get the key for an unbonding delegation +// get the key for an unbonding delegation by delegator and validator addr. +// The value at this key is of type stake/types.UnbondingDelegation func GetUBDKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { return append(GetUBDsKey(delegatorAddr, cdc), validatorAddr.Bytes()...) } // get the index-key for an unbonding delegation, stored by validator-index +// The value at this key is a key for the corresponding unbonding delegation. func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { return append(GetUBDsByValIndexKey(validatorAddr, cdc), delegatorAddr.Bytes()...) } @@ -122,7 +131,7 @@ func GetUBDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { return append(UnbondingDelegationKey, res...) } -// get the prefix keyspace for the indexs of unbonding delegations for a validator +// get the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(validatorAddr sdk.Address, cdc *wire.Codec) []byte { res := cdc.MustMarshalBinary(&validatorAddr) return append(UnbondingDelegationByValIndexKey, res...) @@ -131,6 +140,7 @@ func GetUBDsByValIndexKey(validatorAddr sdk.Address, cdc *wire.Codec) []byte { //________________________________________________________________________________ // get the key for a redelegation +// The value at this key is of type stake/types.RedelegationKey func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { @@ -143,6 +153,7 @@ func GetREDKey(delegatorAddr, validatorSrcAddr, } // get the index-key for a redelegation, stored by source-validator-index +// The value at this key is a key for the corresponding redelegation. func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { @@ -155,6 +166,7 @@ func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, } // get the index-key for a redelegation, stored by destination-validator-index +// The value at this key is a key for the corresponding redelegation. func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { From 819eedd28161d2c00277fe9713cdab26c26b2fb4 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Sat, 30 Jun 2018 01:27:58 -0700 Subject: [PATCH 04/53] gaiacli: Improve error messages for `send` command Now provides better error messages when the account you're sending from has no money, or it has insufficient funds. (Avoids making the user interpret ABCI errors) closes #1489 --- CHANGELOG.md | 1 + x/auth/client/cli/account.go | 3 ++- x/bank/client/cli/sendtx.go | 28 ++++++++++++++++++++++++++-- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b543247a..bdb425db34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ FEATURES - You can now use a Ledger with `gaiacli --ledger` for all key-related commands - Ledger keys can be named and tracked locally in the key DB * [gaiacli] added an --async flag to the cli to deliver transactions without waiting for a tendermint response +* [gaiacli] improve error messages on `send` and `account` commands FIXES * [gaia] Added self delegation for validators in the genesis creation diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index ccc1e277be..47980a64ca 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -1,6 +1,7 @@ package cli import ( + "errors" "fmt" "github.com/spf13/cobra" @@ -54,7 +55,7 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode // Check if account was found if res == nil { - return sdk.ErrUnknownAddress("No account with address " + addr + + return errors.New("No account with address " + addr + " was found in the state.\nAre you sure there has been a transaction involving it?") } diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index d3f7377fab..e3ce4c4d2f 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -1,6 +1,7 @@ package cli import ( + "errors" "fmt" "github.com/spf13/cobra" @@ -9,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/bank/client" ) @@ -19,7 +21,7 @@ const ( flagAsync = "async" ) -// SendTxCommand will create a send tx and sign it with the given key +// SendTxCmd will create a send tx and sign it with the given key func SendTxCmd(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "send", @@ -33,19 +35,41 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { return err } + fromAcc, err := ctx.QueryStore(auth.AddressStoreKey(from), ctx.AccountStore) + if err != nil { + return err + } + + bech32From := sdk.MustBech32ifyAcc(from) + // Check if account was found + if fromAcc == nil { + return errors.New("No account with address " + bech32From + + " was found in the state.\nAre you sure there has been a transaction involving it?") + } + toStr := viper.GetString(flagTo) to, err := sdk.GetAccAddressBech32(toStr) if err != nil { return err } - // parse coins + // parse coins trying to be sent amount := viper.GetString(flagAmount) coins, err := sdk.ParseCoins(amount) if err != nil { return err } + // ensure account has enough coins + account, err := ctx.Decoder(fromAcc) + if err != nil { + return err + } + if !account.GetCoins().IsGTE(coins) { + return errors.New("Address " + bech32From + + " doesn't have enough coins to pay for this transaction.") + } + // build and sign the transaction, then broadcast to Tendermint msg := client.BuildMsg(from, to, coins) From ab4661f88b0676f969e0cb4c9b58193158adfd68 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 2 Jul 2018 18:16:47 -0400 Subject: [PATCH 05/53] bug somewhere here --- x/stake/client/cli/query.go | 12 +-- x/stake/client/cli/tx.go | 2 +- x/stake/client/rest/query.go | 6 +- x/stake/keeper/delegation.go | 54 +++++++----- x/stake/keeper/delegation_test.go | 22 ++++- x/stake/keeper/key.go | 141 +++++++++++++++++++----------- x/stake/keeper/sdk_types.go | 2 +- 7 files changed, 155 insertions(+), 84 deletions(-) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index c162717efd..661dce31d7 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -122,7 +122,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { return err } - key := stake.GetDelegationKey(delAddr, valAddr, cdc) + key := stake.GetDelegationKey(delAddr, valAddr) ctx := context.NewCoreContextFromViper() res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -169,7 +169,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } - key := stake.GetDelegationsKey(delegatorAddr, cdc) + key := stake.GetDelegationsKey(delegatorAddr) ctx := context.NewCoreContextFromViper() resKVs, err := ctx.QuerySubspace(cdc, key, storeName) if err != nil { @@ -214,7 +214,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co return err } - key := stake.GetUBDKey(delAddr, valAddr, cdc) + key := stake.GetUBDKey(delAddr, valAddr) ctx := context.NewCoreContextFromViper() res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -261,7 +261,7 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C if err != nil { return err } - key := stake.GetUBDsKey(delegatorAddr, cdc) + key := stake.GetUBDsKey(delegatorAddr) ctx := context.NewCoreContextFromViper() resKVs, err := ctx.QuerySubspace(cdc, key, storeName) if err != nil { @@ -309,7 +309,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { return err } - key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr, cdc) + key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr) ctx := context.NewCoreContextFromViper() res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -356,7 +356,7 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command if err != nil { return err } - key := stake.GetREDsKey(delegatorAddr, cdc) + key := stake.GetREDsKey(delegatorAddr) ctx := context.NewCoreContextFromViper() resKVs, err := ctx.QuerySubspace(cdc, key, storeName) if err != nil { diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index b0fa2e524a..068c19ce22 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -238,7 +238,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent } // make a query to get the existing delegation shares - key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) + key := stake.GetDelegationKey(delegatorAddr, validatorAddr) ctx := context.NewCoreContextFromViper() resQuery, err := ctx.QueryStore(key, storeName) if err != nil { diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index afa9e3bf0c..12ef882e5e 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -60,7 +60,7 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF return } - key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) + key := stake.GetDelegationKey(delegatorAddr, validatorAddr) res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -117,7 +117,7 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - key := stake.GetUBDKey(delegatorAddr, validatorAddr, cdc) + key := stake.GetUBDKey(delegatorAddr, validatorAddr) res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -182,7 +182,7 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr, cdc) + key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr) res, err := ctx.QueryStore(key, storeName) if err != nil { diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 514939e17f..8ede4b55e2 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -2,6 +2,7 @@ package keeper import ( "bytes" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" @@ -12,7 +13,7 @@ func (k Keeper) GetDelegation(ctx sdk.Context, delegatorAddr, validatorAddr sdk.Address) (delegation types.Delegation, found bool) { store := ctx.KVStore(k.storeKey) - delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr, k.cdc)) + delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr)) if delegatorBytes == nil { return delegation, false } @@ -46,7 +47,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (delegations []types.Delegation) { store := ctx.KVStore(k.storeKey) - delegatorPrefixKey := GetDelegationsKey(delegator, k.cdc) + delegatorPrefixKey := GetDelegationsKey(delegator) iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest delegations = make([]types.Delegation, maxRetrieve) @@ -69,13 +70,13 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinary(delegation) - store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc), b) + store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b) } // remove the delegation func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey) - store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc)) + store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr)) } //_____________________________________________________________________________________ @@ -85,7 +86,7 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, DelegatorAddr, ValidatorAddr sdk.Address) (ubd types.UnbondingDelegation, found bool) { store := ctx.KVStore(k.storeKey) - ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr, k.cdc) + ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr) bz := store.Get(ubdKey) if bz == nil { return ubd, false @@ -98,13 +99,13 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, // load all unbonding delegations from a particular validator func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (unbondingDelegations []types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr, k.cdc)) + iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr)) i := 0 for ; ; i++ { if !iterator.Valid() { break } - unbondingKey := iterator.Value() + unbondingKey := GetUBDKeyFromValIndexKey(iterator.Key()) unbondingBytes := store.Get(unbondingKey) var unbondingDelegation types.UnbondingDelegation k.cdc.MustUnmarshalBinary(unbondingBytes, &unbondingDelegation) @@ -119,17 +120,17 @@ func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sd func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(ubd) - ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc) + ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) store.Set(ubdKey, bz) - store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc), ubdKey) + store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) } // remove the unbonding delegation object and associated index func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc) + ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) store.Delete(ubdKey) - store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc)) + store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr)) } //_____________________________________________________________________________________ @@ -139,7 +140,7 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.Address) (red types.Redelegation, found bool) { store := ctx.KVStore(k.storeKey) - redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr, k.cdc) + redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr) bz := store.Get(redKey) if bz == nil { return red, false @@ -152,13 +153,23 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, // load all redelegations from a particular validator func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (redelegations []types.Redelegation) { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr, k.cdc)) + iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr)) i := 0 for ; ; i++ { + fmt.Printf("debug i: %v\n", i) if !iterator.Valid() { break } - redelegationKey := iterator.Value() + redelegationKeyOrig := iterator.Value() + redelegationBytes2 := store.Get(redelegationKeyOrig) + var redelegation2 types.Redelegation + k.cdc.MustUnmarshalBinary(redelegationBytes2, &redelegation2) + fmt.Printf("debug orig redelegation2: %v\n", redelegation2) + + redelegationKey := GetREDKeyFromValSrcIndexKey(iterator.Key()) + fmt.Printf("debug orig redelegationKey: %v\n", redelegationKeyOrig) + fmt.Printf("debug redelegationKey: %v\n", redelegationKey) + fmt.Printf("debug iteratorKey: %v\n", iterator.Key()) redelegationBytes := store.Get(redelegationKey) var redelegation types.Redelegation k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation) @@ -174,7 +185,7 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, DelegatorAddr, ValidatorDstAddr sdk.Address) bool { store := ctx.KVStore(k.storeKey) - prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr, k.cdc) + prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr) iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest found := false @@ -190,19 +201,20 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(red) - redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc) + redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) + fmt.Printf("debug redKey: %v\n", redKey) store.Set(redKey, bz) - store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey) - store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey) + store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), redKey) //[]byte{}) + store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), redKey) // []byte{}) } // remove a redelegation object and associated index func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) - redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc) + redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) store.Delete(redKey) - store.Delete(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)) - store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)) + store.Delete(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)) + store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)) } //_____________________________________________________________________________________ diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index eb318df4d3..4b5d12e095 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -201,19 +202,38 @@ func TestRedelegation(t *testing.T) { keeper.SetRedelegation(ctx, rd) resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) - require.True(t, rd.Equal(resBond)) + + fmt.Println("zoo0") + redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + + fmt.Println("zoo1") + redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + fmt.Println("zoo2") // check if has the redelegation has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) require.True(t, has) + fmt.Println("hoolahoop") // modify a records, save, and retrieve rd.SharesSrc = sdk.NewRat(21) rd.SharesDst = sdk.NewRat(21) + keeper.SetRedelegation(ctx, rd) + resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) require.True(t, rd.Equal(resBond)) + fmt.Println("hippo2") + + redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + fmt.Println("zzzzzzzzzzzzzzzzzzebra") // delete a record keeper.RemoveRedelegation(ctx, rd) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 3be009e220..c0f8c8b299 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -6,7 +6,6 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -29,34 +28,39 @@ var ( UnbondingDelegationKey = []byte{0x0B} // key for an unbonding-delegation UnbondingDelegationByValIndexKey = []byte{0x0C} // prefix for each key for an unbonding-delegation, by validator owner RedelegationKey = []byte{0x0D} // key for a redelegation - RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by validator owner - RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by validator owner + RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by source validator owner + RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by destination validator owner ) const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch // get the key for the validator with address. -// the value at this key is of type stake/types.Validator +// VALUE: stake/types.Validator func GetValidatorKey(ownerAddr sdk.Address) []byte { return append(ValidatorsKey, ownerAddr.Bytes()...) } // get the key for the validator with pubkey. -// the value at this key should the address for a stake/types.Validator +// VALUE: validator owner address ([]byte) func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...) } -// get the key for the current validator group, ordered like tendermint. -// the value at this key is the address of the owner of a validator +// get the key for the current validator group +// VALUE: none (key rearrangement with GetValKeyFromValBondedIndexKey) func GetValidatorsBondedIndexKey(ownerAddr sdk.Address) []byte { return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...) } +// rearrange the ValBondedIndexKey to get the ValidatorKey +func GetValKeyFromValBondedIndexKey(IndexKey []byte) []byte { + addr := IndexKey[1:] // remove prefix bytes + return GetValidatorKey(addr) +} + // get the validator by power index. power index is the key used in the power-store, // and represents the relative power ranking of the validator. -// the value at this key is of type address, the address being the Address -// of the corresponding validator. +// VALUE: validator owner address ([]byte) func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { // NOTE the address doesn't need to be stored because counter bytes must always be different return getValidatorPowerRank(validator, pool) @@ -68,7 +72,6 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { power := validator.EquivalentBondedShares(pool) powerBytes := []byte(power.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) - // TODO ensure that the key will be a readable string.. probably should add seperators and have revokedBytes := make([]byte, 1) if validator.Revoked { revokedBytes[0] = byte(0x01) @@ -76,7 +79,6 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { revokedBytes[0] = byte(0x00) } - // TODO ensure that the key will be a readable string.. probably should add separators and have // heightBytes and counterBytes represent strings like powerBytes does heightBytes := make([]byte, binary.MaxVarintLen64) binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first) @@ -90,62 +92,77 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { } // get the key for the accumulated update validators. -// The value at this key is of type stake/types.Validator +// VALUE: none (key rearrangement used) func GetTendermintUpdatesKey(ownerAddr sdk.Address) []byte { return append(TendermintUpdatesKey, ownerAddr.Bytes()...) } +// rearrange the ValBondedIndexKey to get the ValidatorKey +func GetValKeyFromTUIndexKey(IndexKey []byte) []byte { + addr := IndexKey[1:] // remove prefix bytes + return GetValidatorKey(addr) +} + //________________________________________________________________________________ // get the key for delegator bond with validator. -// The value at this key is of type stake/types.Delegation -func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { - return append(GetDelegationsKey(delegatorAddr, cdc), validatorAddr.Bytes()...) +// VALUE: stake/types.Delegation +func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address) []byte { + return append(GetDelegationsKey(delegatorAddr), validatorAddr.Bytes()...) } // get the prefix for a delegator for all validators -func GetDelegationsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&delegatorAddr) - return append(DelegationKey, res...) +func GetDelegationsKey(delegatorAddr sdk.Address) []byte { + return append(DelegationKey, delegatorAddr.Bytes()...) } //________________________________________________________________________________ // get the key for an unbonding delegation by delegator and validator addr. -// The value at this key is of type stake/types.UnbondingDelegation -func GetUBDKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { - return append(GetUBDsKey(delegatorAddr, cdc), validatorAddr.Bytes()...) +// VALUE: stake/types.UnbondingDelegation +func GetUBDKey(delegatorAddr, validatorAddr sdk.Address) []byte { + return append(GetUBDsKey(delegatorAddr), validatorAddr.Bytes()...) } // get the index-key for an unbonding delegation, stored by validator-index -// The value at this key is a key for the corresponding unbonding delegation. -func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { - return append(GetUBDsByValIndexKey(validatorAddr, cdc), delegatorAddr.Bytes()...) +// VALUE: none (key rearrangement used) +func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address) []byte { + return append(GetUBDsByValIndexKey(validatorAddr), delegatorAddr.Bytes()...) +} + +// rearrange the ValIndexKey to get the UBDKey +func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte { + addrs := IndexKey[1:] // remove prefix bytes + split := len(addrs) / 2 + if (len(addrs) % 2) != 0 { + panic("key length not even") + } + valAddr := addrs[:split] + delAddr := addrs[split:] + return GetUBDKey(delAddr, valAddr) } //______________ // get the prefix for all unbonding delegations from a delegator -func GetUBDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&delegatorAddr) - return append(UnbondingDelegationKey, res...) +func GetUBDsKey(delegatorAddr sdk.Address) []byte { + return append(UnbondingDelegationKey, delegatorAddr.Bytes()...) } // get the prefix keyspace for the indexes of unbonding delegations for a validator -func GetUBDsByValIndexKey(validatorAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&validatorAddr) - return append(UnbondingDelegationByValIndexKey, res...) +func GetUBDsByValIndexKey(validatorAddr sdk.Address) []byte { + return append(UnbondingDelegationByValIndexKey, validatorAddr.Bytes()...) } //________________________________________________________________________________ // get the key for a redelegation -// The value at this key is of type stake/types.RedelegationKey +// VALUE: stake/types.RedelegationKey func GetREDKey(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { + validatorDstAddr sdk.Address) []byte { return append( - GetREDsKey(delegatorAddr, cdc), + GetREDsKey(delegatorAddr), append( validatorSrcAddr.Bytes(), validatorDstAddr.Bytes()...)..., @@ -153,12 +170,12 @@ func GetREDKey(delegatorAddr, validatorSrcAddr, } // get the index-key for a redelegation, stored by source-validator-index -// The value at this key is a key for the corresponding redelegation. +// VALUE: none (key rearrangement used) func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { + validatorDstAddr sdk.Address) []byte { return append( - GetREDsFromValSrcIndexKey(validatorSrcAddr, cdc), + GetREDsFromValSrcIndexKey(validatorSrcAddr), append( delegatorAddr.Bytes(), validatorDstAddr.Bytes()...)..., @@ -166,44 +183,66 @@ func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, } // get the index-key for a redelegation, stored by destination-validator-index -// The value at this key is a key for the corresponding redelegation. +// VALUE: none (key rearrangement used) func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { + validatorDstAddr sdk.Address) []byte { return append( - GetREDsToValDstIndexKey(validatorDstAddr, cdc), + GetREDsToValDstIndexKey(validatorDstAddr), append( delegatorAddr.Bytes(), validatorSrcAddr.Bytes()...)..., ) } +// rearrange the ValSrcIndexKey to get the REDKey +func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { + addrs := IndexKey[1:] // remove prefix bytes + split := len(addrs) / 3 + if (len(addrs) % 3) != 0 { + panic("unexpected key length") + } + valSrcAddr := addrs[:split] + delAddr := addrs[split : 2*split] + valDstAddr := addrs[2*split:] + return GetREDKey(delAddr, valSrcAddr, valDstAddr) +} + +// rearrange the ValDstIndexKey to get the REDKey +func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte { + addrs := IndexKey[1:] // remove prefix bytes + split := len(addrs) / 3 + if (len(addrs) % 3) != 0 { + panic("unexpected key length") + } + valDstAddr := addrs[:split] + delAddr := addrs[split : 2*split] + valSrcAddr := addrs[2*split:] + return GetREDKey(delAddr, valSrcAddr, valDstAddr) +} + //______________ // get the prefix keyspace for redelegations from a delegator -func GetREDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&delegatorAddr) - return append(RedelegationKey, res...) +func GetREDsKey(delegatorAddr sdk.Address) []byte { + return append(RedelegationKey, delegatorAddr.Bytes()...) } // get the prefix keyspace for all redelegations redelegating away from a source validator -func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&validatorSrcAddr) - return append(RedelegationByValSrcIndexKey, res...) +func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address) []byte { + return append(RedelegationByValSrcIndexKey, validatorSrcAddr.Bytes()...) } // get the prefix keyspace for all redelegations redelegating towards a destination validator -func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&validatorDstAddr) - return append(RedelegationByValDstIndexKey, res...) +func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address) []byte { + return append(RedelegationByValDstIndexKey, validatorDstAddr.Bytes()...) } // get the prefix keyspace for all redelegations redelegating towards a destination validator // from a particular delegator func GetREDsByDelToValDstIndexKey(delegatorAddr sdk.Address, - validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { - + validatorDstAddr sdk.Address) []byte { return append( - GetREDsToValDstIndexKey(validatorDstAddr, cdc), + GetREDsToValDstIndexKey(validatorDstAddr), delegatorAddr.Bytes()...) } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 55ad658a2d..1e4782c86c 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -87,7 +87,7 @@ func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.Address, addrVal sdk.Add // iterate through the active validator set and perform the provided function func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func(index int64, delegation sdk.Delegation) (stop bool)) { store := ctx.KVStore(k.storeKey) - key := GetDelegationsKey(delAddr, k.cdc) + key := GetDelegationsKey(delAddr) iterator := sdk.KVStorePrefixIterator(store, key) i := int64(0) for ; iterator.Valid(); iterator.Next() { From b3d6a59c619a9779a2bb3b9d39c7ae857e710da1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 2 Jul 2018 18:58:52 -0400 Subject: [PATCH 06/53] ... --- x/stake/keeper/delegation.go | 20 +++++++------- x/stake/keeper/delegation_test.go | 44 ++++++++++++++++++++++++------- x/stake/keeper/key.go | 4 +++ 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 8ede4b55e2..0fe4406c30 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -154,26 +154,24 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (redelegations []types.Redelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr)) - i := 0 - for ; ; i++ { - fmt.Printf("debug i: %v\n", i) + for { if !iterator.Valid() { break } - redelegationKeyOrig := iterator.Value() - redelegationBytes2 := store.Get(redelegationKeyOrig) - var redelegation2 types.Redelegation - k.cdc.MustUnmarshalBinary(redelegationBytes2, &redelegation2) - fmt.Printf("debug orig redelegation2: %v\n", redelegation2) - redelegationKey := GetREDKeyFromValSrcIndexKey(iterator.Key()) - fmt.Printf("debug orig redelegationKey: %v\n", redelegationKeyOrig) + fmt.Println("called") + //redelegationKey := iterator.Value() + iKey := iterator.Key() + redelegationKey := GetREDKeyFromValSrcIndexKey(iKey) + fmt.Printf("debug iteratorValue: %v\n", iterator.Value()) + fmt.Printf("debug iteratorKey: %v\n", iKey) fmt.Printf("debug redelegationKey: %v\n", redelegationKey) - fmt.Printf("debug iteratorKey: %v\n", iterator.Key()) + redelegationBytes := store.Get(redelegationKey) var redelegation types.Redelegation k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation) redelegations = append(redelegations, redelegation) + iterator.Next() } iterator.Close() diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 4b5d12e095..90cfb8f37b 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -180,6 +180,40 @@ func TestUnbondDelegation(t *testing.T) { require.Equal(t, int64(4), pool.BondedTokens) } +// tests Get/Set/Remove/Has UnbondingDelegation +func TestGetRedelegationsFromValidator(t *testing.T) { + ctx, _, keeper := CreateTestInput(t, false, 0) + + rd := types.Redelegation{ + DelegatorAddr: addrDels[0], + ValidatorSrcAddr: addrVals[0], + ValidatorDstAddr: addrVals[1], + CreationHeight: 0, + MinTime: 0, + SharesSrc: sdk.NewRat(5), + SharesDst: sdk.NewRat(5), + } + + // set and retrieve a record + keeper.SetRedelegation(ctx, rd) + resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + fmt.Printf("debug addrDels[0]: %v\n", addrDels[0]) + fmt.Printf("debug addrVals[0]: %v\n", addrVals[0]) + fmt.Printf("debug addrVals[1]: %v\n", addrVals[1]) + + fmt.Println("zoo0") + redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + + fmt.Println("zoo1") + redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + fmt.Println("zoo2") +} + // tests Get/Set/Remove/Has UnbondingDelegation func TestRedelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) @@ -203,21 +237,13 @@ func TestRedelegation(t *testing.T) { resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) - fmt.Println("zoo0") redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) require.Equal(t, 1, len(redelegations)) require.True(t, redelegations[0].Equal(resBond)) - fmt.Println("zoo1") - redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) - require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resBond)) - fmt.Println("zoo2") - // check if has the redelegation has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) require.True(t, has) - fmt.Println("hoolahoop") // modify a records, save, and retrieve rd.SharesSrc = sdk.NewRat(21) @@ -228,12 +254,10 @@ func TestRedelegation(t *testing.T) { resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) require.True(t, rd.Equal(resBond)) - fmt.Println("hippo2") redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) require.Equal(t, 1, len(redelegations)) require.True(t, redelegations[0].Equal(resBond)) - fmt.Println("zzzzzzzzzzzzzzzzzzebra") // delete a record keeper.RemoveRedelegation(ctx, rd) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index c0f8c8b299..248ee9db0f 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -2,6 +2,7 @@ package keeper import ( "encoding/binary" + "fmt" "github.com/tendermint/tendermint/crypto" @@ -205,6 +206,9 @@ func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { valSrcAddr := addrs[:split] delAddr := addrs[split : 2*split] valDstAddr := addrs[2*split:] + fmt.Printf("debug delAddr: %v\n", delAddr) + fmt.Printf("debug valSrcAddr: %v\n", valSrcAddr) + fmt.Printf("debug valDstAddr: %v\n", valDstAddr) return GetREDKey(delAddr, valSrcAddr, valDstAddr) } From 2355e5ae6e1ad4d65ffa4434d5bcd1ad3461bf1d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 2 Jul 2018 20:05:52 -0400 Subject: [PATCH 07/53] ... --- x/stake/keeper/key.go | 2 +- x/stake/types/delegation.go | 43 +++++++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 248ee9db0f..4b9eb56626 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -206,7 +206,7 @@ func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { valSrcAddr := addrs[:split] delAddr := addrs[split : 2*split] valDstAddr := addrs[2*split:] - fmt.Printf("debug delAddr: %v\n", delAddr) + fmt.Printf("debug delAddr: %v\n", delAddr) fmt.Printf("debug valSrcAddr: %v\n", valSrcAddr) fmt.Printf("debug valDstAddr: %v\n", valDstAddr) return GetREDKey(delAddr, valSrcAddr, valDstAddr) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index eb38a50a7a..c945468fd8 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -13,8 +13,13 @@ import ( type Delegation struct { DelegatorAddr sdk.Address `json:"delegator_addr"` ValidatorAddr sdk.Address `json:"validator_addr"` - Shares sdk.Rat `json:"shares"` - Height int64 `json:"height"` // Last height bond updated + DelegationValue +} + +// delegation store value +type DelegationValue struct { + Shares sdk.Rat `json:"shares"` + Height int64 `json:"height"` // Last height bond updated } // two are equal @@ -57,12 +62,17 @@ func (d Delegation) HumanReadableString() (string, error) { // element stored to represent the passive unbonding queue type UnbondingDelegation struct { - DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator - ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr - CreationHeight int64 `json:"creation_height"` // height which the unbonding took place - MinTime int64 `json:"min_time"` // unix time for unbonding completion - InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion - Balance sdk.Coin `json:"balance"` // atoms to receive at completion + DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator + ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr + UBDValue +} + +// UBD store value +type UBDValue struct { + CreationHeight int64 `json:"creation_height"` // height which the unbonding took place + MinTime int64 `json:"min_time"` // unix time for unbonding completion + InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion + Balance sdk.Coin `json:"balance"` // atoms to receive at completion } // nolint @@ -100,12 +110,17 @@ type Redelegation struct { DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator ValidatorSrcAddr sdk.Address `json:"validator_src_addr"` // validator redelegation source owner addr ValidatorDstAddr sdk.Address `json:"validator_dst_addr"` // validator redelegation destination owner addr - CreationHeight int64 `json:"creation_height"` // height which the redelegation took place - MinTime int64 `json:"min_time"` // unix time for redelegation completion - InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started - Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating + REDValue +} + +// Redelegation store value +type REDValue struct { + CreationHeight int64 `json:"creation_height"` // height which the redelegation took place + MinTime int64 `json:"min_time"` // unix time for redelegation completion + InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started + Balance sdk.Coin `json:"balance"` // current balance + SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating } // nolint From aa243565ce70893f5cfa5328e51d5c08a518f96b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 2 Jul 2018 20:09:57 -0400 Subject: [PATCH 08/53] fix appending over key --- x/stake/keeper/delegation.go | 1 + x/stake/keeper/key.go | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 0fe4406c30..ded603abdd 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -162,6 +162,7 @@ func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Addre fmt.Println("called") //redelegationKey := iterator.Value() iKey := iterator.Key() + fmt.Println("LEN IT", len(iKey)) redelegationKey := GetREDKeyFromValSrcIndexKey(iKey) fmt.Printf("debug iteratorValue: %v\n", iterator.Value()) fmt.Printf("debug iteratorKey: %v\n", iKey) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 248ee9db0f..b831de5f23 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -162,12 +162,13 @@ func GetUBDsByValIndexKey(validatorAddr sdk.Address) []byte { func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.Address) []byte { - return append( - GetREDsKey(delegatorAddr), - append( - validatorSrcAddr.Bytes(), - validatorDstAddr.Bytes()...)..., - ) + fmt.Println("KEY", delegatorAddr.Bytes()) + key := make([]byte, len(delegatorAddr.Bytes())) + copy(key, delegatorAddr.Bytes()) + + return append(append( + GetREDsKey(key), validatorSrcAddr.Bytes()...), + validatorDstAddr.Bytes()...) } // get the index-key for a redelegation, stored by source-validator-index @@ -206,10 +207,18 @@ func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { valSrcAddr := addrs[:split] delAddr := addrs[split : 2*split] valDstAddr := addrs[2*split:] - fmt.Printf("debug delAddr: %v\n", delAddr) + fmt.Printf("debug indexKey: %v\n", IndexKey) fmt.Printf("debug valSrcAddr: %v\n", valSrcAddr) + fmt.Printf("debug delAddr: %v\n", delAddr) fmt.Printf("debug valDstAddr: %v\n", valDstAddr) - return GetREDKey(delAddr, valSrcAddr, valDstAddr) + redKey := GetREDKey(delAddr, valSrcAddr, valDstAddr) + fmt.Println("------") + fmt.Printf("debug indexKey: %v\n", IndexKey) + fmt.Printf("debug valSrcAddr: %v\n", valSrcAddr) + fmt.Printf("debug delAddr: %v\n", delAddr) + fmt.Printf("debug valDstAddr: %v\n", valDstAddr) + fmt.Println("") + return redKey } // rearrange the ValDstIndexKey to get the REDKey From 6f3b4c18056fe32520edf985e3d5d492c54780c7 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 2 Jul 2018 20:58:22 -0400 Subject: [PATCH 09/53] keys cleanup --- x/stake/keeper/delegation.go | 21 +++-------- x/stake/keeper/delegation_test.go | 8 ----- x/stake/keeper/key.go | 27 +++++++------- x/stake/keeper/sdk_types.go | 2 +- x/stake/keeper/validator.go | 8 ++--- x/stake/types/delegation.go | 58 +++++++++++++++++++------------ 6 files changed, 57 insertions(+), 67 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index ded603abdd..bb8170a6a3 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -2,7 +2,6 @@ package keeper import ( "bytes" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" @@ -100,8 +99,7 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (unbondingDelegations []types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr)) - i := 0 - for ; ; i++ { + for { if !iterator.Valid() { break } @@ -158,21 +156,11 @@ func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Addre if !iterator.Valid() { break } - - fmt.Println("called") - //redelegationKey := iterator.Value() - iKey := iterator.Key() - fmt.Println("LEN IT", len(iKey)) - redelegationKey := GetREDKeyFromValSrcIndexKey(iKey) - fmt.Printf("debug iteratorValue: %v\n", iterator.Value()) - fmt.Printf("debug iteratorKey: %v\n", iKey) - fmt.Printf("debug redelegationKey: %v\n", redelegationKey) - + redelegationKey := GetREDKeyFromValSrcIndexKey(iterator.Key()) redelegationBytes := store.Get(redelegationKey) var redelegation types.Redelegation k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation) redelegations = append(redelegations, redelegation) - iterator.Next() } iterator.Close() @@ -201,10 +189,9 @@ func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(red) redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) - fmt.Printf("debug redKey: %v\n", redKey) store.Set(redKey, bz) - store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), redKey) //[]byte{}) - store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), redKey) // []byte{}) + store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) + store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) } // remove a redelegation object and associated index diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 90cfb8f37b..a7cb566f1d 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -1,7 +1,6 @@ package keeper import ( - "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -198,20 +197,14 @@ func TestGetRedelegationsFromValidator(t *testing.T) { keeper.SetRedelegation(ctx, rd) resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) - fmt.Printf("debug addrDels[0]: %v\n", addrDels[0]) - fmt.Printf("debug addrVals[0]: %v\n", addrVals[0]) - fmt.Printf("debug addrVals[1]: %v\n", addrVals[1]) - fmt.Println("zoo0") redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) require.Equal(t, 1, len(redelegations)) require.True(t, redelegations[0].Equal(resBond)) - fmt.Println("zoo1") redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) require.Equal(t, 1, len(redelegations)) require.True(t, redelegations[0].Equal(resBond)) - fmt.Println("zoo2") } // tests Get/Set/Remove/Has UnbondingDelegation @@ -248,7 +241,6 @@ func TestRedelegation(t *testing.T) { // modify a records, save, and retrieve rd.SharesSrc = sdk.NewRat(21) rd.SharesDst = sdk.NewRat(21) - keeper.SetRedelegation(ctx, rd) resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 50d08e4255..6924a10579 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -2,7 +2,6 @@ package keeper import ( "encoding/binary" - "fmt" "github.com/tendermint/tendermint/crypto" @@ -54,9 +53,8 @@ func GetValidatorsBondedIndexKey(ownerAddr sdk.Address) []byte { } // rearrange the ValBondedIndexKey to get the ValidatorKey -func GetValKeyFromValBondedIndexKey(IndexKey []byte) []byte { - addr := IndexKey[1:] // remove prefix bytes - return GetValidatorKey(addr) +func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte { + return IndexKey[1:] // remove prefix bytes } // get the validator by power index. power index is the key used in the power-store, @@ -93,17 +91,12 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { } // get the key for the accumulated update validators. -// VALUE: none (key rearrangement used) +// VALUE: abci.Validator +// note records using these keys should never persist between blocks func GetTendermintUpdatesKey(ownerAddr sdk.Address) []byte { return append(TendermintUpdatesKey, ownerAddr.Bytes()...) } -// rearrange the ValBondedIndexKey to get the ValidatorKey -func GetValKeyFromTUIndexKey(IndexKey []byte) []byte { - addr := IndexKey[1:] // remove prefix bytes - return GetValidatorKey(addr) -} - //________________________________________________________________________________ // get the key for delegator bond with validator. @@ -122,7 +115,13 @@ func GetDelegationsKey(delegatorAddr sdk.Address) []byte { // get the key for an unbonding delegation by delegator and validator addr. // VALUE: stake/types.UnbondingDelegation func GetUBDKey(delegatorAddr, validatorAddr sdk.Address) []byte { - return append(GetUBDsKey(delegatorAddr), validatorAddr.Bytes()...) + + key := make([]byte, len(delegatorAddr.Bytes())) + copy(key, delegatorAddr.Bytes()) + + return append( + GetUBDsKey(key), + validatorAddr.Bytes()...) } // get the index-key for an unbonding delegation, stored by validator-index @@ -162,12 +161,12 @@ func GetUBDsByValIndexKey(validatorAddr sdk.Address) []byte { func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.Address) []byte { - fmt.Println("KEY", delegatorAddr.Bytes()) key := make([]byte, len(delegatorAddr.Bytes())) copy(key, delegatorAddr.Bytes()) return append(append( - GetREDsKey(key), validatorSrcAddr.Bytes()...), + GetREDsKey(key), + validatorSrcAddr.Bytes()...), validatorDstAddr.Bytes()...) } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 1e4782c86c..bedbc15591 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -34,7 +34,7 @@ func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, va iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) i := int64(0) for ; iterator.Valid(); iterator.Next() { - address := iterator.Value() + address := GetAddressFromValBondedIndexKey(iterator.Key()) validator, found := k.GetValidator(ctx, address) if !found { panic(fmt.Sprintf("validator record not found for address: %v\n", address)) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 0d556f7dc4..c2711788be 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -56,7 +56,7 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida // validator index func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner) + store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{}) } // used in testing @@ -124,7 +124,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat if i > int(maxValidators-1) { panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated") } - address := iterator.Value() + address := GetAddressFromValBondedIndexKey(iterator.Key()) validator, found := k.GetValidator(ctx, address) if !found { panic(fmt.Sprintf("validator record not found for address: %v\n", address)) @@ -362,7 +362,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) { toKickOut := make(map[string]byte) iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) for ; iterator.Valid(); iterator.Next() { - ownerAddr := iterator.Value() + ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key()) toKickOut[string(ownerAddr)] = 0 // set anything } iterator.Close() @@ -471,7 +471,7 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. // save the now bonded validator record to the three referenced stores bzVal := k.cdc.MustMarshalBinary(validator) store.Set(GetValidatorKey(validator.Owner), bzVal) - store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner) + store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{}) // add to accumulated changes for tendermint bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index c945468fd8..daaeecef1e 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -13,14 +13,16 @@ import ( type Delegation struct { DelegatorAddr sdk.Address `json:"delegator_addr"` ValidatorAddr sdk.Address `json:"validator_addr"` - DelegationValue + Shares sdk.Rat `json:"shares"` + Height int64 `json:"height"` // Last height bond updated + //DelegationValue } // delegation store value -type DelegationValue struct { - Shares sdk.Rat `json:"shares"` - Height int64 `json:"height"` // Last height bond updated -} +//type DelegationValue struct { +//Shares sdk.Rat `json:"shares"` +//Height int64 `json:"height"` // Last height bond updated +//} // two are equal func (d Delegation) Equal(d2 Delegation) bool { @@ -62,18 +64,22 @@ func (d Delegation) HumanReadableString() (string, error) { // element stored to represent the passive unbonding queue type UnbondingDelegation struct { - DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator - ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr - UBDValue + DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator + ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr + CreationHeight int64 `json:"creation_height"` // height which the unbonding took place + MinTime int64 `json:"min_time"` // unix time for unbonding completion + InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion + Balance sdk.Coin `json:"balance"` // atoms to receive at completion + //UBDValue } // UBD store value -type UBDValue struct { - CreationHeight int64 `json:"creation_height"` // height which the unbonding took place - MinTime int64 `json:"min_time"` // unix time for unbonding completion - InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion - Balance sdk.Coin `json:"balance"` // atoms to receive at completion -} +//type UBDValue struct { +//CreationHeight int64 `json:"creation_height"` // height which the unbonding took place +//MinTime int64 `json:"min_time"` // unix time for unbonding completion +//InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion +//Balance sdk.Coin `json:"balance"` // atoms to receive at completion +//} // nolint func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { @@ -110,18 +116,24 @@ type Redelegation struct { DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator ValidatorSrcAddr sdk.Address `json:"validator_src_addr"` // validator redelegation source owner addr ValidatorDstAddr sdk.Address `json:"validator_dst_addr"` // validator redelegation destination owner addr - REDValue + CreationHeight int64 `json:"creation_height"` // height which the redelegation took place + MinTime int64 `json:"min_time"` // unix time for redelegation completion + InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started + Balance sdk.Coin `json:"balance"` // current balance + SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating + //REDValue } // Redelegation store value -type REDValue struct { - CreationHeight int64 `json:"creation_height"` // height which the redelegation took place - MinTime int64 `json:"min_time"` // unix time for redelegation completion - InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started - Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating -} +//type REDValue struct { +//CreationHeight int64 `json:"creation_height"` // height which the redelegation took place +//MinTime int64 `json:"min_time"` // unix time for redelegation completion +//InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started +//Balance sdk.Coin `json:"balance"` // current balance +//SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating +//SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating +//} // nolint func (d Redelegation) Equal(d2 Redelegation) bool { From aec264d92302d2f22e9122c60ccd29290d0e4a40 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 2 Jul 2018 21:06:05 -0400 Subject: [PATCH 10/53] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b261e7d84b..4dea6d7f8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ BREAKING CHANGES * Add REST endpoint to unrevoke a validator previously revoked for downtime * Add REST endpoint to retrieve liveness signing information for a validator * [types] renamed rational.Evaluate to rational.Round{Int64, Int} +* [stake] most index keys nolonger hold a value - inputs are rearranged to form the desired key FEATURES * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag From 271fbb2db3a5946f20ba34891bdedc77a9b15e15 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 2 Jul 2018 21:16:32 -0400 Subject: [PATCH 11/53] remove some junk --- x/stake/types/delegation.go | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index daaeecef1e..eb38a50a7a 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -15,15 +15,8 @@ type Delegation struct { ValidatorAddr sdk.Address `json:"validator_addr"` Shares sdk.Rat `json:"shares"` Height int64 `json:"height"` // Last height bond updated - //DelegationValue } -// delegation store value -//type DelegationValue struct { -//Shares sdk.Rat `json:"shares"` -//Height int64 `json:"height"` // Last height bond updated -//} - // two are equal func (d Delegation) Equal(d2 Delegation) bool { return bytes.Equal(d.DelegatorAddr, d2.DelegatorAddr) && @@ -70,17 +63,8 @@ type UnbondingDelegation struct { MinTime int64 `json:"min_time"` // unix time for unbonding completion InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion Balance sdk.Coin `json:"balance"` // atoms to receive at completion - //UBDValue } -// UBD store value -//type UBDValue struct { -//CreationHeight int64 `json:"creation_height"` // height which the unbonding took place -//MinTime int64 `json:"min_time"` // unix time for unbonding completion -//InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion -//Balance sdk.Coin `json:"balance"` // atoms to receive at completion -//} - // nolint func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { bz1 := MsgCdc.MustMarshalBinary(&d) @@ -122,19 +106,8 @@ type Redelegation struct { Balance sdk.Coin `json:"balance"` // current balance SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating - //REDValue } -// Redelegation store value -//type REDValue struct { -//CreationHeight int64 `json:"creation_height"` // height which the redelegation took place -//MinTime int64 `json:"min_time"` // unix time for redelegation completion -//InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started -//Balance sdk.Coin `json:"balance"` // current balance -//SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating -//SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating -//} - // nolint func (d Redelegation) Equal(d2 Redelegation) bool { bz1 := MsgCdc.MustMarshalBinary(&d) From 4f0c7d8746e3e0d4315888dac72869034ed336a0 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 3 Jul 2018 13:37:17 -0400 Subject: [PATCH 12/53] address bucky comments - rearrange appends --- x/stake/keeper/delegation_test.go | 4 +++- x/stake/keeper/key.go | 39 ++++++++++++------------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index a7cb566f1d..c0a3ee8c57 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -179,7 +179,7 @@ func TestUnbondDelegation(t *testing.T) { require.Equal(t, int64(4), pool.BondedTokens) } -// tests Get/Set/Remove/Has UnbondingDelegation +// Make sure that that the retrieving the delegations doesn't affect the state func TestGetRedelegationsFromValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) @@ -198,10 +198,12 @@ func TestGetRedelegationsFromValidator(t *testing.T) { resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) + // get the redelegations one time redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) require.Equal(t, 1, len(redelegations)) require.True(t, redelegations[0].Equal(resBond)) + // get the redelegations a second time, should be exactly the same redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) require.Equal(t, 1, len(redelegations)) require.True(t, redelegations[0].Equal(resBond)) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 6924a10579..4d1ad0baea 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -52,7 +52,7 @@ func GetValidatorsBondedIndexKey(ownerAddr sdk.Address) []byte { return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...) } -// rearrange the ValBondedIndexKey to get the ValidatorKey +// Get the validator owner address from ValBondedIndexKey func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte { return IndexKey[1:] // remove prefix bytes } @@ -84,10 +84,12 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { counterBytes := make([]byte, 2) binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority) - return append(ValidatorsByPowerIndexKey, - append(revokedBytes, - append(powerBytes, - append(heightBytes, counterBytes...)...)...)...) + return append(append(append(append( + ValidatorsByPowerIndexKey, + revokedBytes...), + powerBytes...), + heightBytes...), + counterBytes...) } // get the key for the accumulated update validators. @@ -115,12 +117,8 @@ func GetDelegationsKey(delegatorAddr sdk.Address) []byte { // get the key for an unbonding delegation by delegator and validator addr. // VALUE: stake/types.UnbondingDelegation func GetUBDKey(delegatorAddr, validatorAddr sdk.Address) []byte { - - key := make([]byte, len(delegatorAddr.Bytes())) - copy(key, delegatorAddr.Bytes()) - return append( - GetUBDsKey(key), + GetUBDsKey(delegatorAddr.Bytes()), validatorAddr.Bytes()...) } @@ -161,11 +159,8 @@ func GetUBDsByValIndexKey(validatorAddr sdk.Address) []byte { func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.Address) []byte { - key := make([]byte, len(delegatorAddr.Bytes())) - copy(key, delegatorAddr.Bytes()) - return append(append( - GetREDsKey(key), + GetREDsKey(delegatorAddr.Bytes()), validatorSrcAddr.Bytes()...), validatorDstAddr.Bytes()...) } @@ -175,12 +170,10 @@ func GetREDKey(delegatorAddr, validatorSrcAddr, func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.Address) []byte { - return append( + return append(append( GetREDsFromValSrcIndexKey(validatorSrcAddr), - append( - delegatorAddr.Bytes(), - validatorDstAddr.Bytes()...)..., - ) + delegatorAddr.Bytes()...), + validatorDstAddr.Bytes()...) } // get the index-key for a redelegation, stored by destination-validator-index @@ -188,12 +181,10 @@ func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.Address) []byte { - return append( + return append(append( GetREDsToValDstIndexKey(validatorDstAddr), - append( - delegatorAddr.Bytes(), - validatorSrcAddr.Bytes()...)..., - ) + delegatorAddr.Bytes()...), + validatorSrcAddr.Bytes()...) } // rearrange the ValSrcIndexKey to get the REDKey From ab964da10568b7ff1872dc754160c87312e940bf Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 3 Jul 2018 15:03:35 -0400 Subject: [PATCH 13/53] marshal/unmarshal delegation --- x/stake/types/delegation.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index eb38a50a7a..705dcb6cd9 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -5,6 +5,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) // Delegation represents the bond with tokens held by an account. It is @@ -17,6 +18,41 @@ type Delegation struct { Height int64 `json:"height"` // Last height bond updated } +type delegationValue struct { + Shares sdk.Rat + Height int64 +} + +// return the delegation without fields contained within the key for the store +func MarshalDelegation(cdc *wire.Codec, delegation Delegation) []byte { + val := delegationValue{ + delegation.Shares, + delegation.Height, + } + return cdc.MustMarshalBinary(val) +} + +// return the delegation without fields contained within the key for the store +func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) Delegation { + var storeValue delegationValue + cdc.MustUnmarshalBinary(value, &storeValue) + + addrs := IndexKey[1:] // remove prefix bytes + split := len(addrs) / 2 + if (len(addrs) % 2) != 0 { + panic("key length not even") + } + delAddr := sdk.Address{addrs[:split]} + valAddr := sdk.Address{addrs[split:]} + + return Delegation{ + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, + Shares: storeValue.Shares, + Height: storeValue.Height, + } +} + // two are equal func (d Delegation) Equal(d2 Delegation) bool { return bytes.Equal(d.DelegatorAddr, d2.DelegatorAddr) && From 270e2162622446994fb3ef17a5d141e7d4aa31df Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Tue, 3 Jul 2018 15:10:56 -0700 Subject: [PATCH 14/53] Merge PR #1512: Add Ledger Instructions * Add ledger instructions * Address PR comments --- docs/clients/ledger.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 docs/clients/ledger.md diff --git a/docs/clients/ledger.md b/docs/clients/ledger.md new file mode 100644 index 0000000000..9f6386715d --- /dev/null +++ b/docs/clients/ledger.md @@ -0,0 +1,29 @@ +# Ledger // Cosmos + +### Ledger Support for account keys + +`gaiacli` now supports derivation of account keys from a Ledger seed. To use this functionality you will need the following: + +- A running `gaiad` instance connected to the network you wish to use. +- A `gaiacli` instance configured to connect to your chosen `gaiad` instance. +- A LedgerNano with the `ledger-cosmos` app installed + * Install the Cosmos app onto your Ledger by following the instructions in the [`ledger-cosmos`](https://github.com/cosmos/ledger-cosmos/blob/master/docs/BUILD.md) repository. + * A production-ready version of this app will soon be included in the [Ledger Apps Store](https://www.ledgerwallet.com/apps) + +> **NOTE:** Cosmos keys are derived acording to the [BIP 44 Hierarchical Deterministic wallet spec](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). For more information on Cosmos derivation paths [see the hd package](https://github.com/cosmos/cosmos-sdk/blob/develop/crypto/keys/hd/hdpath.go#L30). + +Once you have the Cosmos app installed on your Ledger, and the Ledger is accessible from the machine you are using `gaiacli` from you can create a new account key using the Ledger: + +```bash +$ gaiacli keys add {{ .Key.Name }} --ledger +NAME: TYPE: ADDRESS: PUBKEY: +{{ .Key.Name }} ledger cosmosaccaddr1aw64xxr80lwqqdk8u2xhlrkxqaxamkr3e2g943 cosmosaccpub1addwnpepqvhs678gh9aqrjc2tg2vezw86csnvgzqq530ujkunt5tkuc7lhjkz5mj629 +``` + +This key will only be accessible while the Ledger is plugged in and unlocked. To send some coins with this key, run the following: + +```bash +$ gaiacli send --name {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000 +``` + +You will be asked to review and confirm the transaction on the Ledger. Once you do this you should see the result in the console! Now you can use your Ledger to manage your Atoms and Stake! From cae6b40221979ded236c0fb0bad2859434b0f086 Mon Sep 17 00:00:00 2001 From: Rigel Date: Tue, 3 Jul 2018 19:15:48 -0400 Subject: [PATCH 15/53] Merge pull request #1467: staking index keys don't hold values * docs: Explain the expected return type within the store (#1452) * bug somewhere here * ... * ... * fix appending over key * keys cleanup * changelog * remove some junk * address bucky comments - rearrange appends * hard code address length --- CHANGELOG.md | 2 + x/stake/client/cli/query.go | 12 +- x/stake/client/cli/tx.go | 2 +- x/stake/client/rest/query.go | 6 +- x/stake/keeper/delegation.go | 48 ++++---- x/stake/keeper/delegation_test.go | 40 ++++++- x/stake/keeper/key.go | 182 ++++++++++++++++++------------ x/stake/keeper/sdk_types.go | 4 +- x/stake/keeper/validator.go | 8 +- 9 files changed, 192 insertions(+), 112 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecba003625..56bad46c37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,8 @@ BREAKING CHANGES to an infraction, slash them proportional to their stake at the time * Add REST endpoint to unrevoke a validator previously revoked for downtime * Add REST endpoint to retrieve liveness signing information for a validator +* [types] renamed rational.Evaluate to rational.Round{Int64, Int} +* [stake] most index keys nolonger hold a value - inputs are rearranged to form the desired key * [lcd] Switch key creation output to return bech32 FEATURES diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index bccfd7c2be..5a22f2c416 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -122,7 +122,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { return err } - key := stake.GetDelegationKey(delAddr, valAddr, cdc) + key := stake.GetDelegationKey(delAddr, valAddr) ctx := context.NewCoreContextFromViper() res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -169,7 +169,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } - key := stake.GetDelegationsKey(delegatorAddr, cdc) + key := stake.GetDelegationsKey(delegatorAddr) ctx := context.NewCoreContextFromViper() resKVs, err := ctx.QuerySubspace(cdc, key, storeName) if err != nil { @@ -214,7 +214,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co return err } - key := stake.GetUBDKey(delAddr, valAddr, cdc) + key := stake.GetUBDKey(delAddr, valAddr) ctx := context.NewCoreContextFromViper() res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -261,7 +261,7 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C if err != nil { return err } - key := stake.GetUBDsKey(delegatorAddr, cdc) + key := stake.GetUBDsKey(delegatorAddr) ctx := context.NewCoreContextFromViper() resKVs, err := ctx.QuerySubspace(cdc, key, storeName) if err != nil { @@ -309,7 +309,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { return err } - key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr, cdc) + key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr) ctx := context.NewCoreContextFromViper() res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -356,7 +356,7 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command if err != nil { return err } - key := stake.GetREDsKey(delegatorAddr, cdc) + key := stake.GetREDsKey(delegatorAddr) ctx := context.NewCoreContextFromViper() resKVs, err := ctx.QuerySubspace(cdc, key, storeName) if err != nil { diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index dff765fac7..7200caef3f 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -240,7 +240,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent } // make a query to get the existing delegation shares - key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) + key := stake.GetDelegationKey(delegatorAddr, validatorAddr) ctx := context.NewCoreContextFromViper() resQuery, err := ctx.QueryStore(key, storeName) if err != nil { diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index afa9e3bf0c..12ef882e5e 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -60,7 +60,7 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF return } - key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) + key := stake.GetDelegationKey(delegatorAddr, validatorAddr) res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -117,7 +117,7 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - key := stake.GetUBDKey(delegatorAddr, validatorAddr, cdc) + key := stake.GetUBDKey(delegatorAddr, validatorAddr) res, err := ctx.QueryStore(key, storeName) if err != nil { @@ -182,7 +182,7 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr, cdc) + key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr) res, err := ctx.QueryStore(key, storeName) if err != nil { diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 514939e17f..bb8170a6a3 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -12,7 +12,7 @@ func (k Keeper) GetDelegation(ctx sdk.Context, delegatorAddr, validatorAddr sdk.Address) (delegation types.Delegation, found bool) { store := ctx.KVStore(k.storeKey) - delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr, k.cdc)) + delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr)) if delegatorBytes == nil { return delegation, false } @@ -46,7 +46,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (delegations []types.Delegation) { store := ctx.KVStore(k.storeKey) - delegatorPrefixKey := GetDelegationsKey(delegator, k.cdc) + delegatorPrefixKey := GetDelegationsKey(delegator) iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest delegations = make([]types.Delegation, maxRetrieve) @@ -69,13 +69,13 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinary(delegation) - store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc), b) + store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b) } // remove the delegation func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey) - store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc)) + store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr)) } //_____________________________________________________________________________________ @@ -85,7 +85,7 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, DelegatorAddr, ValidatorAddr sdk.Address) (ubd types.UnbondingDelegation, found bool) { store := ctx.KVStore(k.storeKey) - ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr, k.cdc) + ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr) bz := store.Get(ubdKey) if bz == nil { return ubd, false @@ -98,13 +98,12 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, // load all unbonding delegations from a particular validator func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (unbondingDelegations []types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr, k.cdc)) - i := 0 - for ; ; i++ { + iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr)) + for { if !iterator.Valid() { break } - unbondingKey := iterator.Value() + unbondingKey := GetUBDKeyFromValIndexKey(iterator.Key()) unbondingBytes := store.Get(unbondingKey) var unbondingDelegation types.UnbondingDelegation k.cdc.MustUnmarshalBinary(unbondingBytes, &unbondingDelegation) @@ -119,17 +118,17 @@ func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sd func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(ubd) - ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc) + ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) store.Set(ubdKey, bz) - store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc), ubdKey) + store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) } // remove the unbonding delegation object and associated index func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc) + ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) store.Delete(ubdKey) - store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc)) + store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr)) } //_____________________________________________________________________________________ @@ -139,7 +138,7 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.Address) (red types.Redelegation, found bool) { store := ctx.KVStore(k.storeKey) - redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr, k.cdc) + redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr) bz := store.Get(redKey) if bz == nil { return red, false @@ -152,13 +151,12 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, // load all redelegations from a particular validator func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (redelegations []types.Redelegation) { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr, k.cdc)) - i := 0 - for ; ; i++ { + iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr)) + for { if !iterator.Valid() { break } - redelegationKey := iterator.Value() + redelegationKey := GetREDKeyFromValSrcIndexKey(iterator.Key()) redelegationBytes := store.Get(redelegationKey) var redelegation types.Redelegation k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation) @@ -174,7 +172,7 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, DelegatorAddr, ValidatorDstAddr sdk.Address) bool { store := ctx.KVStore(k.storeKey) - prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr, k.cdc) + prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr) iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest found := false @@ -190,19 +188,19 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(red) - redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc) + redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) store.Set(redKey, bz) - store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey) - store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey) + store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) + store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) } // remove a redelegation object and associated index func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) - redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc) + redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) store.Delete(redKey) - store.Delete(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)) - store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)) + store.Delete(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)) + store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)) } //_____________________________________________________________________________________ diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index eb318df4d3..c0a3ee8c57 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -179,6 +179,36 @@ func TestUnbondDelegation(t *testing.T) { require.Equal(t, int64(4), pool.BondedTokens) } +// Make sure that that the retrieving the delegations doesn't affect the state +func TestGetRedelegationsFromValidator(t *testing.T) { + ctx, _, keeper := CreateTestInput(t, false, 0) + + rd := types.Redelegation{ + DelegatorAddr: addrDels[0], + ValidatorSrcAddr: addrVals[0], + ValidatorDstAddr: addrVals[1], + CreationHeight: 0, + MinTime: 0, + SharesSrc: sdk.NewRat(5), + SharesDst: sdk.NewRat(5), + } + + // set and retrieve a record + keeper.SetRedelegation(ctx, rd) + resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + + // get the redelegations one time + redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + + // get the redelegations a second time, should be exactly the same + redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) +} + // tests Get/Set/Remove/Has UnbondingDelegation func TestRedelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) @@ -201,7 +231,10 @@ func TestRedelegation(t *testing.T) { keeper.SetRedelegation(ctx, rd) resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) - require.True(t, rd.Equal(resBond)) + + redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) // check if has the redelegation has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) @@ -211,10 +244,15 @@ func TestRedelegation(t *testing.T) { rd.SharesSrc = sdk.NewRat(21) rd.SharesDst = sdk.NewRat(21) keeper.SetRedelegation(ctx, rd) + resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) require.True(t, rd.Equal(resBond)) + redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resBond)) + // delete a record keeper.RemoveRedelegation(ctx, rd) _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 667f5f681e..cfe8ded82b 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -6,7 +6,6 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -29,41 +28,49 @@ var ( UnbondingDelegationKey = []byte{0x0B} // key for an unbonding-delegation UnbondingDelegationByValIndexKey = []byte{0x0C} // prefix for each key for an unbonding-delegation, by validator owner RedelegationKey = []byte{0x0D} // key for a redelegation - RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by validator owner - RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by validator owner + RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by source validator owner + RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by destination validator owner ) const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch -// get the key for the validator with address +// get the key for the validator with address. +// VALUE: stake/types.Validator func GetValidatorKey(ownerAddr sdk.Address) []byte { return append(ValidatorsKey, ownerAddr.Bytes()...) } -// get the key for the validator with pubkey +// get the key for the validator with pubkey. +// VALUE: validator owner address ([]byte) func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...) } -// get the key for the current validator group, ordered like tendermint +// get the key for the current validator group +// VALUE: none (key rearrangement with GetValKeyFromValBondedIndexKey) func GetValidatorsBondedIndexKey(ownerAddr sdk.Address) []byte { return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...) } -// get the power which is the key for the validator used in the power-store -func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { - - // NOTE the address doesn't need to be stored because counter bytes must always be different - return GetValidatorPowerRank(validator, pool) +// Get the validator owner address from ValBondedIndexKey +func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte { + return IndexKey[1:] // remove prefix bytes } -// get the power of a validator -func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { +// get the validator by power index. power index is the key used in the power-store, +// and represents the relative power ranking of the validator. +// VALUE: validator owner address ([]byte) +func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { + // NOTE the address doesn't need to be stored because counter bytes must always be different + return getValidatorPowerRank(validator, pool) +} + +// get the power ranking of a validator +func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { power := validator.EquivalentBondedShares(pool) powerBytes := []byte(power.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) - // TODO ensure that the key will be a readable string.. probably should add seperators and have revokedBytes := make([]byte, 1) if validator.Revoked { revokedBytes[0] = byte(0x01) @@ -71,127 +78,162 @@ func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { revokedBytes[0] = byte(0x00) } - // TODO ensure that the key will be a readable string.. probably should add seperators and have // heightBytes and counterBytes represent strings like powerBytes does heightBytes := make([]byte, binary.MaxVarintLen64) binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first) counterBytes := make([]byte, 2) binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority) - return append(ValidatorsByPowerIndexKey, - append(revokedBytes, - append(powerBytes, - append(heightBytes, counterBytes...)...)...)...) + return append(append(append(append( + ValidatorsByPowerIndexKey, + revokedBytes...), + powerBytes...), + heightBytes...), + counterBytes...) } -// get the key for the accumulated update validators +// get the key for the accumulated update validators. +// VALUE: abci.Validator +// note records using these keys should never persist between blocks func GetTendermintUpdatesKey(ownerAddr sdk.Address) []byte { return append(TendermintUpdatesKey, ownerAddr.Bytes()...) } //________________________________________________________________________________ -// get the key for delegator bond with validator -func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { - return append(GetDelegationsKey(delegatorAddr, cdc), validatorAddr.Bytes()...) +// get the key for delegator bond with validator. +// VALUE: stake/types.Delegation +func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address) []byte { + return append(GetDelegationsKey(delegatorAddr), validatorAddr.Bytes()...) } // get the prefix for a delegator for all validators -func GetDelegationsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&delegatorAddr) - return append(DelegationKey, res...) +func GetDelegationsKey(delegatorAddr sdk.Address) []byte { + return append(DelegationKey, delegatorAddr.Bytes()...) } //________________________________________________________________________________ -// get the key for an unbonding delegation -func GetUBDKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { - return append(GetUBDsKey(delegatorAddr, cdc), validatorAddr.Bytes()...) +// get the key for an unbonding delegation by delegator and validator addr. +// VALUE: stake/types.UnbondingDelegation +func GetUBDKey(delegatorAddr, validatorAddr sdk.Address) []byte { + return append( + GetUBDsKey(delegatorAddr.Bytes()), + validatorAddr.Bytes()...) } // get the index-key for an unbonding delegation, stored by validator-index -func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { - return append(GetUBDsByValIndexKey(validatorAddr, cdc), delegatorAddr.Bytes()...) +// VALUE: none (key rearrangement used) +func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address) []byte { + return append(GetUBDsByValIndexKey(validatorAddr), delegatorAddr.Bytes()...) +} + +// rearrange the ValIndexKey to get the UBDKey +func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte { + addrs := IndexKey[1:] // remove prefix bytes + if len(addrs) != 40 { + panic("unexpected key length") + } + valAddr := addrs[:20] + delAddr := addrs[20:] + return GetUBDKey(delAddr, valAddr) } //______________ // get the prefix for all unbonding delegations from a delegator -func GetUBDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&delegatorAddr) - return append(UnbondingDelegationKey, res...) +func GetUBDsKey(delegatorAddr sdk.Address) []byte { + return append(UnbondingDelegationKey, delegatorAddr.Bytes()...) } -// get the prefix keyspace for the indexs of unbonding delegations for a validator -func GetUBDsByValIndexKey(validatorAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&validatorAddr) - return append(UnbondingDelegationByValIndexKey, res...) +// get the prefix keyspace for the indexes of unbonding delegations for a validator +func GetUBDsByValIndexKey(validatorAddr sdk.Address) []byte { + return append(UnbondingDelegationByValIndexKey, validatorAddr.Bytes()...) } //________________________________________________________________________________ // get the key for a redelegation +// VALUE: stake/types.RedelegationKey func GetREDKey(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { + validatorDstAddr sdk.Address) []byte { - return append( - GetREDsKey(delegatorAddr, cdc), - append( - validatorSrcAddr.Bytes(), - validatorDstAddr.Bytes()...)..., - ) + return append(append( + GetREDsKey(delegatorAddr.Bytes()), + validatorSrcAddr.Bytes()...), + validatorDstAddr.Bytes()...) } // get the index-key for a redelegation, stored by source-validator-index +// VALUE: none (key rearrangement used) func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { + validatorDstAddr sdk.Address) []byte { - return append( - GetREDsFromValSrcIndexKey(validatorSrcAddr, cdc), - append( - delegatorAddr.Bytes(), - validatorDstAddr.Bytes()...)..., - ) + return append(append( + GetREDsFromValSrcIndexKey(validatorSrcAddr), + delegatorAddr.Bytes()...), + validatorDstAddr.Bytes()...) } // get the index-key for a redelegation, stored by destination-validator-index +// VALUE: none (key rearrangement used) func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { + validatorDstAddr sdk.Address) []byte { - return append( - GetREDsToValDstIndexKey(validatorDstAddr, cdc), - append( - delegatorAddr.Bytes(), - validatorSrcAddr.Bytes()...)..., - ) + return append(append( + GetREDsToValDstIndexKey(validatorDstAddr), + delegatorAddr.Bytes()...), + validatorSrcAddr.Bytes()...) +} + +// rearrange the ValSrcIndexKey to get the REDKey +func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { + addrs := IndexKey[1:] // remove prefix bytes + if len(addrs) != 60 { + panic("unexpected key length") + } + valSrcAddr := addrs[:20] + delAddr := addrs[20:40] + valDstAddr := addrs[40:] + + return GetREDKey(delAddr, valSrcAddr, valDstAddr) +} + +// rearrange the ValDstIndexKey to get the REDKey +func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte { + addrs := IndexKey[1:] // remove prefix bytes + if len(addrs) != 60 { + panic("unexpected key length") + } + valDstAddr := addrs[:20] + delAddr := addrs[20:40] + valSrcAddr := addrs[40:] + return GetREDKey(delAddr, valSrcAddr, valDstAddr) } //______________ // get the prefix keyspace for redelegations from a delegator -func GetREDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&delegatorAddr) - return append(RedelegationKey, res...) +func GetREDsKey(delegatorAddr sdk.Address) []byte { + return append(RedelegationKey, delegatorAddr.Bytes()...) } // get the prefix keyspace for all redelegations redelegating away from a source validator -func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&validatorSrcAddr) - return append(RedelegationByValSrcIndexKey, res...) +func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address) []byte { + return append(RedelegationByValSrcIndexKey, validatorSrcAddr.Bytes()...) } // get the prefix keyspace for all redelegations redelegating towards a destination validator -func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { - res := cdc.MustMarshalBinary(&validatorDstAddr) - return append(RedelegationByValDstIndexKey, res...) +func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address) []byte { + return append(RedelegationByValDstIndexKey, validatorDstAddr.Bytes()...) } // get the prefix keyspace for all redelegations redelegating towards a destination validator // from a particular delegator func GetREDsByDelToValDstIndexKey(delegatorAddr sdk.Address, - validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { + validatorDstAddr sdk.Address) []byte { return append( - GetREDsToValDstIndexKey(validatorDstAddr, cdc), + GetREDsToValDstIndexKey(validatorDstAddr), delegatorAddr.Bytes()...) } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 55ad658a2d..bedbc15591 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -34,7 +34,7 @@ func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, va iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) i := int64(0) for ; iterator.Valid(); iterator.Next() { - address := iterator.Value() + address := GetAddressFromValBondedIndexKey(iterator.Key()) validator, found := k.GetValidator(ctx, address) if !found { panic(fmt.Sprintf("validator record not found for address: %v\n", address)) @@ -87,7 +87,7 @@ func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.Address, addrVal sdk.Add // iterate through the active validator set and perform the provided function func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func(index int64, delegation sdk.Delegation) (stop bool)) { store := ctx.KVStore(k.storeKey) - key := GetDelegationsKey(delAddr, k.cdc) + key := GetDelegationsKey(delAddr) iterator := sdk.KVStorePrefixIterator(store, key) i := int64(0) for ; iterator.Valid(); iterator.Next() { diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 0d556f7dc4..c2711788be 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -56,7 +56,7 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida // validator index func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner) + store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{}) } // used in testing @@ -124,7 +124,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat if i > int(maxValidators-1) { panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated") } - address := iterator.Value() + address := GetAddressFromValBondedIndexKey(iterator.Key()) validator, found := k.GetValidator(ctx, address) if !found { panic(fmt.Sprintf("validator record not found for address: %v\n", address)) @@ -362,7 +362,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) { toKickOut := make(map[string]byte) iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) for ; iterator.Valid(); iterator.Next() { - ownerAddr := iterator.Value() + ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key()) toKickOut[string(ownerAddr)] = 0 // set anything } iterator.Close() @@ -471,7 +471,7 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. // save the now bonded validator record to the three referenced stores bzVal := k.cdc.MustMarshalBinary(validator) store.Set(GetValidatorKey(validator.Owner), bzVal) - store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner) + store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{}) // add to accumulated changes for tendermint bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) From f1194019cd295c20cc4a00fc3aa023c962b9e32c Mon Sep 17 00:00:00 2001 From: Yukai Tu Date: Wed, 4 Jul 2018 11:29:05 +0800 Subject: [PATCH 16/53] Merge PR #1534: Check new rat decimal string length --- docs/clients/ledger.md | 29 +++++++++++++++++++++++++++++ types/rational.go | 4 ++++ types/rational_test.go | 1 + 3 files changed, 34 insertions(+) create mode 100644 docs/clients/ledger.md diff --git a/docs/clients/ledger.md b/docs/clients/ledger.md new file mode 100644 index 0000000000..9f6386715d --- /dev/null +++ b/docs/clients/ledger.md @@ -0,0 +1,29 @@ +# Ledger // Cosmos + +### Ledger Support for account keys + +`gaiacli` now supports derivation of account keys from a Ledger seed. To use this functionality you will need the following: + +- A running `gaiad` instance connected to the network you wish to use. +- A `gaiacli` instance configured to connect to your chosen `gaiad` instance. +- A LedgerNano with the `ledger-cosmos` app installed + * Install the Cosmos app onto your Ledger by following the instructions in the [`ledger-cosmos`](https://github.com/cosmos/ledger-cosmos/blob/master/docs/BUILD.md) repository. + * A production-ready version of this app will soon be included in the [Ledger Apps Store](https://www.ledgerwallet.com/apps) + +> **NOTE:** Cosmos keys are derived acording to the [BIP 44 Hierarchical Deterministic wallet spec](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). For more information on Cosmos derivation paths [see the hd package](https://github.com/cosmos/cosmos-sdk/blob/develop/crypto/keys/hd/hdpath.go#L30). + +Once you have the Cosmos app installed on your Ledger, and the Ledger is accessible from the machine you are using `gaiacli` from you can create a new account key using the Ledger: + +```bash +$ gaiacli keys add {{ .Key.Name }} --ledger +NAME: TYPE: ADDRESS: PUBKEY: +{{ .Key.Name }} ledger cosmosaccaddr1aw64xxr80lwqqdk8u2xhlrkxqaxamkr3e2g943 cosmosaccpub1addwnpepqvhs678gh9aqrjc2tg2vezw86csnvgzqq530ujkunt5tkuc7lhjkz5mj629 +``` + +This key will only be accessible while the Ledger is plugged in and unlocked. To send some coins with this key, run the following: + +```bash +$ gaiacli send --name {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000 +``` + +You will be asked to review and confirm the transaction on the Ledger. Once you do this you should see the result in the console! Now you can use your Ledger to manage your Atoms and Stake! diff --git a/types/rational.go b/types/rational.go index ab400868d4..24072fc09e 100644 --- a/types/rational.go +++ b/types/rational.go @@ -41,6 +41,10 @@ func NewRat(Numerator int64, Denominator ...int64) Rat { // precision is the number of values after the decimal point which should be read func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) { // first extract any negative symbol + if len(decimalStr) == 0 { + return f, ErrUnknownRequest("decimal string is empty") + } + neg := false if string(decimalStr[0]) == "-" { neg = true diff --git a/types/rational_test.go b/types/rational_test.go index 3215313e09..ecbc09e881 100644 --- a/types/rational_test.go +++ b/types/rational_test.go @@ -27,6 +27,7 @@ func TestNewFromDecimal(t *testing.T) { expErr bool exp Rat }{ + {"", true, Rat{}}, {"0", false, NewRat(0)}, {"1", false, NewRat(1)}, {"1.1", false, NewRat(11, 10)}, From 199c1e81ebda231ae344e086f27654772be93284 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 3 Jul 2018 23:44:54 -0400 Subject: [PATCH 17/53] delegations new key format ported --- x/stake/client/cli/query.go | 7 +++---- x/stake/client/rest/query.go | 10 +++------- x/stake/keeper/delegation.go | 17 +++++++---------- x/stake/keeper/sdk_types.go | 4 +--- x/stake/types/delegation.go | 9 ++++----- 5 files changed, 18 insertions(+), 29 deletions(-) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 5a22f2c416..e66a3bb4d5 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/types" ) // get the command to query a validator @@ -130,7 +131,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { } // parse out the delegation - delegation := new(stake.Delegation) + delegation := types.UnmarshalDelegation(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -140,7 +141,6 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { } fmt.Println(resp) case "json": - cdc.MustUnmarshalBinary(res, delegation) output, err := wire.MarshalJSONIndent(cdc, delegation) if err != nil { return err @@ -179,8 +179,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { // parse out the validators var delegations []stake.Delegation for _, KV := range resKVs { - var delegation stake.Delegation - cdc.MustUnmarshalBinary(KV.Value, &delegation) + delegation := types.UnmarshalDelegation(cdc, KV.Key, KV.Value) delegations = append(delegations, delegation) } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 12ef882e5e..b19cea72b7 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -9,7 +9,9 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/types" ) const storeName = "stake" @@ -75,13 +77,7 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF return } - var delegation stake.Delegation - err = cdc.UnmarshalBinary(res, &delegation) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't decode delegation. Error: %s", err.Error()))) - return - } + delegation := types.UnmarshalDelegation(cdc, key, res) output, err := cdc.MarshalJSON(delegation) if err != nil { diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index bb8170a6a3..9c56b85125 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -12,12 +12,13 @@ func (k Keeper) GetDelegation(ctx sdk.Context, delegatorAddr, validatorAddr sdk.Address) (delegation types.Delegation, found bool) { store := ctx.KVStore(k.storeKey) - delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr)) - if delegatorBytes == nil { + key := GetDelegationKey(delegatorAddr, validatorAddr) + value := store.Get(key) + if value == nil { return delegation, false } - k.cdc.MustUnmarshalBinary(delegatorBytes, &delegation) + delegation = types.UnmarshalDelegation(k.cdc, key, value) return delegation, true } @@ -31,9 +32,7 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati if !iterator.Valid() { break } - bondBytes := iterator.Value() - var delegation types.Delegation - k.cdc.MustUnmarshalBinary(bondBytes, &delegation) + delegation := types.UnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) delegations = append(delegations, delegation) iterator.Next() } @@ -55,9 +54,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, if !iterator.Valid() || i > int(maxRetrieve-1) { break } - bondBytes := iterator.Value() - var delegation types.Delegation - k.cdc.MustUnmarshalBinary(bondBytes, &delegation) + delegation := types.UnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) delegations[i] = delegation iterator.Next() } @@ -68,7 +65,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, // set the delegation func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(delegation) + b := types.MarshalDelegation(k.cdc, delegation) store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b) } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index bedbc15591..9e45982b46 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -91,9 +91,7 @@ func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func iterator := sdk.KVStorePrefixIterator(store, key) i := int64(0) for ; iterator.Valid(); iterator.Next() { - bz := iterator.Value() - var delegation types.Delegation - k.cdc.MustUnmarshalBinary(bz, &delegation) + delegation := types.UnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to? if stop { break diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 705dcb6cd9..b6d35fb560 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -37,13 +37,12 @@ func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) Delegation { var storeValue delegationValue cdc.MustUnmarshalBinary(value, &storeValue) - addrs := IndexKey[1:] // remove prefix bytes - split := len(addrs) / 2 - if (len(addrs) % 2) != 0 { + addrs := key[1:] // remove prefix bytes + if len(addrs) != 40 { panic("key length not even") } - delAddr := sdk.Address{addrs[:split]} - valAddr := sdk.Address{addrs[split:]} + delAddr := sdk.Address(addrs[:20]) + valAddr := sdk.Address(addrs[20:]) return Delegation{ DelegatorAddr: delAddr, From 0b9e0f2afc2bf39257af101119727fd4afaafc99 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Wed, 4 Jul 2018 00:21:36 -0400 Subject: [PATCH 18/53] Merge PR #1492: Improve Module Test Coverage * Merge pull request #1492: Improve Module Test Coverage * Revert renaming of SignCheckDeliver [#1492] * Remove named fields from stake unit tests & fix comments [#1492] * update for tmlibs->tendermint/libs * Remove tmlibs dependency --- Gopkg.lock | 3 +- docs/core/app5.md | 2 +- examples/democoin/app/app_test.go | 4 +- examples/democoin/x/cool/app_test.go | 10 +- examples/democoin/x/pow/app_test.go | 2 +- x/auth/mock/app.go | 110 ------------ x/auth/mock/auth_app_test.go | 92 ---------- x/auth/mock/simulate_block.go | 110 ------------ x/bank/app_test.go | 2 +- x/bank/bench_test.go | 2 +- x/gov/msgs_test.go | 2 +- x/gov/test_common.go | 4 +- x/ibc/app_test.go | 2 +- x/mock/app.go | 168 ++++++++++++++++++ x/mock/app_test.go | 102 +++++++++++ x/mock/test_utils.go | 71 ++++++++ x/slashing/app_test.go | 10 +- x/stake/app_test.go | 118 ++++++------ x/stake/genesis.go | 34 ++-- x/stake/stake.go | 46 +++-- x/stake/types/delegation.go | 35 ++-- x/stake/types/delegation_test.go | 116 ++++++++++++ x/stake/types/errors.go | 27 ++- x/stake/types/msg_test.go | 32 +--- x/stake/types/params.go | 10 +- x/stake/types/params_test.go | 21 +++ x/stake/types/pool_test.go | 25 ++- x/stake/types/shares.go | 78 ++++---- x/stake/types/shares_test.go | 35 ++++ .../types/{test_common.go => test_utils.go} | 68 +++---- x/stake/types/validator.go | 98 ++++++---- x/stake/types/validator_test.go | 91 +++++++++- 32 files changed, 942 insertions(+), 588 deletions(-) delete mode 100644 x/auth/mock/app.go delete mode 100644 x/auth/mock/auth_app_test.go delete mode 100644 x/auth/mock/simulate_block.go create mode 100644 x/mock/app.go create mode 100644 x/mock/app_test.go create mode 100644 x/mock/test_utils.go create mode 100644 x/stake/types/delegation_test.go create mode 100644 x/stake/types/params_test.go create mode 100644 x/stake/types/shares_test.go rename x/stake/types/{test_common.go => test_utils.go} (84%) diff --git a/Gopkg.lock b/Gopkg.lock index a9b4a1f5cf..7a9b566965 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -137,6 +137,7 @@ ".", "hcl/ast", "hcl/parser", + "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -433,7 +434,7 @@ "netutil", "trace" ] - revision = "87b3feba568e144938625fc5d80ec92566c1a8fe" + revision = "ed29d75add3d7c4bf7ca65aac0c6df3d1420216f" [[projects]] branch = "master" diff --git a/docs/core/app5.md b/docs/core/app5.md index c6011f0425..39cc7a2637 100644 --- a/docs/core/app5.md +++ b/docs/core/app5.md @@ -59,7 +59,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application { Note we utilize the popular [cobra library](https://github.com/spf13/cobra) for the CLI, in concert with the [viper library](https://github.com/spf13/library) -for managing configuration. See our [cli library](https://github.com/tendermint/tmlibs/blob/master/cli/setup.go) +for managing configuration. See our [cli library](https://github.com/tendermint/blob/master/tmlibs/cli/setup.go) for more details. TODO: compile and run the binary diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index a642eff72d..60005713ef 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -4,14 +4,12 @@ import ( "os" "testing" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/examples/democoin/types" "github.com/cosmos/cosmos-sdk/examples/democoin/x/cool" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" - + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tendermint/libs/db" diff --git a/examples/democoin/x/cool/app_test.go b/examples/democoin/x/cool/app_test.go index e93f6d99c5..df5786a043 100644 --- a/examples/democoin/x/cool/app_test.go +++ b/examples/democoin/x/cool/app_test.go @@ -3,15 +3,13 @@ package cool import ( "testing" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/mock" bank "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/mock" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" ) var ( diff --git a/examples/democoin/x/pow/app_test.go b/examples/democoin/x/pow/app_test.go index d223a1f107..076dc20bc6 100644 --- a/examples/democoin/x/pow/app_test.go +++ b/examples/democoin/x/pow/app_test.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/mock" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" diff --git a/x/auth/mock/app.go b/x/auth/mock/app.go deleted file mode 100644 index 758b1efab8..0000000000 --- a/x/auth/mock/app.go +++ /dev/null @@ -1,110 +0,0 @@ -package mock - -import ( - "os" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/libs/log" - - bam "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" - "github.com/cosmos/cosmos-sdk/x/auth" -) - -// Extended ABCI application -type App struct { - *bam.BaseApp - Cdc *wire.Codec // public since the codec is passed into the module anyways. - KeyMain *sdk.KVStoreKey - KeyAccount *sdk.KVStoreKey - - // TODO: Abstract this out from not needing to be auth specifically - AccountMapper auth.AccountMapper - FeeCollectionKeeper auth.FeeCollectionKeeper - - GenesisAccounts []auth.Account -} - -// partially construct a new app on the memstore for module and genesis testing -func NewApp() *App { - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") - db := dbm.NewMemDB() - - // create the cdc with some standard codecs - cdc := wire.NewCodec() - sdk.RegisterWire(cdc) - wire.RegisterCrypto(cdc) - auth.RegisterWire(cdc) - - // create your application object - app := &App{ - BaseApp: bam.NewBaseApp("mock", cdc, logger, db), - Cdc: cdc, - KeyMain: sdk.NewKVStoreKey("main"), - KeyAccount: sdk.NewKVStoreKey("acc"), - } - - // define the accountMapper - app.AccountMapper = auth.NewAccountMapper( - app.Cdc, - app.KeyAccount, // target store - &auth.BaseAccount{}, // prototype - ) - - // initialize the app, the chainers and blockers can be overwritten before calling complete setup - app.SetInitChainer(app.InitChainer) - - app.SetAnteHandler(auth.NewAnteHandler(app.AccountMapper, app.FeeCollectionKeeper)) - - return app -} - -// complete the application setup after the routes have been registered -func (app *App) CompleteSetup(newKeys []*sdk.KVStoreKey) error { - newKeys = append(newKeys, app.KeyMain) - newKeys = append(newKeys, app.KeyAccount) - app.MountStoresIAVL(newKeys...) - err := app.LoadLatestVersion(app.KeyMain) - return err -} - -// custom logic for initialization -func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain { - - // load the accounts - for _, genacc := range app.GenesisAccounts { - acc := app.AccountMapper.NewAccountWithAddress(ctx, genacc.GetAddress()) - err := acc.SetCoins(genacc.GetCoins()) - if err != nil { - // TODO: Handle with #870 - panic(err) - } - app.AccountMapper.SetAccount(ctx, acc) - } - - return abci.ResponseInitChain{} -} - -// Generate genesis accounts loaded with coins, and returns their addresses, pubkeys, and privkeys -func CreateGenAccounts(numAccs int64, genCoins sdk.Coins) (genAccs []auth.Account, addrs []sdk.Address, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) { - for i := int64(0); i < numAccs; i++ { - privKey := crypto.GenPrivKeyEd25519() - pubKey := privKey.PubKey() - addr := pubKey.Address() - - genAcc := &auth.BaseAccount{ - Address: addr, - Coins: genCoins, - } - - genAccs = append(genAccs, genAcc) - privKeys = append(privKeys, privKey) - pubKeys = append(pubKeys, pubKey) - addrs = append(addrs, addr) - } - - return -} diff --git a/x/auth/mock/auth_app_test.go b/x/auth/mock/auth_app_test.go deleted file mode 100644 index 3f340bbf90..0000000000 --- a/x/auth/mock/auth_app_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package mock - -import ( - "testing" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" -) - -// A mock transaction that has a validation which can fail. -type testMsg struct { - signers []sdk.Address - positiveNum int64 -} - -// TODO: Clean this up, make it public -const msgType = "testMsg" - -func (tx testMsg) Type() string { return msgType } -func (tx testMsg) GetMsg() sdk.Msg { return tx } -func (tx testMsg) GetMemo() string { return "" } -func (tx testMsg) GetSignBytes() []byte { return nil } -func (tx testMsg) GetSigners() []sdk.Address { return tx.signers } -func (tx testMsg) GetSignatures() []auth.StdSignature { return nil } -func (tx testMsg) ValidateBasic() sdk.Error { - if tx.positiveNum >= 0 { - return nil - } - return sdk.ErrTxDecode("positiveNum should be a non-negative integer.") -} - -// test auth module messages - -var ( - priv1 = crypto.GenPrivKeyEd25519() - addr1 = priv1.PubKey().Address() - priv2 = crypto.GenPrivKeyEd25519() - addr2 = priv2.PubKey().Address() - - coins = sdk.Coins{sdk.NewCoin("foocoin", 10)} - testMsg1 = testMsg{signers: []sdk.Address{addr1}, positiveNum: 1} -) - -// initialize the mock application for this module -func getMockApp(t *testing.T) *App { - mapp := NewApp() - - mapp.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) - require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{})) - return mapp -} - -func TestMsgPrivKeys(t *testing.T) { - mapp := getMockApp(t) - mapp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) - - // Construct some genesis bytes to reflect basecoin/types/AppAccount - // Give 77 foocoin to the first key - coins := sdk.Coins{sdk.NewCoin("foocoin", 77)} - acc1 := &auth.BaseAccount{ - Address: addr1, - Coins: coins, - } - accs := []auth.Account{acc1} - - // Construct genesis state - SetGenesis(mapp, accs) - - // A checkTx context (true) - ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) - require.Equal(t, acc1, res1.(*auth.BaseAccount)) - - // Run a CheckDeliver - SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{0}, true, priv1) - - // signing a SendMsg with the wrong privKey should be an auth error - mapp.BeginBlock(abci.RequestBeginBlock{}) - tx := GenTx([]sdk.Msg{testMsg1}, []int64{0}, []int64{1}, priv2) - res := mapp.Deliver(tx) - require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) - - // resigning the tx with the correct priv key should still work - res = SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{1}, true, priv1) - - require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), res.Code, res.Log) -} diff --git a/x/auth/mock/simulate_block.go b/x/auth/mock/simulate_block.go deleted file mode 100644 index f85fdf1803..0000000000 --- a/x/auth/mock/simulate_block.go +++ /dev/null @@ -1,110 +0,0 @@ -package mock - -import ( - "testing" - - "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto" - - abci "github.com/tendermint/tendermint/abci/types" -) - -var chainID = "" // TODO - -// set the mock app genesis -func SetGenesis(app *App, accs []auth.Account) { - - // pass the accounts in via the application (lazy) instead of through RequestInitChain - app.GenesisAccounts = accs - - app.InitChain(abci.RequestInitChain{}) - app.Commit() -} - -// check an account balance -func CheckBalance(t *testing.T, app *App, addr sdk.Address, exp sdk.Coins) { - ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) - res := app.AccountMapper.GetAccount(ctxCheck, addr) - require.Equal(t, exp, res.GetCoins()) -} - -// generate a signed transaction -func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyEd25519) auth.StdTx { - - // make the transaction free - fee := auth.StdFee{ - sdk.Coins{sdk.NewCoin("foocoin", 0)}, - 100000, - } - - sigs := make([]auth.StdSignature, len(priv)) - memo := "testmemotestmemo" - for i, p := range priv { - sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo)) - if err != nil { - panic(err) - } - sigs[i] = auth.StdSignature{ - PubKey: p.PubKey(), - Signature: sig, - AccountNumber: accnums[i], - Sequence: seq[i], - } - } - return auth.NewStdTx(msgs, fee, sigs, memo) -} - -// generate a set of signed transactions a msg, that differ only by having the -// sequence numbers incremented between every transaction. -func GenSequenceOfTxs(msgs []sdk.Msg, accnums []int64, initSeqNums []int64, numToGenerate int, priv ...crypto.PrivKeyEd25519) []auth.StdTx { - txs := make([]auth.StdTx, numToGenerate, numToGenerate) - for i := 0; i < numToGenerate; i++ { - txs[i] = GenTx(msgs, accnums, initSeqNums, priv...) - incrementAllSequenceNumbers(initSeqNums) - } - return txs -} - -func incrementAllSequenceNumbers(initSeqNums []int64) { - for i := 0; i < len(initSeqNums); i++ { - initSeqNums[i]++ - } -} - -// check a transaction result -func SignCheck(app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.Result { - tx := GenTx(msgs, accnums, seq, priv...) - res := app.Check(tx) - return res -} - -// simulate a block -func SignCheckDeliver(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) sdk.Result { - - // Sign the tx - tx := GenTx(msgs, accnums, seq, priv...) - - // Run a Check - res := app.Check(tx) - if expPass { - require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) - } else { - require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) - } - - // Simulate a Block - app.BeginBlock(abci.RequestBeginBlock{}) - res = app.Deliver(tx) - if expPass { - require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) - } else { - require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) - } - app.EndBlock(abci.RequestEndBlock{}) - - app.Commit() - return res -} diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 72ea312a9a..425e9aa2d9 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/mock" + "github.com/cosmos/cosmos-sdk/x/mock" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index dce4d8fa95..be8319f9fd 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/mock" + "github.com/cosmos/cosmos-sdk/x/mock" abci "github.com/tendermint/tendermint/abci/types" ) diff --git a/x/gov/msgs_test.go b/x/gov/msgs_test.go index e9be4ded3d..d0a6292997 100644 --- a/x/gov/msgs_test.go +++ b/x/gov/msgs_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/mock" + "github.com/cosmos/cosmos-sdk/x/mock" ) var ( diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 743c5b6392..70e47e86d7 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -12,13 +12,13 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/stake" ) // initialize the mock application for this module -func getMockApp(t *testing.T, numGenAccs int64) (*mock.App, Keeper, stake.Keeper, []sdk.Address, []crypto.PubKey, []crypto.PrivKey) { +func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper, []sdk.Address, []crypto.PubKey, []crypto.PrivKey) { mapp := mock.NewApp() stake.RegisterWire(mapp.Cdc) diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go index 1540bf2ed8..3671cd3e19 100644 --- a/x/ibc/app_test.go +++ b/x/ibc/app_test.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/mock" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" diff --git a/x/mock/app.go b/x/mock/app.go new file mode 100644 index 0000000000..e16a322688 --- /dev/null +++ b/x/mock/app.go @@ -0,0 +1,168 @@ +package mock + +import ( + "os" + + bam "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" +) + +const chainID = "" + +// App extends an ABCI application. +type App struct { + *bam.BaseApp + Cdc *wire.Codec // Cdc is public since the codec is passed into the module anyways + KeyMain *sdk.KVStoreKey + KeyAccount *sdk.KVStoreKey + + // TODO: Abstract this out from not needing to be auth specifically + AccountMapper auth.AccountMapper + FeeCollectionKeeper auth.FeeCollectionKeeper + + GenesisAccounts []auth.Account +} + +// NewApp partially constructs a new app on the memstore for module and genesis +// testing. +func NewApp() *App { + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") + db := dbm.NewMemDB() + + // Create the cdc with some standard codecs + cdc := wire.NewCodec() + sdk.RegisterWire(cdc) + wire.RegisterCrypto(cdc) + auth.RegisterWire(cdc) + + // Create your application object + app := &App{ + BaseApp: bam.NewBaseApp("mock", cdc, logger, db), + Cdc: cdc, + KeyMain: sdk.NewKVStoreKey("main"), + KeyAccount: sdk.NewKVStoreKey("acc"), + } + + // Define the accountMapper + app.AccountMapper = auth.NewAccountMapper( + app.Cdc, + app.KeyAccount, + &auth.BaseAccount{}, + ) + + // Initialize the app. The chainers and blockers can be overwritten before + // calling complete setup. + app.SetInitChainer(app.InitChainer) + app.SetAnteHandler(auth.NewAnteHandler(app.AccountMapper, app.FeeCollectionKeeper)) + + return app +} + +// CompleteSetup completes the application setup after the routes have been +// registered. +func (app *App) CompleteSetup(newKeys []*sdk.KVStoreKey) error { + newKeys = append(newKeys, app.KeyMain) + newKeys = append(newKeys, app.KeyAccount) + + app.MountStoresIAVL(newKeys...) + err := app.LoadLatestVersion(app.KeyMain) + + return err +} + +// InitChainer performs custom logic for initialization. +func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain { + // Load the genesis accounts + for _, genacc := range app.GenesisAccounts { + acc := app.AccountMapper.NewAccountWithAddress(ctx, genacc.GetAddress()) + acc.SetCoins(genacc.GetCoins()) + app.AccountMapper.SetAccount(ctx, acc) + } + + return abci.ResponseInitChain{} +} + +// CreateGenAccounts generates genesis accounts loaded with coins, and returns +// their addresses, pubkeys, and privkeys. +func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []auth.Account, addrs []sdk.Address, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) { + for i := 0; i < numAccs; i++ { + privKey := crypto.GenPrivKeyEd25519() + pubKey := privKey.PubKey() + addr := pubKey.Address() + + genAcc := &auth.BaseAccount{ + Address: addr, + Coins: genCoins, + } + + genAccs = append(genAccs, genAcc) + privKeys = append(privKeys, privKey) + pubKeys = append(pubKeys, pubKey) + addrs = append(addrs, addr) + } + + return +} + +// SetGenesis sets the mock app genesis accounts. +func SetGenesis(app *App, accs []auth.Account) { + // Pass the accounts in via the application (lazy) instead of through + // RequestInitChain. + app.GenesisAccounts = accs + + app.InitChain(abci.RequestInitChain{}) + app.Commit() +} + +// GenTx generates a signed mock transaction. +func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx { + // Make the transaction free + fee := auth.StdFee{ + sdk.Coins{sdk.NewCoin("foocoin", 0)}, + 100000, + } + + sigs := make([]auth.StdSignature, len(priv)) + memo := "testmemotestmemo" + + for i, p := range priv { + sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo)) + if err != nil { + panic(err) + } + + sigs[i] = auth.StdSignature{ + PubKey: p.PubKey(), + Signature: sig, + AccountNumber: accnums[i], + Sequence: seq[i], + } + } + + return auth.NewStdTx(msgs, fee, sigs, memo) +} + +// GenSequenceOfTxs generates a set of signed transactions of messages, such +// that they differ only by having the sequence numbers incremented between +// every transaction. +func GenSequenceOfTxs(msgs []sdk.Msg, accnums []int64, initSeqNums []int64, numToGenerate int, priv ...crypto.PrivKey) []auth.StdTx { + txs := make([]auth.StdTx, numToGenerate, numToGenerate) + for i := 0; i < numToGenerate; i++ { + txs[i] = GenTx(msgs, accnums, initSeqNums, priv...) + incrementAllSequenceNumbers(initSeqNums) + } + + return txs +} + +func incrementAllSequenceNumbers(initSeqNums []int64) { + for i := 0; i < len(initSeqNums); i++ { + initSeqNums[i]++ + } +} diff --git a/x/mock/app_test.go b/x/mock/app_test.go new file mode 100644 index 0000000000..7ee82474ce --- /dev/null +++ b/x/mock/app_test.go @@ -0,0 +1,102 @@ +package mock + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" +) + +const msgType = "testMsg" + +var ( + numAccts = 2 + genCoins = sdk.Coins{sdk.NewCoin("foocoin", 77)} + accs, addrs, pubKeys, privKeys = CreateGenAccounts(numAccts, genCoins) +) + +// testMsg is a mock transaction that has a validation which can fail. +type testMsg struct { + signers []sdk.Address + positiveNum int64 +} + +func (tx testMsg) Type() string { return msgType } +func (tx testMsg) GetMsg() sdk.Msg { return tx } +func (tx testMsg) GetMemo() string { return "" } +func (tx testMsg) GetSignBytes() []byte { return nil } +func (tx testMsg) GetSigners() []sdk.Address { return tx.signers } +func (tx testMsg) GetSignatures() []auth.StdSignature { return nil } +func (tx testMsg) ValidateBasic() sdk.Error { + if tx.positiveNum >= 0 { + return nil + } + return sdk.ErrTxDecode("positiveNum should be a non-negative integer.") +} + +// getMockApp returns an initialized mock application. +func getMockApp(t *testing.T) *App { + mApp := NewApp() + + mApp.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) + require.NoError(t, mApp.CompleteSetup([]*sdk.KVStoreKey{})) + + return mApp +} + +func TestCheckAndDeliverGenTx(t *testing.T) { + mApp := getMockApp(t) + mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) + + SetGenesis(mApp, accs) + ctxCheck := mApp.BaseApp.NewContext(true, abci.Header{}) + + msg := testMsg{signers: []sdk.Address{addrs[0]}, positiveNum: 1} + + acct := mApp.AccountMapper.GetAccount(ctxCheck, addrs[0]) + require.Equal(t, accs[0], acct.(*auth.BaseAccount)) + + SignCheckDeliver( + t, mApp.BaseApp, []sdk.Msg{msg}, + []int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()}, + true, privKeys[0], + ) + + // Signing a tx with the wrong privKey should result in an auth error + res := SignCheckDeliver( + t, mApp.BaseApp, []sdk.Msg{msg}, + []int64{accs[1].GetAccountNumber()}, []int64{accs[1].GetSequence() + 1}, + false, privKeys[1], + ) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) + + // Resigning the tx with the correct privKey should result in an OK result + SignCheckDeliver( + t, mApp.BaseApp, []sdk.Msg{msg}, + []int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence() + 1}, + true, privKeys[0], + ) +} + +func TestCheckGenTx(t *testing.T) { + mApp := getMockApp(t) + mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) + + SetGenesis(mApp, accs) + + msg1 := testMsg{signers: []sdk.Address{addrs[0]}, positiveNum: 1} + CheckGenTx( + t, mApp.BaseApp, []sdk.Msg{msg1}, + []int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()}, + true, privKeys[0], + ) + + msg2 := testMsg{signers: []sdk.Address{addrs[0]}, positiveNum: -1} + CheckGenTx( + t, mApp.BaseApp, []sdk.Msg{msg2}, + []int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()}, + false, privKeys[0], + ) +} diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go new file mode 100644 index 0000000000..f9620c1403 --- /dev/null +++ b/x/mock/test_utils.go @@ -0,0 +1,71 @@ +package mock + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" +) + +// CheckBalance checks the balance of an account. +func CheckBalance(t *testing.T, app *App, addr sdk.Address, exp sdk.Coins) { + ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) + res := app.AccountMapper.GetAccount(ctxCheck, addr) + + require.Equal(t, exp, res.GetCoins()) +} + +// CheckGenTx checks a generated signed transaction. The result of the check is +// compared against the parameter 'expPass'. A test assertion is made using the +// parameter 'expPass' against the result. A corresponding result is returned. +func CheckGenTx( + t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []int64, + seq []int64, expPass bool, priv ...crypto.PrivKey, +) sdk.Result { + tx := GenTx(msgs, accNums, seq, priv...) + res := app.Check(tx) + + if expPass { + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) + } else { + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) + } + + return res +} + +// SignCheckDeliver checks a generated signed transaction and simulates a +// block commitment with the given transaction. A test assertion is made using +// the parameter 'expPass' against the result. A corresponding result is +// returned. +func SignCheckDeliver( + t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []int64, + seq []int64, expPass bool, priv ...crypto.PrivKey, +) sdk.Result { + tx := GenTx(msgs, accNums, seq, priv...) + res := app.Check(tx) + + if expPass { + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) + } else { + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) + } + + // Simulate a sending a transaction and committing a block + app.BeginBlock(abci.RequestBeginBlock{}) + res = app.Deliver(tx) + + if expPass { + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) + } else { + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) + } + + app.EndBlock(abci.RequestEndBlock{}) + app.Commit() + + return res +} diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index a64d3eb0f1..d6fb0d9fe8 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -5,11 +5,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/stretchr/testify/require" - + "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" ) @@ -103,10 +102,9 @@ func TestSlashingMsgs(t *testing.T) { require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) unrevokeMsg := MsgUnrevoke{ValidatorAddr: validator.PubKey.Address()} - // no signing info yet checkValidatorSigningInfo(t, mapp, keeper, addr1, false) - // unrevoke should fail with validator not revoked - res := mock.SignCheck(mapp.BaseApp, []sdk.Msg{unrevokeMsg}, []int64{0}, []int64{1}, priv1) + // unrevoke should fail with unknown validator + res := mock.CheckGenTx(t, mapp.BaseApp, []sdk.Msg{unrevokeMsg}, []int64{0}, []int64{1}, false, priv1) require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotRevoked), res.Code) } diff --git a/x/stake/app_test.go b/x/stake/app_test.go index d4fc5bdf00..02dd091341 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -5,11 +5,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/stretchr/testify/assert" + "github.com/cosmos/cosmos-sdk/x/mock" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" ) @@ -22,81 +20,86 @@ var ( addr3 = crypto.GenPrivKeyEd25519().PubKey().Address() priv4 = crypto.GenPrivKeyEd25519() addr4 = priv4.PubKey().Address() - coins = sdk.Coins{{"foocoin", sdk.NewInt(10)}} - fee = auth.StdFee{ - sdk.Coins{{"foocoin", sdk.NewInt(0)}}, - 100000, - } + coins = sdk.NewCoin("foocoin", 10) + fee = auth.StdFee{sdk.Coins{sdk.NewCoin("foocoin", 0)}, 100000} ) -// initialize the mock application for this module +// getMockApp returns an initialized mock application for this module. func getMockApp(t *testing.T) (*mock.App, Keeper) { - mapp := mock.NewApp() + mApp := mock.NewApp() + + RegisterWire(mApp.Cdc) - RegisterWire(mapp.Cdc) keyStake := sdk.NewKVStoreKey("stake") - coinKeeper := bank.NewKeeper(mapp.AccountMapper) - keeper := NewKeeper(mapp.Cdc, keyStake, coinKeeper, mapp.RegisterCodespace(DefaultCodespace)) - mapp.Router().AddRoute("stake", NewHandler(keeper)) + coinKeeper := bank.NewKeeper(mApp.AccountMapper) + keeper := NewKeeper(mApp.Cdc, keyStake, coinKeeper, mApp.RegisterCodespace(DefaultCodespace)) - mapp.SetEndBlocker(getEndBlocker(keeper)) - mapp.SetInitChainer(getInitChainer(mapp, keeper)) + mApp.Router().AddRoute("stake", NewHandler(keeper)) + mApp.SetEndBlocker(getEndBlocker(keeper)) + mApp.SetInitChainer(getInitChainer(mApp, keeper)) - require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake})) - return mapp, keeper + require.NoError(t, mApp.CompleteSetup([]*sdk.KVStoreKey{keyStake})) + return mApp, keeper } -// stake endblocker +// getEndBlocker returns a stake endblocker. func getEndBlocker(keeper Keeper) sdk.EndBlocker { return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { validatorUpdates := EndBlocker(ctx, keeper) + return abci.ResponseEndBlock{ ValidatorUpdates: validatorUpdates, } } } -// overwrite the mock init chainer +// getInitChainer initializes the chainer of the mock app and sets the genesis +// state. It returns an empty ResponseInitChain. func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) + stakeGenesis := DefaultGenesisState() stakeGenesis.Pool.LooseTokens = 100000 + InitGenesis(ctx, keeper, stakeGenesis) return abci.ResponseInitChain{} } } -//__________________________________________________________________________________________ - -func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, - addr sdk.Address, expFound bool) Validator { - +func checkValidator( + t *testing.T, mapp *mock.App, keeper Keeper, + addr sdk.Address, expFound bool, +) Validator { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) validator, found := keeper.GetValidator(ctxCheck, addr1) + require.Equal(t, expFound, found) return validator } -func checkDelegation(t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr, - validatorAddr sdk.Address, expFound bool, expShares sdk.Rat) { - +func checkDelegation( + t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr, + validatorAddr sdk.Address, expFound bool, expShares sdk.Rat, +) { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr) if expFound { require.True(t, found) - assert.True(sdk.RatEq(t, expShares, delegation.Shares)) + require.True(sdk.RatEq(t, expShares, delegation.Shares)) + return } + require.False(t, found) } func TestStakeMsgs(t *testing.T) { - mapp, keeper := getMockApp(t) + mApp, keeper := getMockApp(t) - genCoin := sdk.Coin{"steak", sdk.NewInt(42)} - bondCoin := sdk.Coin{"steak", sdk.NewInt(10)} + genCoin := sdk.NewCoin("steak", 42) + bondCoin := sdk.NewCoin("steak", 10) acc1 := &auth.BaseAccount{ Address: addr1, @@ -108,56 +111,51 @@ func TestStakeMsgs(t *testing.T) { } accs := []auth.Account{acc1, acc2} - mock.SetGenesis(mapp, accs) - mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin}) - mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin}) - - //////////////////// - // Create Validator + mock.SetGenesis(mApp, accs) + mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin}) + mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) + // create validator description := NewDescription("foo_moniker", "", "", "") createValidatorMsg := NewMsgCreateValidator( addr1, priv1.PubKey(), bondCoin, description, ) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1) - mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Minus(bondCoin)}) - mapp.BeginBlock(abci.RequestBeginBlock{}) - validator := checkValidator(t, mapp, keeper, addr1, true) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1) + mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin)}) + mApp.BeginBlock(abci.RequestBeginBlock{}) + + validator := checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, addr1, validator.Owner) require.Equal(t, sdk.Bonded, validator.Status()) require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) // check the bond that should have been created as well - checkDelegation(t, mapp, keeper, addr1, addr1, true, sdk.NewRat(10)) - - //////////////////// - // Edit Validator + checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10)) + // edit the validator description = NewDescription("bar_moniker", "", "", "") editValidatorMsg := NewMsgEditValidator(addr1, description) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{1}, true, priv1) - validator = checkValidator(t, mapp, keeper, addr1, true) + + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{1}, true, priv1) + validator = checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, description, validator.Description) - //////////////////// - // Delegate - - mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin}) + // delegate + mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) delegateMsg := NewMsgDelegate(addr2, addr1, bondCoin) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{0}, true, priv2) - mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) - checkDelegation(t, mapp, keeper, addr2, addr1, true, sdk.NewRat(10)) - //////////////////// - // Begin Unbonding + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{0}, true, priv2) + mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) + checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewRat(10)) + // begin unbonding beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10)) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{1}, true, priv2) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{1}, true, priv2) // delegation should exist anymore - checkDelegation(t, mapp, keeper, addr2, addr1, false, sdk.Rat{}) + checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Rat{}) // balance should be the same because bonding not yet complete - mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) + mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) } diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 55dd06f76f..1116a4748d 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -1,50 +1,58 @@ package stake import ( - tmtypes "github.com/tendermint/tendermint/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" + tmtypes "github.com/tendermint/tendermint/types" ) -// InitGenesis - store genesis parameters +// InitGenesis sets the pool and parameters for the provided keeper and +// initializes the IntraTxCounter. For each validator in data, it sets that +// validator in the keeper along with manually setting the indexes. In +// addition, it also sets any delegations found in data. Finally, it updates +// the bonded validators. func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) { keeper.SetPool(ctx, data.Pool) keeper.SetNewParams(ctx, data.Params) keeper.InitIntraTxCounter(ctx) - for _, validator := range data.Validators { - // set validator + for _, validator := range data.Validators { keeper.SetValidator(ctx, validator) - // manually set indexes for the first time + // Manually set indexes for the first time keeper.SetValidatorByPubKeyIndex(ctx, validator) keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool) + if validator.Status() == sdk.Bonded { keeper.SetValidatorBondedIndex(ctx, validator) } } + for _, bond := range data.Bonds { keeper.SetDelegation(ctx, bond) } + keeper.UpdateBondedValidatorsFull(ctx) } -// WriteGenesis - output genesis parameters +// WriteGenesis returns a GenesisState for a given context and keeper. The +// GenesisState will contain the pool, params, validators, and bonds found in +// the keeper. func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { pool := keeper.GetPool(ctx) params := keeper.GetParams(ctx) validators := keeper.GetAllValidators(ctx) bonds := keeper.GetAllDelegations(ctx) + return types.GenesisState{ - pool, - params, - validators, - bonds, + Pool: pool, + Params: params, + Validators: validators, + Bonds: bonds, } } -// WriteValidators - output current validator set +// WriteValidators returns a slice of bonded genesis validators. func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisValidator) { keeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { vals = append(vals, tmtypes.GenesisValidator{ @@ -52,7 +60,9 @@ func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisVali Power: validator.GetPower().RoundInt64(), Name: validator.GetMoniker(), }) + return false }) + return } diff --git a/x/stake/stake.go b/x/stake/stake.go index 5e4356b814..869b838ffa 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -7,30 +7,29 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake/types" ) -// keeper -type Keeper = keeper.Keeper - -var NewKeeper = keeper.NewKeeper - -// types -type Validator = types.Validator -type Description = types.Description -type Delegation = types.Delegation -type UnbondingDelegation = types.UnbondingDelegation -type Redelegation = types.Redelegation -type Params = types.Params -type Pool = types.Pool -type PoolShares = types.PoolShares -type MsgCreateValidator = types.MsgCreateValidator -type MsgEditValidator = types.MsgEditValidator -type MsgDelegate = types.MsgDelegate -type MsgBeginUnbonding = types.MsgBeginUnbonding -type MsgCompleteUnbonding = types.MsgCompleteUnbonding -type MsgBeginRedelegate = types.MsgBeginRedelegate -type MsgCompleteRedelegate = types.MsgCompleteRedelegate -type GenesisState = types.GenesisState +type ( + Keeper = keeper.Keeper + Validator = types.Validator + Description = types.Description + Delegation = types.Delegation + UnbondingDelegation = types.UnbondingDelegation + Redelegation = types.Redelegation + Params = types.Params + Pool = types.Pool + PoolShares = types.PoolShares + MsgCreateValidator = types.MsgCreateValidator + MsgEditValidator = types.MsgEditValidator + MsgDelegate = types.MsgDelegate + MsgBeginUnbonding = types.MsgBeginUnbonding + MsgCompleteUnbonding = types.MsgCompleteUnbonding + MsgBeginRedelegate = types.MsgBeginRedelegate + MsgCompleteRedelegate = types.MsgCompleteRedelegate + GenesisState = types.GenesisState +) var ( + NewKeeper = keeper.NewKeeper + GetValidatorKey = keeper.GetValidatorKey GetValidatorByPubKeyIndexKey = keeper.GetValidatorByPubKeyIndexKey GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey @@ -72,7 +71,6 @@ var ( DefaultGenesisState = types.DefaultGenesisState RegisterWire = types.RegisterWire - // messages NewMsgCreateValidator = types.NewMsgCreateValidator NewMsgEditValidator = types.NewMsgEditValidator NewMsgDelegate = types.NewMsgDelegate @@ -82,7 +80,6 @@ var ( NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate ) -// errors const ( DefaultCodespace = types.DefaultCodespace CodeInvalidValidator = types.CodeInvalidValidator @@ -126,7 +123,6 @@ var ( ErrMissingSignature = types.ErrMissingSignature ) -// tags var ( ActionCreateValidator = tags.ActionCreateValidator ActionEditValidator = tags.ActionEditValidator diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index eb38a50a7a..a7d0a1f8c5 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -17,7 +17,7 @@ type Delegation struct { Height int64 `json:"height"` // Last height bond updated } -// two are equal +// Equal returns a boolean determining if two Delegation types are identical. func (d Delegation) Equal(d2 Delegation) bool { return bytes.Equal(d.DelegatorAddr, d2.DelegatorAddr) && bytes.Equal(d.ValidatorAddr, d2.ValidatorAddr) && @@ -33,16 +33,20 @@ func (d Delegation) GetDelegator() sdk.Address { return d.DelegatorAddr } func (d Delegation) GetValidator() sdk.Address { return d.ValidatorAddr } func (d Delegation) GetBondShares() sdk.Rat { return d.Shares } -//Human Friendly pretty printer +// HumanReadableString returns a human readable string representation of a +// Delegation. An error is returned if the Delegation's delegator or validator +// addresses cannot be Bech32 encoded. func (d Delegation) HumanReadableString() (string, error) { bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr) if err != nil { return "", err } + bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr) if err != nil { return "", err } + resp := "Delegation \n" resp += fmt.Sprintf("Delegator: %s\n", bechAcc) resp += fmt.Sprintf("Validator: %s\n", bechVal) @@ -50,12 +54,9 @@ func (d Delegation) HumanReadableString() (string, error) { resp += fmt.Sprintf("Height: %d", d.Height) return resp, nil - } -//__________________________________________________________________ - -// element stored to represent the passive unbonding queue +// UnbondingDelegation reflects a delegation's passive unbonding queue. type UnbondingDelegation struct { DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr @@ -65,23 +66,28 @@ type UnbondingDelegation struct { Balance sdk.Coin `json:"balance"` // atoms to receive at completion } -// nolint +// Equal returns a boolean determining if two UnbondingDelegation types are +// identical. func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { bz1 := MsgCdc.MustMarshalBinary(&d) bz2 := MsgCdc.MustMarshalBinary(&d2) return bytes.Equal(bz1, bz2) } -//Human Friendly pretty printer +// HumanReadableString returns a human readable string representation of an +// UnbondingDelegation. An error is returned if the UnbondingDelegation's +// delegator or validator addresses cannot be Bech32 encoded. func (d UnbondingDelegation) HumanReadableString() (string, error) { bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr) if err != nil { return "", err } + bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr) if err != nil { return "", err } + resp := "Unbonding Delegation \n" resp += fmt.Sprintf("Delegator: %s\n", bechAcc) resp += fmt.Sprintf("Validator: %s\n", bechVal) @@ -93,9 +99,7 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) { } -//__________________________________________________________________ - -// element stored to represent the passive redelegation queue +// Redelegation reflects a delegation's passive re-delegation queue. type Redelegation struct { DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator ValidatorSrcAddr sdk.Address `json:"validator_src_addr"` // validator redelegation source owner addr @@ -108,27 +112,32 @@ type Redelegation struct { SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating } -// nolint +// Equal returns a boolean determining if two Redelegation types are identical. func (d Redelegation) Equal(d2 Redelegation) bool { bz1 := MsgCdc.MustMarshalBinary(&d) bz2 := MsgCdc.MustMarshalBinary(&d2) return bytes.Equal(bz1, bz2) } -//Human Friendly pretty printer +// HumanReadableString returns a human readable string representation of a +// Redelegation. An error is returned if the UnbondingDelegation's delegator or +// validator addresses cannot be Bech32 encoded. func (d Redelegation) HumanReadableString() (string, error) { bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr) if err != nil { return "", err } + bechValSrc, err := sdk.Bech32ifyAcc(d.ValidatorSrcAddr) if err != nil { return "", err } + bechValDst, err := sdk.Bech32ifyAcc(d.ValidatorDstAddr) if err != nil { return "", err } + resp := "Redelegation \n" resp += fmt.Sprintf("Delegator: %s\n", bechAcc) resp += fmt.Sprintf("Source Validator: %s\n", bechValSrc) diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go new file mode 100644 index 0000000000..640f5d9791 --- /dev/null +++ b/x/stake/types/delegation_test.go @@ -0,0 +1,116 @@ +package types + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestDelegationEqual(t *testing.T) { + d1 := Delegation{ + DelegatorAddr: addr1, + ValidatorAddr: addr2, + Shares: sdk.NewRat(100), + } + d2 := Delegation{ + DelegatorAddr: addr1, + ValidatorAddr: addr2, + Shares: sdk.NewRat(100), + } + + ok := d1.Equal(d2) + require.True(t, ok) + + d2.ValidatorAddr = addr3 + d2.Shares = sdk.NewRat(200) + + ok = d1.Equal(d2) + require.False(t, ok) +} + +func TestDelegationHumanReadableString(t *testing.T) { + d := Delegation{ + DelegatorAddr: addr1, + ValidatorAddr: addr2, + Shares: sdk.NewRat(100), + } + + // NOTE: Being that the validator's keypair is random, we cannot test the + // actual contents of the string. + valStr, err := d.HumanReadableString() + require.Nil(t, err) + require.NotEmpty(t, valStr) +} + +func TestUnbondingDelegationEqual(t *testing.T) { + ud1 := UnbondingDelegation{ + DelegatorAddr: addr1, + ValidatorAddr: addr2, + } + ud2 := UnbondingDelegation{ + DelegatorAddr: addr1, + ValidatorAddr: addr2, + } + + ok := ud1.Equal(ud2) + require.True(t, ok) + + ud2.ValidatorAddr = addr3 + ud2.MinTime = 20 * 20 * 2 + + ok = ud1.Equal(ud2) + require.False(t, ok) +} + +func TestUnbondingDelegationHumanReadableString(t *testing.T) { + ud := UnbondingDelegation{ + DelegatorAddr: addr1, + ValidatorAddr: addr2, + } + + // NOTE: Being that the validator's keypair is random, we cannot test the + // actual contents of the string. + valStr, err := ud.HumanReadableString() + require.Nil(t, err) + require.NotEmpty(t, valStr) +} + +func TestRedelegationEqual(t *testing.T) { + r1 := Redelegation{ + DelegatorAddr: addr1, + ValidatorSrcAddr: addr2, + ValidatorDstAddr: addr3, + } + r2 := Redelegation{ + DelegatorAddr: addr1, + ValidatorSrcAddr: addr2, + ValidatorDstAddr: addr3, + } + + ok := r1.Equal(r2) + require.True(t, ok) + + r2.SharesDst = sdk.NewRat(10) + r2.SharesSrc = sdk.NewRat(20) + r2.MinTime = 20 * 20 * 2 + + ok = r1.Equal(r2) + require.False(t, ok) +} + +func TestRedelegationHumanReadableString(t *testing.T) { + r := Redelegation{ + DelegatorAddr: addr1, + ValidatorSrcAddr: addr2, + ValidatorDstAddr: addr3, + SharesDst: sdk.NewRat(10), + SharesSrc: sdk.NewRat(20), + } + + // NOTE: Being that the validator's keypair is random, we cannot test the + // actual contents of the string. + valStr, err := r.HumanReadableString() + require.Nil(t, err) + require.NotEmpty(t, valStr) +} diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index 2914741f45..09ed2d3696 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -25,97 +25,118 @@ const ( func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil") } + func ErrNoValidatorFound(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") } + func ErrValidatorAlreadyExists(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist, cannot re-create validator") } + func ErrValidatorRevoked(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "validator for this address is currently revoked") } + func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "error removing validator") } + func ErrDescriptionLength(codespace sdk.CodespaceType, descriptor string, got, max int) sdk.Error { msg := fmt.Sprintf("bad description length for %v, got length %v, max is %v", descriptor, got, max) return sdk.NewError(codespace, CodeInvalidValidator, msg) } + func ErrCommissionNegative(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "commission must be positive") } + func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%") } -// delegation func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil") } + func ErrBadDenom(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "invalid coin denomination") } + func ErrBadDelegationAmount(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "amount must be > 0") } + func ErrNoDelegation(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "no delegation for this (address, validator) pair") } + func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not exist for that address") } + func ErrNoDelegatorForAddress(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not contain this delegation") } + func ErrInsufficientShares(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "insufficient delegation shares") } + func ErrDelegationValidatorEmpty(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "cannot delegate to an empty validator") } + func ErrNotEnoughDelegationShares(codespace sdk.CodespaceType, shares string) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, fmt.Sprintf("not enough shares only have %v", shares)) } + func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0") } + func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points", maximumBondingRationalDenominator.String()), ) } + func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") } -// redelegation func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min int64) sdk.Error { msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v", operation, descriptor, got, min) return sdk.NewError(codespace, CodeUnauthorized, msg) } + func ErrNoUnbondingDelegation(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "no unbonding delegation found") } + func ErrNoRedelegation(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "no redelegation found") } + func ErrBadRedelegationDst(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "redelegation validator not found") } + func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "redelegation to this validator already in progress, first redelegation to this validator must complete before next redelegation") } -// messages func ErrBothShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidInput, "both shares amount and shares percent provided") } + func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidInput, "neither shares amount nor shares percent provided") } + func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "missing signature") } diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index f3d8bc686f..1a854a4926 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -10,9 +10,9 @@ import ( ) var ( - coinPos = sdk.Coin{"steak", sdk.NewInt(1000)} - coinZero = sdk.Coin{"steak", sdk.NewInt(0)} - coinNeg = sdk.Coin{"steak", sdk.NewInt(-10000)} + coinPos = sdk.NewCoin("steak", 1000) + coinZero = sdk.NewCoin("steak", 0) + coinNeg = sdk.NewCoin("steak", -10000) ) // test ValidateBasic for MsgCreateValidator @@ -197,29 +197,3 @@ func TestMsgCompleteUnbonding(t *testing.T) { } } } - -// TODO introduce with go-amino -//func TestSerializeMsg(t *testing.T) { - -//// make sure all types construct properly -//bondAmt := 1234321 -//bond := sdk.Coin{Denom: "atom", Amount: int64(bondAmt)} - -//tests := []struct { -//tx sdk.Msg -//}{ -//{NewMsgCreateValidator(addr1, pk1, bond, Description{})}, -//{NewMsgEditValidator(addr1, Description{})}, -//{NewMsgDelegate(addr1, addr2, bond)}, -//{NewMsgUnbond(addr1, addr2, strconv.Itoa(bondAmt))}, -//} - -//for i, tc := range tests { -//var tx sdk.Tx -//bs := wire.BinaryBytes(tc.tx) -//err := wire.ReadBinaryBytes(bs, &tx) -//if require.NoError(t, err, "%d", i) { -//require.Equal(t, tc.tx, tx, "%d", i) -//} -//} -//} diff --git a/x/stake/types/params.go b/x/stake/types/params.go index 8c1b897f2e..5a7dd6ef55 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -6,6 +6,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// defaultUnbondingTime reflects three weeks in seconds as the default +// unbonding time. +const defaultUnbondingTime int64 = 60 * 60 * 24 * 3 + // Params defines the high level settings for staking type Params struct { InflationRateChange sdk.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate @@ -19,21 +23,21 @@ type Params struct { BondDenom string `json:"bond_denom"` // bondable coin denomination } -// nolint +// Equal returns a boolean determining if two Param types are identical. func (p Params) Equal(p2 Params) bool { bz1 := MsgCdc.MustMarshalBinary(&p) bz2 := MsgCdc.MustMarshalBinary(&p2) return bytes.Equal(bz1, bz2) } -// default params +// DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ InflationRateChange: sdk.NewRat(13, 100), InflationMax: sdk.NewRat(20, 100), InflationMin: sdk.NewRat(7, 100), GoalBonded: sdk.NewRat(67, 100), - UnbondingTime: 60 * 60 * 24 * 3, // 3 weeks in seconds + UnbondingTime: defaultUnbondingTime, MaxValidators: 100, BondDenom: "steak", } diff --git a/x/stake/types/params_test.go b/x/stake/types/params_test.go new file mode 100644 index 0000000000..c18700ef43 --- /dev/null +++ b/x/stake/types/params_test.go @@ -0,0 +1,21 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParamsEqual(t *testing.T) { + p1 := DefaultParams() + p2 := DefaultParams() + + ok := p1.Equal(p2) + require.True(t, ok) + + p2.UnbondingTime = 60 * 60 * 24 * 2 + p2.BondDenom = "soup" + + ok = p1.Equal(p2) + require.False(t, ok) +} diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index a62c69d468..3a52646f67 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -3,11 +3,24 @@ package types import ( "testing" - "github.com/stretchr/testify/require" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" ) +func TestPoolEqual(t *testing.T) { + p1 := InitialPool() + p2 := InitialPool() + + ok := p1.Equal(p2) + require.True(t, ok) + + p2.BondedTokens = 3 + p2.BondedShares = sdk.NewRat(10) + + ok = p1.Equal(p2) + require.False(t, ok) +} + func TestBondedRatio(t *testing.T) { pool := InitialPool() pool.LooseTokens = 1 @@ -62,10 +75,10 @@ func TestUnbondedShareExRate(t *testing.T) { } func TestAddTokensBonded(t *testing.T) { - poolA := InitialPool() poolA.LooseTokens = 10 require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) + poolB, sharesB := poolA.addTokensBonded(10) require.Equal(t, poolB.BondedShareExRate(), sdk.OneRat()) @@ -78,10 +91,10 @@ func TestAddTokensBonded(t *testing.T) { } func TestRemoveSharesBonded(t *testing.T) { - poolA := InitialPool() poolA.LooseTokens = 10 require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) + poolB, tokensB := poolA.removeSharesBonded(sdk.NewRat(10)) require.Equal(t, poolB.BondedShareExRate(), sdk.OneRat()) @@ -94,10 +107,10 @@ func TestRemoveSharesBonded(t *testing.T) { } func TestAddTokensUnbonded(t *testing.T) { - poolA := InitialPool() poolA.LooseTokens = 10 require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) + poolB, sharesB := poolA.addTokensUnbonded(10) require.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat()) @@ -110,11 +123,11 @@ func TestAddTokensUnbonded(t *testing.T) { } func TestRemoveSharesUnbonded(t *testing.T) { - poolA := InitialPool() poolA.UnbondedTokens = 10 poolA.UnbondedShares = sdk.NewRat(10) require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) + poolB, tokensB := poolA.removeSharesUnbonded(sdk.NewRat(10)) require.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat()) diff --git a/x/stake/types/shares.go b/x/stake/types/shares.go index 09301d0db6..5a2cb2be6c 100644 --- a/x/stake/types/shares.go +++ b/x/stake/types/shares.go @@ -4,18 +4,19 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// pool shares held by a validator +// PoolShares reflects the shares of a validator in a pool. type PoolShares struct { Status sdk.BondStatus `json:"status"` - Amount sdk.Rat `json:"amount"` // total shares of type ShareKind + Amount sdk.Rat `json:"amount"` } -// only the vitals - does not check bond height of IntraTxCounter +// Equal returns a boolean determining of two PoolShares are identical. func (s PoolShares) Equal(s2 PoolShares) bool { return s.Status == s2.Status && s.Amount.Equal(s2.Amount) } +// NewUnbondedShares returns a new PoolShares with a specified unbonded amount. func NewUnbondedShares(amount sdk.Rat) PoolShares { return PoolShares{ Status: sdk.Unbonded, @@ -23,6 +24,8 @@ func NewUnbondedShares(amount sdk.Rat) PoolShares { } } +// NewUnbondingShares returns a new PoolShares with a specified unbonding +// amount. func NewUnbondingShares(amount sdk.Rat) PoolShares { return PoolShares{ Status: sdk.Unbonding, @@ -30,6 +33,7 @@ func NewUnbondingShares(amount sdk.Rat) PoolShares { } } +// NewBondedShares returns a new PoolSahres with a specified bonding amount. func NewBondedShares(amount sdk.Rat) PoolShares { return PoolShares{ Status: sdk.Bonded, @@ -37,9 +41,7 @@ func NewBondedShares(amount sdk.Rat) PoolShares { } } -//_________________________________________________________________________________________________________ - -// amount of unbonded shares +// Unbonded returns the amount of unbonded shares. func (s PoolShares) Unbonded() sdk.Rat { if s.Status == sdk.Unbonded { return s.Amount @@ -47,7 +49,7 @@ func (s PoolShares) Unbonded() sdk.Rat { return sdk.ZeroRat() } -// amount of unbonding shares +// Unbonding returns the amount of unbonding shares. func (s PoolShares) Unbonding() sdk.Rat { if s.Status == sdk.Unbonding { return s.Amount @@ -55,7 +57,7 @@ func (s PoolShares) Unbonding() sdk.Rat { return sdk.ZeroRat() } -// amount of bonded shares +// Bonded returns amount of bonded shares. func (s PoolShares) Bonded() sdk.Rat { if s.Status == sdk.Bonded { return s.Amount @@ -63,64 +65,80 @@ func (s PoolShares) Bonded() sdk.Rat { return sdk.ZeroRat() } -//_________________________________________________________________________________________________________ - -// equivalent amount of shares if the shares were unbonded +// ToUnbonded returns the equivalent amount of pool shares if the shares were +// unbonded. func (s PoolShares) ToUnbonded(p Pool) PoolShares { var amount sdk.Rat + switch s.Status { case sdk.Bonded: - exRate := p.BondedShareExRate().Quo(p.UnbondedShareExRate()) // (tok/bondedshr)/(tok/unbondedshr) = unbondedshr/bondedshr - amount = s.Amount.Mul(exRate) // bondedshr*unbondedshr/bondedshr = unbondedshr + // (tok/bondedshr)/(tok/unbondedshr) = unbondedshr/bondedshr + exRate := p.BondedShareExRate().Quo(p.UnbondedShareExRate()) + // bondedshr*unbondedshr/bondedshr = unbondedshr + amount = s.Amount.Mul(exRate) case sdk.Unbonding: - exRate := p.UnbondingShareExRate().Quo(p.UnbondedShareExRate()) // (tok/unbondingshr)/(tok/unbondedshr) = unbondedshr/unbondingshr - amount = s.Amount.Mul(exRate) // unbondingshr*unbondedshr/unbondingshr = unbondedshr + // (tok/unbondingshr)/(tok/unbondedshr) = unbondedshr/unbondingshr + exRate := p.UnbondingShareExRate().Quo(p.UnbondedShareExRate()) + // unbondingshr*unbondedshr/unbondingshr = unbondedshr + amount = s.Amount.Mul(exRate) case sdk.Unbonded: amount = s.Amount } + return NewUnbondedShares(amount) } -// equivalent amount of shares if the shares were unbonding +// ToUnbonding returns the equivalent amount of pool shares if the shares were +// unbonding. func (s PoolShares) ToUnbonding(p Pool) PoolShares { var amount sdk.Rat + switch s.Status { case sdk.Bonded: - exRate := p.BondedShareExRate().Quo(p.UnbondingShareExRate()) // (tok/bondedshr)/(tok/unbondingshr) = unbondingshr/bondedshr - amount = s.Amount.Mul(exRate) // bondedshr*unbondingshr/bondedshr = unbondingshr + // (tok/bondedshr)/(tok/unbondingshr) = unbondingshr/bondedshr + exRate := p.BondedShareExRate().Quo(p.UnbondingShareExRate()) + // bondedshr*unbondingshr/bondedshr = unbondingshr + amount = s.Amount.Mul(exRate) case sdk.Unbonding: amount = s.Amount case sdk.Unbonded: - exRate := p.UnbondedShareExRate().Quo(p.UnbondingShareExRate()) // (tok/unbondedshr)/(tok/unbondingshr) = unbondingshr/unbondedshr - amount = s.Amount.Mul(exRate) // unbondedshr*unbondingshr/unbondedshr = unbondingshr + // (tok/unbondedshr)/(tok/unbondingshr) = unbondingshr/unbondedshr + exRate := p.UnbondedShareExRate().Quo(p.UnbondingShareExRate()) + // unbondedshr*unbondingshr/unbondedshr = unbondingshr + amount = s.Amount.Mul(exRate) } + return NewUnbondingShares(amount) } -// equivalent amount of shares if the shares were bonded +// ToBonded the equivalent amount of pool shares if the shares were bonded. func (s PoolShares) ToBonded(p Pool) PoolShares { var amount sdk.Rat + switch s.Status { case sdk.Bonded: amount = s.Amount case sdk.Unbonding: - exRate := p.UnbondingShareExRate().Quo(p.BondedShareExRate()) // (tok/ubshr)/(tok/bshr) = bshr/ubshr - amount = s.Amount.Mul(exRate) // ubshr*bshr/ubshr = bshr + // (tok/ubshr)/(tok/bshr) = bshr/ubshr + exRate := p.UnbondingShareExRate().Quo(p.BondedShareExRate()) + // ubshr*bshr/ubshr = bshr + amount = s.Amount.Mul(exRate) case sdk.Unbonded: - exRate := p.UnbondedShareExRate().Quo(p.BondedShareExRate()) // (tok/ubshr)/(tok/bshr) = bshr/ubshr - amount = s.Amount.Mul(exRate) // ubshr*bshr/ubshr = bshr + // (tok/ubshr)/(tok/bshr) = bshr/ubshr + exRate := p.UnbondedShareExRate().Quo(p.BondedShareExRate()) + // ubshr*bshr/ubshr = bshr + amount = s.Amount.Mul(exRate) } + return NewUnbondedShares(amount) } -//_________________________________________________________________________________________________________ - -// TODO better tests -// get the equivalent amount of tokens contained by the shares +// Tokens returns the equivalent amount of tokens contained by the pool shares +// for a given pool. func (s PoolShares) Tokens(p Pool) sdk.Rat { switch s.Status { case sdk.Bonded: - return p.BondedShareExRate().Mul(s.Amount) // (tokens/shares) * shares + return p.BondedShareExRate().Mul(s.Amount) case sdk.Unbonding: return p.UnbondingShareExRate().Mul(s.Amount) case sdk.Unbonded: diff --git a/x/stake/types/shares_test.go b/x/stake/types/shares_test.go new file mode 100644 index 0000000000..8a374606c5 --- /dev/null +++ b/x/stake/types/shares_test.go @@ -0,0 +1,35 @@ +package types + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestPoolSharesTokens(t *testing.T) { + pool := InitialPool() + pool.LooseTokens = 10 + + val := Validator{ + Owner: addr1, + PubKey: pk1, + PoolShares: NewBondedShares(sdk.NewRat(100)), + DelegatorShares: sdk.NewRat(100), + } + + pool.BondedTokens = val.PoolShares.Bonded().RoundInt64() + pool.BondedShares = val.PoolShares.Bonded() + + poolShares := NewBondedShares(sdk.NewRat(50)) + tokens := poolShares.Tokens(pool) + require.Equal(t, int64(50), tokens.RoundInt64()) + + poolShares = NewUnbondingShares(sdk.NewRat(50)) + tokens = poolShares.Tokens(pool) + require.Equal(t, int64(50), tokens.RoundInt64()) + + poolShares = NewUnbondedShares(sdk.NewRat(50)) + tokens = poolShares.Tokens(pool) + require.Equal(t, int64(50), tokens.RoundInt64()) +} diff --git a/x/stake/types/test_common.go b/x/stake/types/test_utils.go similarity index 84% rename from x/stake/types/test_common.go rename to x/stake/types/test_utils.go index 12f11f864b..7912b7fa85 100644 --- a/x/stake/types/test_common.go +++ b/x/stake/types/test_utils.go @@ -11,7 +11,6 @@ import ( ) var ( - // dummy pubkeys/addresses pk1 = crypto.GenPrivKeyEd25519().PubKey() pk2 = crypto.GenPrivKeyEd25519().PubKey() pk3 = crypto.GenPrivKeyEd25519().PubKey() @@ -23,18 +22,20 @@ var ( emptyPubkey crypto.PubKey ) -//______________________________________________________________ - -// any operation that transforms staking state -// takes in RNG instance, pool, validator -// returns updated pool, updated validator, delta tokens, descriptive message +// Operation reflects any operation that transforms staking state. It takes in +// a RNG instance, pool, validator and returns an updated pool, updated +// validator, delta tokens, and descriptive message. type Operation func(r *rand.Rand, pool Pool, c Validator) (Pool, Validator, int64, string) -// operation: bond or unbond a validator depending on current status +// OpBondOrUnbond implements an operation that bonds or unbonds a validator +// depending on current status. // nolint: unparam func OpBondOrUnbond(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) { - var msg string - var newStatus sdk.BondStatus + var ( + msg string + newStatus sdk.BondStatus + ) + if val.Status() == sdk.Bonded { msg = fmt.Sprintf("sdk.Unbonded previously bonded validator %s (poolShares: %v, delShares: %v, DelegatorShareExRate: %v)", val.Owner, val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool)) @@ -45,21 +46,27 @@ func OpBondOrUnbond(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, in val.Owner, val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool)) newStatus = sdk.Bonded } + val, pool = val.UpdateStatus(pool, newStatus) return pool, val, 0, msg } -// operation: add a random number of tokens to a validator +// OpAddTokens implements an operation that adds a random number of tokens to a +// validator. func OpAddTokens(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) { - tokens := int64(r.Int31n(1000)) msg := fmt.Sprintf("validator %s (status: %d, poolShares: %v, delShares: %v, DelegatorShareExRate: %v)", val.Owner, val.Status(), val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool)) + + tokens := int64(r.Int31n(1000)) val, pool, _ = val.AddTokensFromDel(pool, tokens) msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg) - return pool, val, -1 * tokens, msg // tokens are removed so for accounting must be negative + + // Tokens are removed so for accounting must be negative + return pool, val, -1 * tokens, msg } -// operation: remove a random number of shares from a validator +// OpRemoveShares implements an operation that removes a random number of +// shares from a validator. func OpRemoveShares(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) { var shares sdk.Rat for { @@ -76,7 +83,7 @@ func OpRemoveShares(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, in return pool, val, tokens, msg } -// pick a random staking operation +// RandomOperation returns a random staking operation. func RandomOperation(r *rand.Rand) Operation { operations := []Operation{ OpBondOrUnbond, @@ -86,10 +93,11 @@ func RandomOperation(r *rand.Rand) Operation { r.Shuffle(len(operations), func(i, j int) { operations[i], operations[j] = operations[j], operations[i] }) + return operations[0] } -// ensure invariants that should always be true are true +// AssertInvariants ensures invariants that should always be true are true. // nolint: unparam func AssertInvariants(t *testing.T, msg string, pOrig Pool, cOrig []Validator, pMod Pool, vMods []Validator, tokens int64) { @@ -105,29 +113,28 @@ func AssertInvariants(t *testing.T, msg string, pOrig.UnbondedTokens, pOrig.BondedTokens, pMod.UnbondedTokens, pMod.BondedTokens, tokens) - // nonnegative bonded shares + // Nonnegative bonded shares require.False(t, pMod.BondedShares.LT(sdk.ZeroRat()), "Negative bonded shares - msg: %v\npOrig: %v\npMod: %v\ntokens: %v\n", msg, pOrig, pMod, tokens) - // nonnegative unbonded shares + // Nonnegative unbonded shares require.False(t, pMod.UnbondedShares.LT(sdk.ZeroRat()), "Negative unbonded shares - msg: %v\npOrig: %v\npMod: %v\ntokens: %v\n", msg, pOrig, pMod, tokens) - // nonnegative bonded ex rate + // Nonnegative bonded ex rate require.False(t, pMod.BondedShareExRate().LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative BondedShareExRate: %d", msg, pMod.BondedShareExRate().RoundInt64()) - // nonnegative unbonded ex rate + // Nonnegative unbonded ex rate require.False(t, pMod.UnbondedShareExRate().LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative UnbondedShareExRate: %d", msg, pMod.UnbondedShareExRate().RoundInt64()) for _, vMod := range vMods { - - // nonnegative ex rate + // Nonnegative ex rate require.False(t, vMod.DelegatorShareExRate(pMod).LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative validator.DelegatorShareExRate(): %v (validator.Owner: %s)", msg, @@ -135,7 +142,7 @@ func AssertInvariants(t *testing.T, msg string, vMod.Owner, ) - // nonnegative poolShares + // Nonnegative poolShares require.False(t, vMod.PoolShares.Bonded().LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative validator.PoolShares.Bonded(): %v (validator.DelegatorShares: %v, validator.DelegatorShareExRate: %v, validator.Owner: %s)", msg, @@ -145,7 +152,7 @@ func AssertInvariants(t *testing.T, msg string, vMod.Owner, ) - // nonnegative delShares + // Nonnegative delShares require.False(t, vMod.DelegatorShares.LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative validator.DelegatorShares: %v (validator.PoolShares.Bonded(): %v, validator.DelegatorShareExRate: %v, validator.Owner: %s)", msg, @@ -154,27 +161,25 @@ func AssertInvariants(t *testing.T, msg string, vMod.DelegatorShareExRate(pMod), vMod.Owner, ) - } - } -//________________________________________________________________________________ -// TODO refactor this random setup +// TODO: refactor this random setup -// generate a random validator +// randomValidator generates a random validator. // nolint: unparam func randomValidator(r *rand.Rand, i int) Validator { - poolSharesAmt := sdk.NewRat(int64(r.Int31n(10000))) delShares := sdk.NewRat(int64(r.Int31n(10000))) var pShares PoolShares + if r.Float64() < float64(0.5) { pShares = NewBondedShares(poolSharesAmt) } else { pShares = NewUnbondedShares(poolSharesAmt) } + return Validator{ Owner: addr1, PubKey: pk1, @@ -183,7 +188,7 @@ func randomValidator(r *rand.Rand, i int) Validator { } } -// generate a random staking state +// RandomSetup generates a random staking state. func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) { pool := InitialPool() pool.LooseTokens = 100000 @@ -191,6 +196,7 @@ func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) { validators := make([]Validator, numValidators) for i := 0; i < numValidators; i++ { validator := randomValidator(r, i) + if validator.Status() == sdk.Bonded { pool.BondedShares = pool.BondedShares.Add(validator.PoolShares.Bonded()) pool.BondedTokens += validator.PoolShares.Bonded().RoundInt64() @@ -198,7 +204,9 @@ func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) { pool.UnbondedShares = pool.UnbondedShares.Add(validator.PoolShares.Unbonded()) pool.UnbondedTokens += validator.PoolShares.Unbonded().RoundInt64() } + validators[i] = validator } + return pool, validators } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index c2c19439be..c55ae725a6 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -4,13 +4,14 @@ import ( "bytes" "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" - - sdk "github.com/cosmos/cosmos-sdk/types" ) +const doNotModifyDescVal = "[do-not-modify]" + // Validator defines the total amount of bond shares and their exchange rate to // coins. Accumulation of interest is modelled as an in increase in the // exchange rate, and slashing as a decrease. When coins are delegated to this @@ -60,15 +61,13 @@ func NewValidator(owner sdk.Address, pubKey crypto.PubKey, description Descripti } } -// only the vitals - does not check bond height of IntraTxCounter +// Equal returns a boolean reflecting if two given validators are identical. func (v Validator) Equal(c2 Validator) bool { return v.PubKey.Equals(c2.PubKey) && bytes.Equal(v.Owner, c2.Owner) && v.PoolShares.Equal(c2.PoolShares) && v.DelegatorShares.Equal(c2.DelegatorShares) && v.Description == c2.Description && - //v.BondHeight == c2.BondHeight && - //v.BondIntraTxCounter == c2.BondIntraTxCounter && // counter is always changing v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) && v.Commission.Equal(c2.Commission) && v.CommissionMax.Equal(c2.CommissionMax) && @@ -85,6 +84,7 @@ type Description struct { Details string `json:"details"` // optional details } +// NewDescription returns a new Description with the provided values. func NewDescription(moniker, identity, website, details string) Description { return Description{ Moniker: moniker, @@ -94,20 +94,22 @@ func NewDescription(moniker, identity, website, details string) Description { } } -// update the description based on input +// UpdateDescription updates the fields of a given description. An error is +// returned if the resulting description contains an invalid length. func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error) { - if d.Moniker == "[do-not-modify]" { + if d.Moniker == doNotModifyDescVal { d2.Moniker = d.Moniker } - if d.Identity == "[do-not-modify]" { + if d.Identity == doNotModifyDescVal { d2.Identity = d.Identity } - if d.Website == "[do-not-modify]" { + if d.Website == doNotModifyDescVal { d2.Website = d.Website } - if d.Details == "[do-not-modify]" { + if d.Details == doNotModifyDescVal { d2.Details = d.Details } + return Description{ Moniker: d2.Moniker, Identity: d2.Identity, @@ -116,7 +118,7 @@ func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error) }.EnsureLength() } -// ensure the length of the description +// EnsureLength ensures the length of a validator's description. func (d Description) EnsureLength() (Description, sdk.Error) { if len(d.Moniker) > 70 { return d, ErrDescriptionLength(DefaultCodespace, "moniker", len(d.Moniker), 70) @@ -130,10 +132,11 @@ func (d Description) EnsureLength() (Description, sdk.Error) { if len(d.Details) > 280 { return d, ErrDescriptionLength(DefaultCodespace, "details", len(d.Details), 280) } + return d, nil } -// abci validator from stake validator type +// ABCIValidator returns an abci.Validator from a staked validator type. func (v Validator) ABCIValidator() abci.Validator { return abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(v.PubKey), @@ -141,8 +144,8 @@ func (v Validator) ABCIValidator() abci.Validator { } } -// abci validator from stake validator type -// with zero power used for validator updates +// ABCIValidatorZero returns an abci.Validator from a staked validator type +// with with zero power used for validator updates. func (v Validator) ABCIValidatorZero() abci.Validator { return abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(v.PubKey), @@ -150,12 +153,13 @@ func (v Validator) ABCIValidatorZero() abci.Validator { } } -// abci validator from stake validator type +// Status returns the validator's bond status inferred from the pool shares. func (v Validator) Status() sdk.BondStatus { return v.PoolShares.Status } -// update the location of the shares within a validator if its bond status has changed +// UpdateStatus updates the location of the shares within a validator if it's +// bond status has changed. func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, Pool) { var tokens int64 @@ -173,7 +177,8 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, pool, tokens = pool.removeSharesUnbonding(v.PoolShares.Amount) case sdk.Bonded: - if NewStatus == sdk.Bonded { // return if nothing needs switching + if NewStatus == sdk.Bonded { + // Return if nothing needs switching return v, pool } pool, tokens = pool.removeSharesBonded(v.PoolShares.Amount) @@ -187,14 +192,16 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Bonded: pool, v.PoolShares = pool.addTokensBonded(tokens) } + return v, pool } -// Remove pool shares -// Returns corresponding tokens, which could be burned (e.g. when slashing -// a validator) or redistributed elsewhere +// RemovePoolShares removes pool shares from a validator. It returns +// corresponding tokens, which could be burned (e.g. when slashing a validator) +// or redistributed elsewhere. func (v Validator) RemovePoolShares(pool Pool, poolShares sdk.Rat) (Validator, Pool, int64) { var tokens int64 + switch v.Status() { case sdk.Unbonded: pool, tokens = pool.removeSharesUnbonded(poolShares) @@ -203,29 +210,33 @@ func (v Validator) RemovePoolShares(pool Pool, poolShares sdk.Rat) (Validator, P case sdk.Bonded: pool, tokens = pool.removeSharesBonded(poolShares) } + v.PoolShares.Amount = v.PoolShares.Amount.Sub(poolShares) return v, pool, tokens } -// TODO remove should only be tokens -// get the power or potential power for a validator -// if bonded, the power is the BondedShares -// if not bonded, the power is the amount of bonded shares which the -// the validator would have it was bonded +// EquivalentBondedShares ... +// +// TODO: Remove should only be tokens get the power or potential power for a +// validator if bonded, the power is the BondedShares if not bonded, the power +// is the amount of bonded shares which the the validator would have it was +// bonded. func (v Validator) EquivalentBondedShares(pool Pool) (eqBondedShares sdk.Rat) { return v.PoolShares.ToBonded(pool).Amount } //_________________________________________________________________________________________________________ -// add tokens to a validator -func (v Validator) AddTokensFromDel(pool Pool, - amount int64) (validator2 Validator, p2 Pool, issuedDelegatorShares sdk.Rat) { +// AddTokensFromDel adds tokens to a validator +func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Rat) { + var ( + poolShares PoolShares + equivalentBondedShares sdk.Rat + ) - exRate := v.DelegatorShareExRate(pool) // bshr/delshr + // bondedShare/delegatedShare + exRate := v.DelegatorShareExRate(pool) - var poolShares PoolShares - var equivalentBondedShares sdk.Rat switch v.Status() { case sdk.Unbonded: pool, poolShares = pool.addTokensUnbonded(amount) @@ -237,21 +248,24 @@ func (v Validator) AddTokensFromDel(pool Pool, v.PoolShares.Amount = v.PoolShares.Amount.Add(poolShares.Amount) equivalentBondedShares = poolShares.ToBonded(pool).Amount - issuedDelegatorShares = equivalentBondedShares.Quo(exRate) // bshr/(bshr/delshr) = delshr + // bondedShare/(bondedShare/delegatedShare) = delegatedShare + issuedDelegatorShares := equivalentBondedShares.Quo(exRate) v.DelegatorShares = v.DelegatorShares.Add(issuedDelegatorShares) return v, pool, issuedDelegatorShares } -// remove delegator shares from a validator -// NOTE this function assumes the shares have already been updated for the validator status -func (v Validator) RemoveDelShares(pool Pool, - delShares sdk.Rat) (validator2 Validator, p2 Pool, createdCoins int64) { - +// RemoveDelShares removes delegator shares from a validator. +// +// NOTE: This function assumes the shares have already been updated for the +// validator status. +func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, int64) { amount := v.DelegatorShareExRate(pool).Mul(delShares) eqBondedSharesToRemove := NewBondedShares(amount) v.DelegatorShares = v.DelegatorShares.Sub(delShares) + var createdCoins int64 + switch v.Status() { case sdk.Unbonded: unbondedShares := eqBondedSharesToRemove.ToUnbonded(pool).Amount @@ -265,15 +279,17 @@ func (v Validator) RemoveDelShares(pool Pool, pool, createdCoins = pool.removeSharesBonded(eqBondedSharesToRemove.Amount) v.PoolShares.Amount = v.PoolShares.Amount.Sub(eqBondedSharesToRemove.Amount) } + return v, pool, createdCoins } -// get the exchange rate of tokens over delegator shares +// DelegatorShareExRate gets the exchange rate of tokens over delegator shares. // UNITS: eq-val-bonded-shares/delegator-shares func (v Validator) DelegatorShareExRate(pool Pool) sdk.Rat { if v.DelegatorShares.IsZero() { return sdk.OneRat() } + eqBondedShares := v.PoolShares.ToBonded(pool).Amount return eqBondedShares.Quo(v.DelegatorShares) } @@ -293,16 +309,20 @@ func (v Validator) GetPower() sdk.Rat { return v.PoolShares.Bonded() } func (v Validator) GetDelegatorShares() sdk.Rat { return v.DelegatorShares } func (v Validator) GetBondHeight() int64 { return v.BondHeight } -//Human Friendly pretty printer +// HumanReadableString returns a human readable string representation of a +// validator. An error is returned if the owner or the owner's public key +// cannot be converted to Bech32 format. func (v Validator) HumanReadableString() (string, error) { bechOwner, err := sdk.Bech32ifyAcc(v.Owner) if err != nil { return "", err } + bechVal, err := sdk.Bech32ifyValPub(v.PubKey) if err != nil { return "", err } + resp := "Validator \n" resp += fmt.Sprintf("Owner: %s\n", bechOwner) resp += fmt.Sprintf("Validator: %s\n", bechVal) diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 4fcfa6e17d..f978a6d6eb 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -5,12 +5,89 @@ import ( "math/rand" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" + tmtypes "github.com/tendermint/tendermint/types" ) +func TestValidatorEqual(t *testing.T) { + val1 := NewValidator(addr1, pk1, Description{}) + val2 := NewValidator(addr1, pk1, Description{}) + + ok := val1.Equal(val2) + require.True(t, ok) + + val2 = NewValidator(addr2, pk2, Description{}) + + ok = val1.Equal(val2) + require.False(t, ok) +} + +func TestUpdateDescription(t *testing.T) { + d1 := Description{ + Moniker: doNotModifyDescVal, + Identity: doNotModifyDescVal, + Website: doNotModifyDescVal, + Details: doNotModifyDescVal, + } + d2 := Description{ + Website: "https://validator.cosmos", + Details: "Test validator", + } + + d, err := d1.UpdateDescription(d2) + require.Nil(t, err) + require.Equal(t, d, d1) +} + +func TestABCIValidator(t *testing.T) { + val := NewValidator(addr1, pk1, Description{}) + + abciVal := val.ABCIValidator() + require.Equal(t, tmtypes.TM2PB.PubKey(val.PubKey), abciVal.PubKey) + require.Equal(t, val.PoolShares.Bonded().RoundInt64(), abciVal.Power) +} + +func TestABCIValidatorZero(t *testing.T) { + val := NewValidator(addr1, pk1, Description{}) + + abciVal := val.ABCIValidatorZero() + require.Equal(t, tmtypes.TM2PB.PubKey(val.PubKey), abciVal.PubKey) + require.Equal(t, int64(0), abciVal.Power) +} + +func TestRemovePoolShares(t *testing.T) { + pool := InitialPool() + pool.LooseTokens = 10 + + val := Validator{ + Owner: addr1, + PubKey: pk1, + PoolShares: NewBondedShares(sdk.NewRat(100)), + DelegatorShares: sdk.NewRat(100), + } + + pool.BondedTokens = val.PoolShares.Bonded().RoundInt64() + pool.BondedShares = val.PoolShares.Bonded() + + val, pool = val.UpdateStatus(pool, sdk.Bonded) + val, pool, tk := val.RemovePoolShares(pool, sdk.NewRat(10)) + require.Equal(t, int64(90), val.PoolShares.Amount.RoundInt64()) + require.Equal(t, int64(90), pool.BondedTokens) + require.Equal(t, int64(90), pool.BondedShares.RoundInt64()) + require.Equal(t, int64(20), pool.LooseTokens) + require.Equal(t, int64(10), tk) + + val, pool = val.UpdateStatus(pool, sdk.Unbonded) + val, pool, tk = val.RemovePoolShares(pool, sdk.NewRat(10)) + require.Equal(t, int64(80), val.PoolShares.Amount.RoundInt64()) + require.Equal(t, int64(0), pool.BondedTokens) + require.Equal(t, int64(0), pool.BondedShares.RoundInt64()) + require.Equal(t, int64(30), pool.LooseTokens) + require.Equal(t, int64(10), tk) +} + func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() pool.LooseTokens = 10 @@ -230,3 +307,13 @@ func TestMultiValidatorIntegrationInvariants(t *testing.T) { } } } + +func TestHumanReadableString(t *testing.T) { + val := NewValidator(addr1, pk1, Description{}) + + // NOTE: Being that the validator's keypair is random, we cannot test the + // actual contents of the string. + valStr, err := val.HumanReadableString() + require.Nil(t, err) + require.NotEmpty(t, valStr) +} From c5710ceadc2dce772402c3fc72b8f55a69df3c36 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 4 Jul 2018 00:24:29 -0400 Subject: [PATCH 19/53] add codeowners file --- .github/CODEOWNERS | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..dcdf7080b8 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,7 @@ +# CODEOWNERS: https://help.github.com/articles/about-codeowners/ + +# Primary repo maintainers +* @ebuchman @rigelrozanski @cwgoes + +# Precious documentation +/docs/ @zramsay @jolesbi From 04921b9ebd640b3b5f3c9d6dabcc73d438976c88 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 4 Jul 2018 00:29:02 -0400 Subject: [PATCH 20/53] ubd and red more limited values --- x/stake/client/cli/query.go | 24 ++++------ x/stake/client/rest/query.go | 16 +------ x/stake/keeper/delegation.go | 60 ++++++++++++------------ x/stake/types/delegation.go | 90 +++++++++++++++++++++++++++++++++++- 4 files changed, 130 insertions(+), 60 deletions(-) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index e66a3bb4d5..d50b0d14db 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -75,9 +75,9 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { // parse out the validators var validators []stake.Validator - for _, KV := range resKVs { + for _, kv := range resKVs { var validator stake.Validator - cdc.MustUnmarshalBinary(KV.Value, &validator) + cdc.MustUnmarshalBinary(kv.Value, &validator) validators = append(validators, validator) } @@ -178,8 +178,8 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { // parse out the validators var delegations []stake.Delegation - for _, KV := range resKVs { - delegation := types.UnmarshalDelegation(cdc, KV.Key, KV.Value) + for _, kv := range resKVs { + delegation := types.UnmarshalDelegation(cdc, kv.Key, kv.Value) delegations = append(delegations, delegation) } @@ -221,7 +221,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co } // parse out the unbonding delegation - ubd := new(stake.UnbondingDelegation) + ubd := types.UnmarshalUBD(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -231,7 +231,6 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co } fmt.Println(resp) case "json": - cdc.MustUnmarshalBinary(res, ubd) output, err := wire.MarshalJSONIndent(cdc, ubd) if err != nil { return err @@ -269,9 +268,8 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C // parse out the validators var ubds []stake.UnbondingDelegation - for _, KV := range resKVs { - var ubd stake.UnbondingDelegation - cdc.MustUnmarshalBinary(KV.Value, &ubd) + for _, kv := range resKVs { + ubd := types.UnmarshalUBD(cdc, kv.Key, kv.Value) ubds = append(ubds, ubd) } @@ -316,7 +314,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { } // parse out the unbonding delegation - red := new(stake.Redelegation) + red := types.UnmarshalRED(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -326,7 +324,6 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { } fmt.Println(resp) case "json": - cdc.MustUnmarshalBinary(res, red) output, err := wire.MarshalJSONIndent(cdc, red) if err != nil { return err @@ -364,9 +361,8 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command // parse out the validators var reds []stake.Redelegation - for _, KV := range resKVs { - var red stake.Redelegation - cdc.MustUnmarshalBinary(KV.Value, &red) + for _, kv := range resKVs { + red := types.UnmarshalRED(cdc, kv.Key, kv.Value) reds = append(reds, red) } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index b19cea72b7..457806de08 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -128,13 +128,7 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - var ubd stake.UnbondingDelegation - err = cdc.UnmarshalBinary(res, &ubd) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't decode unbonding-delegation. Error: %s", err.Error()))) - return - } + ubd := types.UnmarshalUBD(cdc, key, res) output, err := cdc.MarshalJSON(ubd) if err != nil { @@ -193,13 +187,7 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - var red stake.Redelegation - err = cdc.UnmarshalBinary(res, &red) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't decode redelegation. Error: %s", err.Error()))) - return - } + red := types.UnmarshalRED(cdc, key, res) output, err := cdc.MarshalJSON(red) if err != nil { diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 9c56b85125..3d949a9a0a 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -82,49 +82,48 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, DelegatorAddr, ValidatorAddr sdk.Address) (ubd types.UnbondingDelegation, found bool) { store := ctx.KVStore(k.storeKey) - ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr) - bz := store.Get(ubdKey) - if bz == nil { + key := GetUBDKey(DelegatorAddr, ValidatorAddr) + value := store.Get(key) + if value == nil { return ubd, false } - k.cdc.MustUnmarshalBinary(bz, &ubd) + ubd = types.UnmarshalUBD(k.cdc, key, value) return ubd, true } // load all unbonding delegations from a particular validator -func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (unbondingDelegations []types.UnbondingDelegation) { +func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (ubds []types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr)) for { if !iterator.Valid() { break } - unbondingKey := GetUBDKeyFromValIndexKey(iterator.Key()) - unbondingBytes := store.Get(unbondingKey) - var unbondingDelegation types.UnbondingDelegation - k.cdc.MustUnmarshalBinary(unbondingBytes, &unbondingDelegation) - unbondingDelegations = append(unbondingDelegations, unbondingDelegation) + key := GetUBDKeyFromValIndexKey(iterator.Key()) + value := store.Get(key) + ubd := types.UnmarshalUBD(k.cdc, key, value) + ubds = append(ubds, ubd) iterator.Next() } iterator.Close() - return unbondingDelegations + return ubds } // set the unbonding delegation and associated index func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinary(ubd) - ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) - store.Set(ubdKey, bz) - store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) + bz := types.MarshalUBD(k.cdc, ubd) + key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) + store.Set(key, bz) + store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) // index, store empty bytes } // remove the unbonding delegation object and associated index func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) - store.Delete(ubdKey) + key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) + store.Delete(key) store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr)) } @@ -135,33 +134,32 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.Address) (red types.Redelegation, found bool) { store := ctx.KVStore(k.storeKey) - redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr) - bz := store.Get(redKey) - if bz == nil { + key := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr) + value := store.Get(key) + if value == nil { return red, false } - k.cdc.MustUnmarshalBinary(bz, &red) + red = types.UnmarshalRED(k.cdc, key, value) return red, true } // load all redelegations from a particular validator -func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (redelegations []types.Redelegation) { +func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (reds []types.Redelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr)) for { if !iterator.Valid() { break } - redelegationKey := GetREDKeyFromValSrcIndexKey(iterator.Key()) - redelegationBytes := store.Get(redelegationKey) - var redelegation types.Redelegation - k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation) - redelegations = append(redelegations, redelegation) + key := GetREDKeyFromValSrcIndexKey(iterator.Key()) + value := store.Get(key) + red := types.UnmarshalRED(k.cdc, key, value) + reds = append(reds, red) iterator.Next() } iterator.Close() - return redelegations + return reds } // has a redelegation @@ -184,9 +182,9 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, // set a redelegation and associated index func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinary(red) - redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) - store.Set(redKey, bz) + bz := types.MarshalRED(k.cdc, red) + key := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) + store.Set(key, bz) store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index b6d35fb560..0a3c9cf4fc 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -39,7 +39,7 @@ func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) Delegation { addrs := key[1:] // remove prefix bytes if len(addrs) != 40 { - panic("key length not even") + panic("unexpected key length") } delAddr := sdk.Address(addrs[:20]) valAddr := sdk.Address(addrs[20:]) @@ -100,6 +100,46 @@ type UnbondingDelegation struct { Balance sdk.Coin `json:"balance"` // atoms to receive at completion } +type ubdValue struct { + CreationHeight int64 + MinTime int64 + InitialBalance sdk.Coin + Balance sdk.Coin +} + +// return the unbonding delegation without fields contained within the key for the store +func MarshalUBD(cdc *wire.Codec, ubd UnbondingDelegation) []byte { + val := ubdValue{ + ubd.CreationHeight, + ubd.MinTime, + ubd.InitialBalance, + ubd.Balance, + } + return cdc.MustMarshalBinary(val) +} + +// return the unbonding delegation without fields contained within the key for the store +func UnmarshalUBD(cdc *wire.Codec, key, value []byte) UnbondingDelegation { + var storeValue ubdValue + cdc.MustUnmarshalBinary(value, &storeValue) + + addrs := key[1:] // remove prefix bytes + if len(addrs) != 40 { + panic("unexpected key length") + } + delAddr := sdk.Address(addrs[:20]) + valAddr := sdk.Address(addrs[20:]) + + return UnbondingDelegation{ + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, + CreationHeight: storeValue.CreationHeight, + MinTime: storeValue.MinTime, + InitialBalance: storeValue.InitialBalance, + Balance: storeValue.Balance, + } +} + // nolint func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { bz1 := MsgCdc.MustMarshalBinary(&d) @@ -143,6 +183,54 @@ type Redelegation struct { SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating } +type redValue struct { + CreationHeight int64 + MinTime int64 + InitialBalance sdk.Coin + Balance sdk.Coin + SharesSrc sdk.Rat + SharesDst sdk.Rat +} + +// return the unbonding delegation without fields contained within the key for the store +func MarshalRED(cdc *wire.Codec, red Redelegation) []byte { + val := redValue{ + red.CreationHeight, + red.MinTime, + red.InitialBalance, + red.Balance, + red.SharesSrc, + red.SharesDst, + } + return cdc.MustMarshalBinary(val) +} + +// return the unbonding delegation without fields contained within the key for the store +func UnmarshalRED(cdc *wire.Codec, key, value []byte) Redelegation { + var storeValue redValue + cdc.MustUnmarshalBinary(value, &storeValue) + + addrs := key[1:] // remove prefix bytes + if len(addrs) != 60 { + panic("unexpected key length") + } + delAddr := sdk.Address(addrs[:20]) + valSrcAddr := sdk.Address(addrs[20:40]) + valDstAddr := sdk.Address(addrs[40:60]) + + return Redelegation{ + DelegatorAddr: delAddr, + ValidatorSrcAddr: valSrcAddr, + ValidatorDstAddr: valDstAddr, + CreationHeight: storeValue.CreationHeight, + MinTime: storeValue.MinTime, + InitialBalance: storeValue.InitialBalance, + Balance: storeValue.Balance, + SharesSrc: storeValue.SharesSrc, + SharesDst: storeValue.SharesDst, + } +} + // nolint func (d Redelegation) Equal(d2 Redelegation) bool { bz1 := MsgCdc.MustMarshalBinary(&d) From a2f7b582df0789a0a0993be32afb5df4e047a232 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 4 Jul 2018 01:32:49 -0400 Subject: [PATCH 21/53] validators smaller values stored --- x/slashing/handler_test.go | 3 +- x/slashing/test_common.go | 10 +++--- x/stake/client/cli/query.go | 8 ++--- x/stake/client/rest/query.go | 15 ++++----- x/stake/keeper/sdk_types.go | 5 ++- x/stake/keeper/validator.go | 30 +++++++---------- x/stake/types/delegation.go | 6 ++-- x/stake/types/validator.go | 65 ++++++++++++++++++++++++++++++++++++ 8 files changed, 100 insertions(+), 42 deletions(-) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index c2c5d9166f..d5a6b15dbb 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -15,7 +15,8 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) { slh := NewHandler(keeper) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) - got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) + msg := newTestMsgCreateValidator(addr, val, amt) + got := stake.NewHandler(sk)(ctx, msg) require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index edf119bc7f..77b553317a 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -23,16 +23,16 @@ import ( // TODO remove dependencies on staking (should only refer to validator set type from sdk) var ( - addrs = []sdk.Address{ - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162"), - } pks = []crypto.PubKey{ newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), } + addrs = []sdk.Address{ + pks[0].Address(), + pks[1].Address(), + pks[2].Address(), + } initCoins sdk.Int = sdk.NewInt(200) ) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index d50b0d14db..ee495e96e0 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -32,8 +32,8 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } - validator := new(stake.Validator) - cdc.MustUnmarshalBinary(res, validator) + + validator := types.UnmarshalValidator(cdc, addr, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -76,8 +76,8 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { // parse out the validators var validators []stake.Validator for _, kv := range resKVs { - var validator stake.Validator - cdc.MustUnmarshalBinary(kv.Value, &validator) + addr := kv.Key[1:] + validator := types.UnmarshalValidator(cdc, addr, kv.Value) validators = append(validators, validator) } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 457806de08..49051c73ef 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -275,15 +275,14 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF // parse out the validators validators := make([]StakeValidatorOutput, len(kvs)) for i, kv := range kvs { - var validator stake.Validator - var bech32Validator StakeValidatorOutput - err = cdc.UnmarshalBinary(kv.Value, &validator) - if err == nil { - bech32Validator, err = bech32StakeValidatorOutput(validator) - } + + addr := kv.Key[1:] + validator := types.UnmarshalValidator(cdc, addr, kv.Value) + + bech32Validator, err := bech32StakeValidatorOutput(validator) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't decode validator. Error: %s", err.Error()))) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) return } validators[i] = bech32Validator diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 9e45982b46..0fe465892c 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -16,9 +16,8 @@ func (k Keeper) IterateValidators(ctx sdk.Context, fn func(index int64, validato iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey) i := int64(0) for ; iterator.Valid(); iterator.Next() { - bz := iterator.Value() - var validator types.Validator - k.cdc.MustUnmarshalBinary(bz, &validator) + addr := iterator.Key()[1:] + validator := types.UnmarshalValidator(k.cdc, addr, iterator.Value()) stop := fn(i, validator) // XXX is this safe will the validator unexposed fields be able to get written to? if stop { break diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index c2711788be..ad70958a3c 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -14,11 +14,12 @@ import ( // get a single validator func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator types.Validator, found bool) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorKey(addr)) - if b == nil { + value := store.Get(GetValidatorKey(addr)) + if value == nil { return validator, false } - k.cdc.MustUnmarshalBinary(b, &validator) + fmt.Printf("debug addr: %v\n", addr) + validator = types.UnmarshalValidator(k.cdc, addr, value) return validator, true } @@ -35,15 +36,13 @@ func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (val // set the main record holding validator details func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - // set main store - bz := k.cdc.MustMarshalBinary(validator) + bz := types.MarshalValidator(k.cdc, validator) store.Set(GetValidatorKey(validator.Owner), bz) } // validator index func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - // set pointer by pubkey store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner) } @@ -75,9 +74,8 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) if !iterator.Valid() { break } - bz := iterator.Value() - var validator types.Validator - k.cdc.MustUnmarshalBinary(bz, &validator) + addr := iterator.Key()[1:] + validator := types.UnmarshalValidator(k.cdc, addr, iterator.Value()) validators = append(validators, validator) iterator.Next() } @@ -96,9 +94,8 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators [] if !iterator.Valid() || i > int(maxRetrieve-1) { break } - bz := iterator.Value() - var validator types.Validator - k.cdc.MustUnmarshalBinary(bz, &validator) + addr := iterator.Key()[1:] + validator := types.UnmarshalValidator(k.cdc, addr, iterator.Value()) validators[i] = validator iterator.Next() } @@ -205,8 +202,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type // always update the main list ordered by owner address before exiting defer func() { - bz := k.cdc.MustMarshalBinary(validator) - store.Set(GetValidatorKey(ownerAddr), bz) + k.SetValidator(ctx, validator) }() // retrieve the old validator record @@ -441,8 +437,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) type k.SetPool(ctx, pool) // save the now unbonded validator record - bzVal := k.cdc.MustMarshalBinary(validator) - store.Set(GetValidatorKey(validator.Owner), bzVal) + k.SetValidator(ctx, validator) // add to accumulated changes for tendermint bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) @@ -469,8 +464,7 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. k.SetPool(ctx, pool) // save the now bonded validator record to the three referenced stores - bzVal := k.cdc.MustMarshalBinary(validator) - store.Set(GetValidatorKey(validator.Owner), bzVal) + k.SetValidator(ctx, validator) store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{}) // add to accumulated changes for tendermint diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 0a3c9cf4fc..34aa323772 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -118,7 +118,7 @@ func MarshalUBD(cdc *wire.Codec, ubd UnbondingDelegation) []byte { return cdc.MustMarshalBinary(val) } -// return the unbonding delegation without fields contained within the key for the store +// unmarshal a unbonding delegation from a store key and value func UnmarshalUBD(cdc *wire.Codec, key, value []byte) UnbondingDelegation { var storeValue ubdValue cdc.MustUnmarshalBinary(value, &storeValue) @@ -192,7 +192,7 @@ type redValue struct { SharesDst sdk.Rat } -// return the unbonding delegation without fields contained within the key for the store +// return the redelegation without fields contained within the key for the store func MarshalRED(cdc *wire.Codec, red Redelegation) []byte { val := redValue{ red.CreationHeight, @@ -205,7 +205,7 @@ func MarshalRED(cdc *wire.Codec, red Redelegation) []byte { return cdc.MustMarshalBinary(val) } -// return the unbonding delegation without fields contained within the key for the store +// unmarshal a redelegation from a store key and value func UnmarshalRED(cdc *wire.Codec, key, value []byte) Redelegation { var storeValue redValue cdc.MustUnmarshalBinary(value, &storeValue) diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index c2c19439be..a2a04b8659 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -9,6 +9,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) // Validator defines the total amount of bond shares and their exchange rate to @@ -60,6 +61,70 @@ func NewValidator(owner sdk.Address, pubKey crypto.PubKey, description Descripti } } +// what's kept in the store value +type validatorValue struct { + PubKey crypto.PubKey + Revoked bool + PoolShares PoolShares + DelegatorShares sdk.Rat + Description Description + BondHeight int64 + BondIntraTxCounter int16 + ProposerRewardPool sdk.Coins + Commission sdk.Rat + CommissionMax sdk.Rat + CommissionChangeRate sdk.Rat + CommissionChangeToday sdk.Rat + PrevBondedShares sdk.Rat +} + +// return the redelegation without fields contained within the key for the store +func MarshalValidator(cdc *wire.Codec, validator Validator) []byte { + val := validatorValue{ + PubKey: validator.PubKey, + Revoked: validator.Revoked, + PoolShares: validator.PoolShares, + DelegatorShares: validator.DelegatorShares, + Description: validator.Description, + BondHeight: validator.BondHeight, + BondIntraTxCounter: validator.BondIntraTxCounter, + ProposerRewardPool: validator.ProposerRewardPool, + Commission: validator.Commission, + CommissionMax: validator.CommissionMax, + CommissionChangeRate: validator.CommissionChangeRate, + CommissionChangeToday: validator.CommissionChangeToday, + PrevBondedShares: validator.PrevBondedShares, + } + return cdc.MustMarshalBinary(val) +} + +// unmarshal a redelegation from a store key and value +func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) Validator { + var storeValue validatorValue + cdc.MustUnmarshalBinary(value, &storeValue) + + if len(ownerAddr) != 20 { + panic("unexpected address length") + } + + return Validator{ + Owner: ownerAddr, + PubKey: storeValue.PubKey, + Revoked: storeValue.Revoked, + PoolShares: storeValue.PoolShares, + DelegatorShares: storeValue.DelegatorShares, + Description: storeValue.Description, + BondHeight: storeValue.BondHeight, + BondIntraTxCounter: storeValue.BondIntraTxCounter, + ProposerRewardPool: storeValue.ProposerRewardPool, + Commission: storeValue.Commission, + CommissionMax: storeValue.CommissionMax, + CommissionChangeRate: storeValue.CommissionChangeRate, + CommissionChangeToday: storeValue.CommissionChangeToday, + PrevBondedShares: storeValue.PrevBondedShares, + } +} + // only the vitals - does not check bond height of IntraTxCounter func (v Validator) Equal(c2 Validator) bool { return v.PubKey.Equals(c2.PubKey) && From e41f2bc8b597e3793e25b5868da79809ce743597 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Tue, 3 Jul 2018 23:25:31 -0700 Subject: [PATCH 22/53] tests: cli_tests no longer reset call `unsafe_reset_all` on local env * Makes all cli tests use .test_gaiad, .test_gaiacli instead of the same directories as the default binaries * Abstracts alot of the functionality for setting up the server into a single function / file-wide constants. This is to reduce code duplication, especially since some of this functionality depends on each test setting up the keys in the same way. Closes #1461 --- CHANGELOG.md | 1 + cmd/gaia/cli_test/cli_test.go | 104 ++++++++++++++++++---------------- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56bad46c37..d13fba9e46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ BUG FIXES * \#1353 - CLI: Show pool shares fractions in human-readable format * \#1258 - printing big.rat's can no longer overflow int64 * \#887 - limit the size of rationals that can be passed in from user input +* \#1461 - CLI tests now no longer reset your local environment data ## 0.19.0 diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 07230a4f90..7f04a78f40 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -3,6 +3,9 @@ package clitest import ( "encoding/json" "fmt" + "log" + "os" + "os/user" "testing" "github.com/stretchr/testify/require" @@ -21,30 +24,27 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake" ) +var ( + pass = "1234567890" + gaiadHome = "" + gaiacliHome = "" +) + +func init() { + gaiadHome, gaiacliHome = getTestingHomeDirs() +} + func TestGaiaCLISend(t *testing.T) { + flags, port, proc := resetTestEnv(t) - tests.ExecuteT(t, "gaiad unsafe_reset_all") - pass := "1234567890" - executeWrite(t, "gaiacli keys delete foo", pass) - executeWrite(t, "gaiacli keys delete bar", pass) - chainID := executeInit(t, "gaiad init -o --name=foo") - executeWrite(t, "gaiacli keys add bar", pass) - - // get a free port, also setup some common flags - servAddr, port, err := server.FreeTCPAddr() - require.NoError(t, err) - flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) - - // start gaiad server - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) tests.WaitForNextHeightTM(port) - fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") + fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) fooCech, err := sdk.Bech32ifyAcc(fooAddr) require.NoError(t, err) - barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") + barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) barCech, err := sdk.Bech32ifyAcc(barAddr) require.NoError(t, err) @@ -79,29 +79,15 @@ func TestGaiaCLISend(t *testing.T) { } func TestGaiaCLICreateValidator(t *testing.T) { - - tests.ExecuteT(t, "gaiad unsafe_reset_all") - pass := "1234567890" - executeWrite(t, "gaiacli keys delete foo", pass) - executeWrite(t, "gaiacli keys delete bar", pass) - chainID := executeInit(t, "gaiad init -o --name=foo") - executeWrite(t, "gaiacli keys add bar", pass) - - // get a free port, also setup some common flags - servAddr, port, err := server.FreeTCPAddr() - require.NoError(t, err) - flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) - - // start gaiad server - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) + flags, port, proc := resetTestEnv(t) defer proc.Stop(false) tests.WaitForTMStart(port) tests.WaitForNextHeightTM(port) - fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") + fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) fooCech, err := sdk.Bech32ifyAcc(fooAddr) require.NoError(t, err) - barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json") + barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) barCech, err := sdk.Bech32ifyAcc(barAddr) require.NoError(t, err) barCeshPubKey, err := sdk.Bech32ifyValPub(barPubKey) @@ -153,26 +139,12 @@ func TestGaiaCLICreateValidator(t *testing.T) { } func TestGaiaCLISubmitProposal(t *testing.T) { - - tests.ExecuteT(t, "gaiad unsafe_reset_all") - pass := "1234567890" - executeWrite(t, "gaiacli keys delete foo", pass) - executeWrite(t, "gaiacli keys delete bar", pass) - chainID := executeInit(t, "gaiad init -o --name=foo") - executeWrite(t, "gaiacli keys add bar", pass) - - // get a free port, also setup some common flags - servAddr, port, err := server.FreeTCPAddr() - require.NoError(t, err) - flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) - - // start gaiad server - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) + flags, port, proc := resetTestEnv(t) defer proc.Stop(false) tests.WaitForTMStart(port) tests.WaitForNextHeightTM(port) - fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") + fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) fooCech, err := sdk.Bech32ifyAcc(fooAddr) require.NoError(t, err) @@ -206,6 +178,40 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option) } +//___________________________________________________________________________________ +// helper methods + +func getTestingHomeDirs() (string, string) { + usr, err := user.Current() + if err != nil { + log.Fatal(err) + } + // Users home directory + home := usr.HomeDir + gaiadHome := fmt.Sprintf("%s%s.test_gaiad", home, string(os.PathSeparator)) + gaiacliHome := fmt.Sprintf("%s%s.test_gaiacli", home, string(os.PathSeparator)) + return gaiadHome, gaiacliHome +} + +// returns flags, port, process +func resetTestEnv(t *testing.T) (flags string, port string, proc *tests.Process) { + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + chainID := executeInit(t, "gaiad init -o --name=foo --home="+gaiadHome) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + + // get a free port, also setup some common flags + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) + flags = fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) + + // start gaiad server + proc = tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) + + return flags, port, proc +} + //___________________________________________________________________________________ // executors From 2c697c982b27281417b127565b9fc9b314f0fa37 Mon Sep 17 00:00:00 2001 From: Fabian Weber Date: Wed, 4 Jul 2018 10:42:30 +0200 Subject: [PATCH 23/53] added sunnys changes --- client/keys/add.go | 25 +++++++------------------ client/lcd/lcd_test.go | 2 +- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index 216f84c2ac..4d4dee0b9c 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -7,7 +7,6 @@ import ( "net/http" "github.com/cosmos/cosmos-sdk/client" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/gorilla/mux" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -162,12 +161,6 @@ type NewKeyBody struct { Password string `json:"password"` } -// new key response REST body -type NewKeyResponse struct { - Address string `json:"address"` - Mnemonic string `json:"mnemonic"` -} - // add new key REST handler func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) { var kb keys.Keybase @@ -216,22 +209,18 @@ func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte(err.Error())) return } - bech32Account, err := sdk.Bech32ifyAcc(sdk.Address(info.GetPubKey().Address().Bytes())) + + keyOutput, err := Bech32KeyOutput(info) + keyOutput.Seed = mnemonic + + output, err := json.MarshalIndent(keyOutput, "", " ") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } - bz, err := json.Marshal(NewKeyResponse{ - Address: bech32Account, - Mnemonic: mnemonic, - }) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - w.Write(bz) + + w.Write(output) } // function to just a new seed to display in the UI before actually persisting it in the keybase diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index bb2a205a96..234ed57b01 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -56,7 +56,7 @@ func TestKeys(t *testing.T) { res, body = Request(t, port, "POST", "/keys", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) - var resp keys.NewKeyResponse + var resp keys.KeyOutput err = wire.Cdc.UnmarshalJSON([]byte(body), &resp) require.Nil(t, err, body) From 557e652530c0880702e1a23ac9c9590be7113b38 Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Wed, 4 Jul 2018 09:23:01 -0400 Subject: [PATCH 24/53] docs: fix dead links, closes #1508 --- docs/core/app1.md | 6 +++--- docs/core/app4.md | 2 +- docs/spec/slashing/end_block.md | 2 +- examples/README.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 91e75966a7..ba7f02a8d8 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -189,7 +189,7 @@ docs](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Context) for more det ### Result Handler takes a Context and Msg and returns a Result. -Result is motivated by the corresponding [ABCI result](https://github.com/tendermint/tendermint/abci/blob/master/types/types.proto#L165). +Result is motivated by the corresponding [ABCI result](https://github.com/tendermint/tendermint/blob/master/abci/types/types.proto#L165). It contains return values, error information, logs, and meta data about the transaction: ```go @@ -409,7 +409,7 @@ func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { Finally, we stitch it all together using the `BaseApp`. The BaseApp is an abstraction over the [Tendermint -ABCI](https://github.com/tendermint/tendermint/abci) that +ABCI](https://github.com/tendermint/tendermint/tree/master/abci) that simplifies application development by handling common low-level concerns. It serves as the mediator between the two key components of an SDK app: the store and the message handlers. The BaseApp implements the @@ -473,7 +473,7 @@ Tendermint consensus engine. It would be initialized by a Genesis file, and it would be driven by blocks of transactions committed by the underlying Tendermint consensus. We'll talk more about ABCI and how this all works a bit later, but feel free to check the -[specification](https://github.com/tendermint/tendermint/abci/blob/master/specification.md). +[specification](https://github.com/tendermint/tendermint/blob/master/docs/abci-spec.md). We'll also see how to connect our app to a complete suite of components for running and using a live blockchain application. diff --git a/docs/core/app4.md b/docs/core/app4.md index d7226b4666..0724e5e7a8 100644 --- a/docs/core/app4.md +++ b/docs/core/app4.md @@ -16,7 +16,7 @@ here we will introduce the other ABCI requests sent by Tendermint, and how we can use them to build more advanced applications. For a more complete depiction of the ABCI and how its used, see [the -specification](https://github.com/tendermint/tendermint/abci/blob/master/specification.md) +specification](https://github.com/tendermint/tendermint/blob/master/docs/abci-spec.md) ## InitChain diff --git a/docs/spec/slashing/end_block.md b/docs/spec/slashing/end_block.md index e923fd8444..3eec27372c 100644 --- a/docs/spec/slashing/end_block.md +++ b/docs/spec/slashing/end_block.md @@ -6,7 +6,7 @@ Tendermint blocks can include [Evidence](https://github.com/tendermint/tendermint/blob/develop/docs/spec/blockchain/blockchain.md#evidence), which indicates that a validator committed malicious behaviour. The relevant information is forwarded to the application as [ABCI -Evidence](https://github.com/tendermint/tendermint/abci/blob/develop/types/types.proto#L259), so the validator an be accordingly punished. +Evidence](https://github.com/tendermint/tendermint/blob/develop/abci/types/types.proto#L259), so the validator an be accordingly punished. For some `evidence` to be valid, it must satisfy: diff --git a/examples/README.md b/examples/README.md index 3f45e025cf..a8a483ee62 100644 --- a/examples/README.md +++ b/examples/README.md @@ -256,7 +256,7 @@ Accounts are serialized and stored in a Merkle tree under the key Typically, the address of the account is the 20-byte ``RIPEMD160`` hash of the public key, but other formats are acceptable as well, as defined in the `Tendermint crypto -library `__. The Merkle tree +library `__. The Merkle tree used in Basecoin is a balanced, binary search tree, which we call an `IAVL tree `__. From 59983787735ff9fd141e2eefe8c33e66f9c1e96c Mon Sep 17 00:00:00 2001 From: Fabian Weber Date: Wed, 4 Jul 2018 16:39:16 +0200 Subject: [PATCH 25/53] added error check --- client/keys/add.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/keys/add.go b/client/keys/add.go index 4d4dee0b9c..b763546850 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -211,6 +211,12 @@ func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) { } keyOutput, err := Bech32KeyOutput(info) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + keyOutput.Seed = mnemonic output, err := json.MarshalIndent(keyOutput, "", " ") From b0e6c765543aac883dcab11018c2ca68475cf124 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Wed, 4 Jul 2018 08:20:44 -0700 Subject: [PATCH 26/53] Remove redundant comment, switch to MustBech32ify --- cmd/gaia/cli_test/cli_test.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 7f04a78f40..98f393ec5d 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -42,11 +42,9 @@ func TestGaiaCLISend(t *testing.T) { tests.WaitForNextHeightTM(port) fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) - fooCech, err := sdk.Bech32ifyAcc(fooAddr) - require.NoError(t, err) + fooCech := sdk.MustBech32ifyAcc(fooAddr) barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) - barCech, err := sdk.Bech32ifyAcc(barAddr) - require.NoError(t, err) + barCech := sdk.MustBech32ifyAcc(barAddr) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) @@ -85,13 +83,10 @@ func TestGaiaCLICreateValidator(t *testing.T) { tests.WaitForNextHeightTM(port) fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) - fooCech, err := sdk.Bech32ifyAcc(fooAddr) - require.NoError(t, err) + fooCech := sdk.MustBech32ifyAcc(fooAddr) barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) - barCech, err := sdk.Bech32ifyAcc(barAddr) - require.NoError(t, err) - barCeshPubKey, err := sdk.Bech32ifyValPub(barPubKey) - require.NoError(t, err) + barCech := sdk.MustBech32ifyAcc(barAddr) + barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) @@ -145,8 +140,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { tests.WaitForNextHeightTM(port) fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) - fooCech, err := sdk.Bech32ifyAcc(fooAddr) - require.NoError(t, err) + fooCech := sdk.MustBech32ifyAcc(fooAddr) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) @@ -186,7 +180,6 @@ func getTestingHomeDirs() (string, string) { if err != nil { log.Fatal(err) } - // Users home directory home := usr.HomeDir gaiadHome := fmt.Sprintf("%s%s.test_gaiad", home, string(os.PathSeparator)) gaiacliHome := fmt.Sprintf("%s%s.test_gaiacli", home, string(os.PathSeparator)) From 319358c587d709ecfb6a1bf38c7fdfa3b2d4e39b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 4 Jul 2018 14:34:55 -0400 Subject: [PATCH 27/53] changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56bad46c37..b356641404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,8 +37,9 @@ BREAKING CHANGES * Add REST endpoint to unrevoke a validator previously revoked for downtime * Add REST endpoint to retrieve liveness signing information for a validator * [types] renamed rational.Evaluate to rational.Round{Int64, Int} -* [stake] most index keys nolonger hold a value - inputs are rearranged to form the desired key +* [x/stake] most index keys nolonger hold a value - inputs are rearranged to form the desired key * [lcd] Switch key creation output to return bech32 +* [x/stake] store-value for delegation, validator, ubd, and red do not hold duplicate information contained store-key FEATURES * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag From 640bccf8f798e98f47c1eb40ac7c1373a68d468c Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Wed, 4 Jul 2018 13:09:59 -0700 Subject: [PATCH 28/53] Switch using user home to a tmp directory --- cmd/gaia/cli_test/cli_test.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 98f393ec5d..eb5b988b75 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -3,9 +3,7 @@ package clitest import ( "encoding/json" "fmt" - "log" "os" - "os/user" "testing" "github.com/stretchr/testify/require" @@ -176,13 +174,9 @@ func TestGaiaCLISubmitProposal(t *testing.T) { // helper methods func getTestingHomeDirs() (string, string) { - usr, err := user.Current() - if err != nil { - log.Fatal(err) - } - home := usr.HomeDir - gaiadHome := fmt.Sprintf("%s%s.test_gaiad", home, string(os.PathSeparator)) - gaiacliHome := fmt.Sprintf("%s%s.test_gaiacli", home, string(os.PathSeparator)) + tmpDir := os.TempDir() + gaiadHome := fmt.Sprintf("%s%s.test_gaiad", tmpDir, string(os.PathSeparator)) + gaiacliHome := fmt.Sprintf("%s%s.test_gaiacli", tmpDir, string(os.PathSeparator)) return gaiadHome, gaiacliHome } From aed3a873669d9c84f7087be78e7320e0a2dd7baf Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 4 Jul 2018 17:07:06 -0400 Subject: [PATCH 29/53] address cwgoes comments --- types/account.go | 6 ++- x/stake/client/cli/query.go | 16 +++---- x/stake/client/rest/query.go | 28 +++++++++-- x/stake/keeper/delegation.go | 20 ++++---- x/stake/keeper/key.go | 22 ++++----- x/stake/keeper/sdk_types.go | 4 +- x/stake/keeper/validator.go | 9 ++-- x/stake/types/delegation.go | 90 ++++++++++++++++++++++++++---------- x/stake/types/validator.go | 25 ++++++++-- 9 files changed, 149 insertions(+), 71 deletions(-) diff --git a/types/account.go b/types/account.go index ce872d8b54..0cdc75fe2d 100644 --- a/types/account.go +++ b/types/account.go @@ -13,8 +13,12 @@ import ( //Address is a go crypto-style Address type Address = cmn.HexBytes -// Bech32 prefixes +// nolint const ( + // expected address length + AddrLen = 20 + + // Bech32 prefixes Bech32PrefixAccAddr = "cosmosaccaddr" Bech32PrefixAccPub = "cosmosaccpub" Bech32PrefixValAddr = "cosmosvaladdr" diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index ee495e96e0..39c7771f0a 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -33,7 +33,7 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { return err } - validator := types.UnmarshalValidator(cdc, addr, res) + validator := types.MustUnmarshalValidator(cdc, addr, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -77,7 +77,7 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { var validators []stake.Validator for _, kv := range resKVs { addr := kv.Key[1:] - validator := types.UnmarshalValidator(cdc, addr, kv.Value) + validator := types.MustUnmarshalValidator(cdc, addr, kv.Value) validators = append(validators, validator) } @@ -131,7 +131,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { } // parse out the delegation - delegation := types.UnmarshalDelegation(cdc, key, res) + delegation := types.MustUnmarshalDelegation(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -179,7 +179,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { // parse out the validators var delegations []stake.Delegation for _, kv := range resKVs { - delegation := types.UnmarshalDelegation(cdc, kv.Key, kv.Value) + delegation := types.MustUnmarshalDelegation(cdc, kv.Key, kv.Value) delegations = append(delegations, delegation) } @@ -221,7 +221,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co } // parse out the unbonding delegation - ubd := types.UnmarshalUBD(cdc, key, res) + ubd := types.MustUnmarshalUBD(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -269,7 +269,7 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C // parse out the validators var ubds []stake.UnbondingDelegation for _, kv := range resKVs { - ubd := types.UnmarshalUBD(cdc, kv.Key, kv.Value) + ubd := types.MustUnmarshalUBD(cdc, kv.Key, kv.Value) ubds = append(ubds, ubd) } @@ -314,7 +314,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { } // parse out the unbonding delegation - red := types.UnmarshalRED(cdc, key, res) + red := types.MustUnmarshalRED(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -362,7 +362,7 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command // parse out the validators var reds []stake.Redelegation for _, kv := range resKVs { - red := types.UnmarshalRED(cdc, kv.Key, kv.Value) + red := types.MustUnmarshalRED(cdc, kv.Key, kv.Value) reds = append(reds, red) } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 49051c73ef..090445f0a8 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -77,7 +77,12 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF return } - delegation := types.UnmarshalDelegation(cdc, key, res) + delegation, err := types.UnmarshalDelegation(cdc, key, res) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } output, err := cdc.MarshalJSON(delegation) if err != nil { @@ -128,7 +133,12 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - ubd := types.UnmarshalUBD(cdc, key, res) + ubd, err := types.UnmarshalUBD(cdc, key, res) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) + return + } output, err := cdc.MarshalJSON(ubd) if err != nil { @@ -187,7 +197,12 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - red := types.UnmarshalRED(cdc, key, res) + red, err := types.UnmarshalRED(cdc, key, res) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) + return + } output, err := cdc.MarshalJSON(red) if err != nil { @@ -277,7 +292,12 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF for i, kv := range kvs { addr := kv.Key[1:] - validator := types.UnmarshalValidator(cdc, addr, kv.Value) + validator, err := types.UnmarshalValidator(cdc, addr, kv.Value) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) + return + } bech32Validator, err := bech32StakeValidatorOutput(validator) if err != nil { diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 3d949a9a0a..353154ce22 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -18,7 +18,7 @@ func (k Keeper) GetDelegation(ctx sdk.Context, return delegation, false } - delegation = types.UnmarshalDelegation(k.cdc, key, value) + delegation = types.MustUnmarshalDelegation(k.cdc, key, value) return delegation, true } @@ -32,7 +32,7 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati if !iterator.Valid() { break } - delegation := types.UnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) delegations = append(delegations, delegation) iterator.Next() } @@ -54,7 +54,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, if !iterator.Valid() || i > int(maxRetrieve-1) { break } - delegation := types.UnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) delegations[i] = delegation iterator.Next() } @@ -65,7 +65,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, // set the delegation func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey) - b := types.MarshalDelegation(k.cdc, delegation) + b := types.MustMarshalDelegation(k.cdc, delegation) store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b) } @@ -88,7 +88,7 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, return ubd, false } - ubd = types.UnmarshalUBD(k.cdc, key, value) + ubd = types.MustUnmarshalUBD(k.cdc, key, value) return ubd, true } @@ -102,7 +102,7 @@ func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sd } key := GetUBDKeyFromValIndexKey(iterator.Key()) value := store.Get(key) - ubd := types.UnmarshalUBD(k.cdc, key, value) + ubd := types.MustUnmarshalUBD(k.cdc, key, value) ubds = append(ubds, ubd) iterator.Next() } @@ -113,7 +113,7 @@ func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sd // set the unbonding delegation and associated index func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - bz := types.MarshalUBD(k.cdc, ubd) + bz := types.MustMarshalUBD(k.cdc, ubd) key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) store.Set(key, bz) store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) // index, store empty bytes @@ -140,7 +140,7 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, return red, false } - red = types.UnmarshalRED(k.cdc, key, value) + red = types.MustUnmarshalRED(k.cdc, key, value) return red, true } @@ -154,7 +154,7 @@ func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Addre } key := GetREDKeyFromValSrcIndexKey(iterator.Key()) value := store.Get(key) - red := types.UnmarshalRED(k.cdc, key, value) + red := types.MustUnmarshalRED(k.cdc, key, value) reds = append(reds, red) iterator.Next() } @@ -182,7 +182,7 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, // set a redelegation and associated index func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) - bz := types.MarshalRED(k.cdc, red) + bz := types.MustMarshalRED(k.cdc, red) key := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) store.Set(key, bz) store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index cfe8ded82b..32c54f5196 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -131,11 +131,11 @@ func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address) []byte { // rearrange the ValIndexKey to get the UBDKey func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes - if len(addrs) != 40 { + if len(addrs) != 2*sdk.AddrLen { panic("unexpected key length") } - valAddr := addrs[:20] - delAddr := addrs[20:] + valAddr := addrs[:sdk.AddrLen] + delAddr := addrs[sdk.AddrLen:] return GetUBDKey(delAddr, valAddr) } @@ -189,12 +189,12 @@ func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, // rearrange the ValSrcIndexKey to get the REDKey func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes - if len(addrs) != 60 { + if len(addrs) != 3*sdk.AddrLen { panic("unexpected key length") } - valSrcAddr := addrs[:20] - delAddr := addrs[20:40] - valDstAddr := addrs[40:] + valSrcAddr := addrs[:sdk.AddrLen] + delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen] + valDstAddr := addrs[2*sdk.AddrLen:] return GetREDKey(delAddr, valSrcAddr, valDstAddr) } @@ -202,12 +202,12 @@ func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { // rearrange the ValDstIndexKey to get the REDKey func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes - if len(addrs) != 60 { + if len(addrs) != 3*sdk.AddrLen { panic("unexpected key length") } - valDstAddr := addrs[:20] - delAddr := addrs[20:40] - valSrcAddr := addrs[40:] + valDstAddr := addrs[:sdk.AddrLen] + delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen] + valSrcAddr := addrs[2*sdk.AddrLen:] return GetREDKey(delAddr, valSrcAddr, valDstAddr) } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 0fe465892c..b8be3e34f8 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -17,7 +17,7 @@ func (k Keeper) IterateValidators(ctx sdk.Context, fn func(index int64, validato i := int64(0) for ; iterator.Valid(); iterator.Next() { addr := iterator.Key()[1:] - validator := types.UnmarshalValidator(k.cdc, addr, iterator.Value()) + validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) stop := fn(i, validator) // XXX is this safe will the validator unexposed fields be able to get written to? if stop { break @@ -90,7 +90,7 @@ func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func iterator := sdk.KVStorePrefixIterator(store, key) i := int64(0) for ; iterator.Valid(); iterator.Next() { - delegation := types.UnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to? if stop { break diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index ad70958a3c..164c500492 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -18,8 +18,7 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator types if value == nil { return validator, false } - fmt.Printf("debug addr: %v\n", addr) - validator = types.UnmarshalValidator(k.cdc, addr, value) + validator = types.MustUnmarshalValidator(k.cdc, addr, value) return validator, true } @@ -36,7 +35,7 @@ func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (val // set the main record holding validator details func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - bz := types.MarshalValidator(k.cdc, validator) + bz := types.MustMarshalValidator(k.cdc, validator) store.Set(GetValidatorKey(validator.Owner), bz) } @@ -75,7 +74,7 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) break } addr := iterator.Key()[1:] - validator := types.UnmarshalValidator(k.cdc, addr, iterator.Value()) + validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) validators = append(validators, validator) iterator.Next() } @@ -95,7 +94,7 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators [] break } addr := iterator.Key()[1:] - validator := types.UnmarshalValidator(k.cdc, addr, iterator.Value()) + validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) validators[i] = validator iterator.Next() } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 7b9d45c0d8..f7d31a6407 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "errors" "fmt" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,7 +25,7 @@ type delegationValue struct { } // return the delegation without fields contained within the key for the store -func MarshalDelegation(cdc *wire.Codec, delegation Delegation) []byte { +func MustMarshalDelegation(cdc *wire.Codec, delegation Delegation) []byte { val := delegationValue{ delegation.Shares, delegation.Height, @@ -33,23 +34,36 @@ func MarshalDelegation(cdc *wire.Codec, delegation Delegation) []byte { } // return the delegation without fields contained within the key for the store -func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) Delegation { +func MustUnmarshalDelegation(cdc *wire.Codec, key, value []byte) Delegation { + delegation, err := UnmarshalDelegation(cdc, key, value) + if err != nil { + panic(err) + } + return delegation +} + +// return the delegation without fields contained within the key for the store +func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) (delegation Delegation, err error) { var storeValue delegationValue - cdc.MustUnmarshalBinary(value, &storeValue) + err = cdc.UnmarshalBinary(value, &storeValue) + if err != nil { + return + } addrs := key[1:] // remove prefix bytes - if len(addrs) != 40 { - panic("unexpected key length") + if len(addrs) != 2*sdk.AddrLen { + err = errors.New("unexpected key length") + return } - delAddr := sdk.Address(addrs[:20]) - valAddr := sdk.Address(addrs[20:]) + delAddr := sdk.Address(addrs[:sdk.AddrLen]) + valAddr := sdk.Address(addrs[sdk.AddrLen:]) return Delegation{ DelegatorAddr: delAddr, ValidatorAddr: valAddr, Shares: storeValue.Shares, Height: storeValue.Height, - } + }, nil } // nolint @@ -109,7 +123,7 @@ type ubdValue struct { } // return the unbonding delegation without fields contained within the key for the store -func MarshalUBD(cdc *wire.Codec, ubd UnbondingDelegation) []byte { +func MustMarshalUBD(cdc *wire.Codec, ubd UnbondingDelegation) []byte { val := ubdValue{ ubd.CreationHeight, ubd.MinTime, @@ -120,16 +134,29 @@ func MarshalUBD(cdc *wire.Codec, ubd UnbondingDelegation) []byte { } // unmarshal a unbonding delegation from a store key and value -func UnmarshalUBD(cdc *wire.Codec, key, value []byte) UnbondingDelegation { +func MustUnmarshalUBD(cdc *wire.Codec, key, value []byte) UnbondingDelegation { + ubd, err := UnmarshalUBD(cdc, key, value) + if err != nil { + panic(err) + } + return ubd +} + +// unmarshal a unbonding delegation from a store key and value +func UnmarshalUBD(cdc *wire.Codec, key, value []byte) (ubd UnbondingDelegation, err error) { var storeValue ubdValue - cdc.MustUnmarshalBinary(value, &storeValue) + err = cdc.UnmarshalBinary(value, &storeValue) + if err != nil { + return + } addrs := key[1:] // remove prefix bytes - if len(addrs) != 40 { - panic("unexpected key length") + if len(addrs) != 2*sdk.AddrLen { + err = errors.New("unexpected key length") + return } - delAddr := sdk.Address(addrs[:20]) - valAddr := sdk.Address(addrs[20:]) + delAddr := sdk.Address(addrs[:sdk.AddrLen]) + valAddr := sdk.Address(addrs[sdk.AddrLen:]) return UnbondingDelegation{ DelegatorAddr: delAddr, @@ -138,7 +165,7 @@ func UnmarshalUBD(cdc *wire.Codec, key, value []byte) UnbondingDelegation { MinTime: storeValue.MinTime, InitialBalance: storeValue.InitialBalance, Balance: storeValue.Balance, - } + }, nil } // nolint @@ -196,7 +223,7 @@ type redValue struct { } // return the redelegation without fields contained within the key for the store -func MarshalRED(cdc *wire.Codec, red Redelegation) []byte { +func MustMarshalRED(cdc *wire.Codec, red Redelegation) []byte { val := redValue{ red.CreationHeight, red.MinTime, @@ -209,17 +236,30 @@ func MarshalRED(cdc *wire.Codec, red Redelegation) []byte { } // unmarshal a redelegation from a store key and value -func UnmarshalRED(cdc *wire.Codec, key, value []byte) Redelegation { +func MustUnmarshalRED(cdc *wire.Codec, key, value []byte) Redelegation { + red, err := UnmarshalRED(cdc, key, value) + if err != nil { + panic(err) + } + return red +} + +// unmarshal a redelegation from a store key and value +func UnmarshalRED(cdc *wire.Codec, key, value []byte) (red Redelegation, err error) { var storeValue redValue - cdc.MustUnmarshalBinary(value, &storeValue) + err = cdc.UnmarshalBinary(value, &storeValue) + if err != nil { + return + } addrs := key[1:] // remove prefix bytes - if len(addrs) != 60 { - panic("unexpected key length") + if len(addrs) != 3*sdk.AddrLen { + err = errors.New("unexpected key length") + return } - delAddr := sdk.Address(addrs[:20]) - valSrcAddr := sdk.Address(addrs[20:40]) - valDstAddr := sdk.Address(addrs[40:60]) + delAddr := sdk.Address(addrs[:sdk.AddrLen]) + valSrcAddr := sdk.Address(addrs[sdk.AddrLen : 2*sdk.AddrLen]) + valDstAddr := sdk.Address(addrs[2*sdk.AddrLen:]) return Redelegation{ DelegatorAddr: delAddr, @@ -231,7 +271,7 @@ func UnmarshalRED(cdc *wire.Codec, key, value []byte) Redelegation { Balance: storeValue.Balance, SharesSrc: storeValue.SharesSrc, SharesDst: storeValue.SharesDst, - } + }, nil } // nolint diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 80ee70355c..480416d015 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "errors" "fmt" abci "github.com/tendermint/tendermint/abci/types" @@ -81,7 +82,7 @@ type validatorValue struct { } // return the redelegation without fields contained within the key for the store -func MarshalValidator(cdc *wire.Codec, validator Validator) []byte { +func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte { val := validatorValue{ PubKey: validator.PubKey, Revoked: validator.Revoked, @@ -101,12 +102,26 @@ func MarshalValidator(cdc *wire.Codec, validator Validator) []byte { } // unmarshal a redelegation from a store key and value -func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) Validator { +func MustUnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) Validator { + validator, err := UnmarshalValidator(cdc, ownerAddr, value) + if err != nil { + panic(err) + } + + return validator +} + +// unmarshal a redelegation from a store key and value +func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Validator, err error) { var storeValue validatorValue - cdc.MustUnmarshalBinary(value, &storeValue) + err = cdc.UnmarshalBinary(value, &storeValue) + if err != nil { + return + } if len(ownerAddr) != 20 { - panic("unexpected address length") + err = errors.New("unexpected address length") + return } return Validator{ @@ -124,7 +139,7 @@ func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) Validator { CommissionChangeRate: storeValue.CommissionChangeRate, CommissionChangeToday: storeValue.CommissionChangeToday, PrevBondedShares: storeValue.PrevBondedShares, - } + }, nil } // only the vitals - does not check bond height of IntraTxCounter From 22ec6ad98d789e38c0acc710d2f854376438c0fd Mon Sep 17 00:00:00 2001 From: Joon Date: Thu, 5 Jul 2018 09:04:21 -0700 Subject: [PATCH 30/53] Merge pull request #1532 : Add Codec.Seal fix wire --- baseapp/baseapp_test.go | 1 + cmd/gaia/cmd/gaiadebug/hack.go | 1 + examples/basecoin/app/app.go | 2 ++ examples/democoin/app/app.go | 3 +++ examples/democoin/x/oracle/oracle_test.go | 2 ++ wire/wire.go | 3 +-- x/ibc/ibc_test.go | 2 ++ 7 files changed, 12 insertions(+), 2 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 4eea49fd39..e919375d90 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -769,6 +769,7 @@ func MakeCodec() *wire.Codec { crypto.RegisterAmino(cdc) cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&auth.BaseAccount{}, "cosmos-sdk/BaseAccount", nil) + cdc.Seal() return cdc } diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 1f2ef0649d..ddc8466c76 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -197,6 +197,7 @@ func MakeCodec() *wire.Codec { auth.RegisterWire(cdc) sdk.RegisterWire(cdc) wire.RegisterCrypto(cdc) + cdc.Seal() return cdc } diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index f75d6a834e..6df74ef28c 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -103,6 +103,8 @@ func MakeCodec() *wire.Codec { cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&types.AppAccount{}, "basecoin/Account", nil) + cdc.Seal() + return cdc } diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 1c44a0bbdf..6ea7d52472 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -113,6 +113,9 @@ func MakeCodec() *wire.Codec { // Register AppAccount cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&types.AppAccount{}, "democoin/Account", nil) + + cdc.Seal() + return cdc } diff --git a/examples/democoin/x/oracle/oracle_test.go b/examples/democoin/x/oracle/oracle_test.go index ef925c94f4..467035897d 100644 --- a/examples/democoin/x/oracle/oracle_test.go +++ b/examples/democoin/x/oracle/oracle_test.go @@ -48,6 +48,8 @@ func makeCodec() *wire.Codec { cdc.RegisterInterface((*Payload)(nil), nil) cdc.RegisterConcrete(seqOracle{}, "test/oracle/seqOracle", nil) + cdc.Seal() + return cdc } diff --git a/wire/wire.go b/wire/wire.go index 1d5291f860..679bf7c28a 100644 --- a/wire/wire.go +++ b/wire/wire.go @@ -44,6 +44,5 @@ var Cdc *Codec func init() { cdc := NewCodec() RegisterCrypto(cdc) - Cdc = cdc - //Cdc = cdc.Seal() // TODO uncomment once amino upgraded to 0.9.10 + Cdc = cdc.Seal() } diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index 4cb708c1bb..1d87e7806b 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -53,6 +53,8 @@ func makeCodec() *wire.Codec { cdc.RegisterConcrete(&auth.BaseAccount{}, "test/ibc/Account", nil) wire.RegisterCrypto(cdc) + cdc.Seal() + return cdc } From 492272c5e6a03db5c9c802b4589f3b69f91e337e Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 09:08:43 -0700 Subject: [PATCH 31/53] cli_test: Un-abstract common code This is done to enhance readability, so one can easily reproduce the functionality in the command line. --- cmd/gaia/cli_test/cli_test.go | 63 +++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index eb5b988b75..17c7279591 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -33,7 +33,19 @@ func init() { } func TestGaiaCLISend(t *testing.T) { - flags, port, proc := resetTestEnv(t) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + chainID := executeInit(t, "gaiad init -o --name=foo --home="+gaiadHome) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + + // get a free port, also setup some common flags + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) + flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) + + // start gaiad server + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) @@ -75,7 +87,20 @@ func TestGaiaCLISend(t *testing.T) { } func TestGaiaCLICreateValidator(t *testing.T) { - flags, port, proc := resetTestEnv(t) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + chainID := executeInit(t, "gaiad init -o --name=foo --home="+gaiadHome) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + + // get a free port, also setup some common flags + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) + flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) + + // start gaiad server + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) + defer proc.Stop(false) tests.WaitForTMStart(port) tests.WaitForNextHeightTM(port) @@ -132,7 +157,20 @@ func TestGaiaCLICreateValidator(t *testing.T) { } func TestGaiaCLISubmitProposal(t *testing.T) { - flags, port, proc := resetTestEnv(t) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + chainID := executeInit(t, "gaiad init -o --name=foo --home="+gaiadHome) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + + // get a free port, also setup some common flags + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) + flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) + + // start gaiad server + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) + defer proc.Stop(false) tests.WaitForTMStart(port) tests.WaitForNextHeightTM(port) @@ -180,25 +218,6 @@ func getTestingHomeDirs() (string, string) { return gaiadHome, gaiacliHome } -// returns flags, port, process -func resetTestEnv(t *testing.T) (flags string, port string, proc *tests.Process) { - tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, "gaiad init -o --name=foo --home="+gaiadHome) - executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) - - // get a free port, also setup some common flags - servAddr, port, err := server.FreeTCPAddr() - require.NoError(t, err) - flags = fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) - - // start gaiad server - proc = tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) - - return flags, port, proc -} - //___________________________________________________________________________________ // executors From 547390a238b23024f24ee79898b4b61f783f1682 Mon Sep 17 00:00:00 2001 From: Liamsi Date: Thu, 5 Jul 2018 17:11:44 +0100 Subject: [PATCH 32/53] WIP: add simple sorting using golang json.Marshal --- Gopkg.lock | 512 -------------------------------------------- server/util.go | 17 ++ server/util_test.go | 4 + 3 files changed, 21 insertions(+), 512 deletions(-) delete mode 100644 Gopkg.lock diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index 7a9b566965..0000000000 --- a/Gopkg.lock +++ /dev/null @@ -1,512 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - branch = "master" - name = "github.com/bartekn/go-bip39" - packages = ["."] - revision = "a05967ea095d81c8fe4833776774cfaff8e5036c" - -[[projects]] - branch = "master" - name = "github.com/beorn7/perks" - packages = ["quantile"] - revision = "3a771d992973f24aa725d07868b467d1ddfceafb" - -[[projects]] - name = "github.com/bgentry/speakeasy" - packages = ["."] - revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd" - version = "v0.1.0" - -[[projects]] - branch = "master" - name = "github.com/brejski/hid" - packages = ["."] - revision = "06112dcfcc50a7e0e4fd06e17f9791e788fdaafc" - -[[projects]] - branch = "master" - name = "github.com/btcsuite/btcd" - packages = ["btcec"] - revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64" - -[[projects]] - branch = "master" - name = "github.com/btcsuite/btcutil" - packages = ["bech32"] - revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4" - -[[projects]] - name = "github.com/davecgh/go-spew" - packages = ["spew"] - revision = "346938d642f2ec3594ed81d874461961cd0faa76" - version = "v1.1.0" - -[[projects]] - branch = "master" - name = "github.com/ebuchman/fail-test" - packages = ["."] - revision = "95f809107225be108efcf10a3509e4ea6ceef3c4" - -[[projects]] - name = "github.com/fsnotify/fsnotify" - packages = ["."] - revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" - version = "v1.4.7" - -[[projects]] - name = "github.com/go-kit/kit" - packages = [ - "log", - "log/level", - "log/term", - "metrics", - "metrics/discard", - "metrics/internal/lv", - "metrics/prometheus" - ] - revision = "4dc7be5d2d12881735283bcab7352178e190fc71" - version = "v0.6.0" - -[[projects]] - name = "github.com/go-logfmt/logfmt" - packages = ["."] - revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" - version = "v0.3.0" - -[[projects]] - name = "github.com/go-stack/stack" - packages = ["."] - revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" - version = "v1.7.0" - -[[projects]] - name = "github.com/gogo/protobuf" - packages = [ - "gogoproto", - "jsonpb", - "proto", - "protoc-gen-gogo/descriptor", - "sortkeys", - "types" - ] - revision = "1adfc126b41513cc696b209667c8656ea7aac67c" - version = "v1.0.0" - -[[projects]] - name = "github.com/golang/protobuf" - packages = [ - "proto", - "ptypes", - "ptypes/any", - "ptypes/duration", - "ptypes/timestamp" - ] - revision = "925541529c1fa6821df4e44ce2723319eb2be768" - version = "v1.0.0" - -[[projects]] - branch = "master" - name = "github.com/golang/snappy" - packages = ["."] - revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" - -[[projects]] - name = "github.com/gorilla/context" - packages = ["."] - revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" - version = "v1.1.1" - -[[projects]] - name = "github.com/gorilla/mux" - packages = ["."] - revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf" - version = "v1.6.2" - -[[projects]] - name = "github.com/gorilla/websocket" - packages = ["."] - revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b" - version = "v1.2.0" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/hcl" - packages = [ - ".", - "hcl/ast", - "hcl/parser", - "hcl/printer", - "hcl/scanner", - "hcl/strconv", - "hcl/token", - "json/parser", - "json/scanner", - "json/token" - ] - revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" - -[[projects]] - name = "github.com/inconshreveable/mousetrap" - packages = ["."] - revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" - version = "v1.0" - -[[projects]] - branch = "master" - name = "github.com/jmhodges/levigo" - packages = ["."] - revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" - -[[projects]] - branch = "master" - name = "github.com/kr/logfmt" - packages = ["."] - revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0" - -[[projects]] - name = "github.com/magiconair/properties" - packages = ["."] - revision = "c2353362d570a7bfa228149c62842019201cfb71" - version = "v1.8.0" - -[[projects]] - name = "github.com/mattn/go-isatty" - packages = ["."] - revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" - version = "v0.0.3" - -[[projects]] - name = "github.com/matttproud/golang_protobuf_extensions" - packages = ["pbutil"] - revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" - version = "v1.0.1" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/mapstructure" - packages = ["."] - revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b" - -[[projects]] - name = "github.com/pelletier/go-toml" - packages = ["."] - revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" - version = "v1.2.0" - -[[projects]] - name = "github.com/pkg/errors" - packages = ["."] - revision = "645ef00459ed84a119197bfb8d8205042c6df63d" - version = "v0.8.0" - -[[projects]] - name = "github.com/pmezard/go-difflib" - packages = ["difflib"] - revision = "792786c7400a136282c1664665ae0a8db921c6c2" - version = "v1.0.0" - -[[projects]] - name = "github.com/prometheus/client_golang" - packages = [ - "prometheus", - "prometheus/promhttp" - ] - revision = "c5b7fccd204277076155f10851dad72b76a49317" - version = "v0.8.0" - -[[projects]] - branch = "master" - name = "github.com/prometheus/client_model" - packages = ["go"] - revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" - -[[projects]] - branch = "master" - name = "github.com/prometheus/common" - packages = [ - "expfmt", - "internal/bitbucket.org/ww/goautoneg", - "model" - ] - revision = "7600349dcfe1abd18d72d3a1770870d9800a7801" - -[[projects]] - branch = "master" - name = "github.com/prometheus/procfs" - packages = [ - ".", - "internal/util", - "nfs", - "xfs" - ] - revision = "40f013a808ec4fa79def444a1a56de4d1727efcb" - -[[projects]] - branch = "master" - name = "github.com/rcrowley/go-metrics" - packages = ["."] - revision = "e2704e165165ec55d062f5919b4b29494e9fa790" - -[[projects]] - name = "github.com/spf13/afero" - packages = [ - ".", - "mem" - ] - revision = "787d034dfe70e44075ccc060d346146ef53270ad" - version = "v1.1.1" - -[[projects]] - name = "github.com/spf13/cast" - packages = ["."] - revision = "8965335b8c7107321228e3e3702cab9832751bac" - version = "v1.2.0" - -[[projects]] - name = "github.com/spf13/cobra" - packages = ["."] - revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b" - version = "v0.0.1" - -[[projects]] - branch = "master" - name = "github.com/spf13/jwalterweatherman" - packages = ["."] - revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" - -[[projects]] - name = "github.com/spf13/pflag" - packages = ["."] - revision = "583c0c0531f06d5278b7d917446061adc344b5cd" - version = "v1.0.1" - -[[projects]] - name = "github.com/spf13/viper" - packages = ["."] - revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" - version = "v1.0.0" - -[[projects]] - name = "github.com/stretchr/testify" - packages = [ - "assert", - "require" - ] - revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" - version = "v1.2.1" - -[[projects]] - branch = "master" - name = "github.com/syndtr/goleveldb" - packages = [ - "leveldb", - "leveldb/cache", - "leveldb/comparer", - "leveldb/errors", - "leveldb/filter", - "leveldb/iterator", - "leveldb/journal", - "leveldb/memdb", - "leveldb/opt", - "leveldb/storage", - "leveldb/table", - "leveldb/util" - ] - revision = "0d5a0ceb10cf9ab89fdd744cc8c50a83134f6697" - -[[projects]] - branch = "master" - name = "github.com/tendermint/ed25519" - packages = [ - ".", - "edwards25519", - "extra25519" - ] - revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057" - -[[projects]] - name = "github.com/tendermint/go-amino" - packages = ["."] - revision = "2106ca61d91029c931fd54968c2bb02dc96b1412" - version = "0.10.1" - -[[projects]] - name = "github.com/tendermint/iavl" - packages = ["."] - revision = "9e5dc3e61f70b285bb25414452d47aca1ff34c1d" - version = "v0.8.2-rc0" - -[[projects]] - name = "github.com/tendermint/tendermint" - packages = [ - "abci/client", - "abci/example/code", - "abci/example/kvstore", - "abci/server", - "abci/types", - "blockchain", - "cmd/tendermint/commands", - "config", - "consensus", - "consensus/types", - "crypto", - "crypto/merkle", - "crypto/tmhash", - "evidence", - "libs/autofile", - "libs/bech32", - "libs/cli", - "libs/cli/flags", - "libs/clist", - "libs/common", - "libs/db", - "libs/events", - "libs/flowrate", - "libs/log", - "libs/pubsub", - "libs/pubsub/query", - "lite", - "lite/client", - "lite/errors", - "lite/files", - "lite/proxy", - "mempool", - "node", - "p2p", - "p2p/conn", - "p2p/pex", - "p2p/upnp", - "privval", - "proxy", - "rpc/client", - "rpc/core", - "rpc/core/types", - "rpc/grpc", - "rpc/lib", - "rpc/lib/client", - "rpc/lib/server", - "rpc/lib/types", - "state", - "state/txindex", - "state/txindex/kv", - "state/txindex/null", - "types", - "version" - ] - revision = "5923b6288fe8ce9581936ee97c2bf9cf9c02c2f4" - version = "v0.22.0-rc2" - -[[projects]] - name = "github.com/zondax/ledger-goclient" - packages = ["."] - revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a" - -[[projects]] - branch = "master" - name = "golang.org/x/crypto" - packages = [ - "blowfish", - "curve25519", - "internal/subtle", - "nacl/box", - "nacl/secretbox", - "openpgp/armor", - "openpgp/errors", - "pbkdf2", - "poly1305", - "ripemd160", - "salsa20/salsa" - ] - revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602" - -[[projects]] - branch = "master" - name = "golang.org/x/net" - packages = [ - "context", - "http/httpguts", - "http2", - "http2/hpack", - "idna", - "internal/timeseries", - "netutil", - "trace" - ] - revision = "ed29d75add3d7c4bf7ca65aac0c6df3d1420216f" - -[[projects]] - branch = "master" - name = "golang.org/x/sys" - packages = ["unix"] - revision = "7138fd3d9dc8335c567ca206f4333fb75eb05d56" - -[[projects]] - name = "golang.org/x/text" - packages = [ - "collate", - "collate/build", - "internal/colltab", - "internal/gen", - "internal/tag", - "internal/triegen", - "internal/ucd", - "language", - "secure/bidirule", - "transform", - "unicode/bidi", - "unicode/cldr", - "unicode/norm", - "unicode/rangetable" - ] - revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" - version = "v0.3.0" - -[[projects]] - name = "google.golang.org/genproto" - packages = ["googleapis/rpc/status"] - revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" - -[[projects]] - name = "google.golang.org/grpc" - packages = [ - ".", - "balancer", - "balancer/base", - "balancer/roundrobin", - "codes", - "connectivity", - "credentials", - "encoding", - "encoding/proto", - "grpclb/grpc_lb_v1/messages", - "grpclog", - "internal", - "keepalive", - "metadata", - "naming", - "peer", - "resolver", - "resolver/dns", - "resolver/passthrough", - "stats", - "status", - "tap", - "transport" - ] - revision = "d11072e7ca9811b1100b80ca0269ac831f06d024" - version = "v1.11.3" - -[[projects]] - name = "gopkg.in/yaml.v2" - packages = ["."] - revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" - version = "v2.2.1" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "13ad2a57b6942729e2d08b5c37810d62108aa64a335a4822fcff1ad992c0662b" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/server/util.go b/server/util.go index d1ad001c52..44b0d95ab2 100644 --- a/server/util.go +++ b/server/util.go @@ -135,6 +135,23 @@ func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMess return json.RawMessage(bz), err } +// SortedJSON takes any JSON and returns it sorted by keys. +// This can be used to sort JSON which will be returned by GetSignBytes, +// e.g. for the ledger integration. +// If the passed JSON isn't valid this will fail. +func SortJSON(toSortJSON []byte) ([]byte, error) { + var c interface{} + err := json.Unmarshal(toSortJSON, &c) + if err != nil { + return nil, err + } + js, err := json.MarshalIndent(c, "", " ") + if err != nil { + return nil, err + } + return js, nil +} + // https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go // TODO there must be a better way to get external IP func externalIP() (string, error) { diff --git a/server/util_test.go b/server/util_test.go index 8f1ab21dbc..a207558f39 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -38,3 +38,7 @@ func TestAppendJSON(t *testing.T) { require.Equal(t, bar, resBar, "appended: %v", appended) } + +func TestSortJSON(t *testing.T) { + // TODO add testcases of several types +} From c4c1c626c903f808984e2a7c6490ac35232f8b57 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 09:47:04 -0700 Subject: [PATCH 33/53] Add --owk flag to gaiad init --- cmd/gaia/cli_test/cli_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 17c7279591..f3452f17a7 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -36,7 +36,7 @@ func TestGaiaCLISend(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, "gaiad init -o --name=foo --home="+gaiadHome) + chainID := executeInit(t, "gaiad init -o --owk --name=foo --home="+gaiadHome) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags @@ -90,7 +90,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, "gaiad init -o --name=foo --home="+gaiadHome) + chainID := executeInit(t, "gaiad init -o --owk --name=foo --home="+gaiadHome) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags @@ -160,7 +160,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, "gaiad init -o --name=foo --home="+gaiadHome) + chainID := executeInit(t, "gaiad init -o --owk --name=foo --home="+gaiadHome) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags From 72aac78a39615bbe8317b836d510188ba13831be Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 09:51:20 -0700 Subject: [PATCH 34/53] Set home-client in gaiad init --- cmd/gaia/cli_test/cli_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index f3452f17a7..7f68d11c09 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -36,7 +36,7 @@ func TestGaiaCLISend(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, "gaiad init -o --owk --name=foo --home="+gaiadHome) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --owk --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags @@ -90,7 +90,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, "gaiad init -o --owk --name=foo --home="+gaiadHome) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --owk --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags @@ -160,7 +160,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, "gaiad init -o --owk --name=foo --home="+gaiadHome) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --owk --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags From 23414868a11b00c3e29ecf8d288ca142a117943b Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 10:14:12 -0700 Subject: [PATCH 35/53] Remove --owk flag --- cmd/gaia/cli_test/cli_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 7f68d11c09..0761bd08f7 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -36,7 +36,7 @@ func TestGaiaCLISend(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, fmt.Sprintf("gaiad init -o --owk --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags @@ -90,7 +90,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, fmt.Sprintf("gaiad init -o --owk --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags @@ -160,7 +160,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) - chainID := executeInit(t, fmt.Sprintf("gaiad init -o --owk --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) // get a free port, also setup some common flags From 97182dce21229d12c7191926829066856b6b655e Mon Sep 17 00:00:00 2001 From: Liamsi Date: Thu, 5 Jul 2018 19:09:08 +0100 Subject: [PATCH 36/53] Add test-cases, remove indentation --- server/util.go | 9 +++++---- server/util_test.go | 29 ++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/server/util.go b/server/util.go index 44b0d95ab2..c77222bfe6 100644 --- a/server/util.go +++ b/server/util.go @@ -135,17 +135,18 @@ func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMess return json.RawMessage(bz), err } -// SortedJSON takes any JSON and returns it sorted by keys. -// This can be used to sort JSON which will be returned by GetSignBytes, +// SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces +// are removed. +// This method can be used to canonicalize JSON to be returned by GetSignBytes, // e.g. for the ledger integration. -// If the passed JSON isn't valid this will fail. +// If the passed JSON isn't valid it will return an error. func SortJSON(toSortJSON []byte) ([]byte, error) { var c interface{} err := json.Unmarshal(toSortJSON, &c) if err != nil { return nil, err } - js, err := json.MarshalIndent(c, "", " ") + js, err := json.Marshal(c) if err != nil { return nil, err } diff --git a/server/util_test.go b/server/util_test.go index a207558f39..301215e1a4 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -40,5 +40,32 @@ func TestAppendJSON(t *testing.T) { } func TestSortJSON(t *testing.T) { - // TODO add testcases of several types + cases := []struct { + unsortedJson string + want string + wantErr bool + }{ + // simple case + {unsortedJson: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`, + want: `{"atom":"bar","cosmos":"foo","tendermint":"foobar"}`, wantErr: false}, + // failing case (invalid JSON): + {unsortedJson: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`, + want: "", wantErr: true}, + // genesis.json + {unsortedJson: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, + want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, + wantErr: false}, + // from the TXSpec: + {unsortedJson: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, + want: `{"alt_bytes":null,"chain_id":"test-chain-1","fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"sequence":1}`, + wantErr: false}, + } + + for _, tc := range cases { + got, err := SortJSON([]byte(tc.unsortedJson)) + if tc.wantErr != (err != nil) { + t.Fatalf("got %t, want: %t, err=%s", err != nil, tc.wantErr, err) + } + require.Equal(t, string(got), tc.want) + } } From 51fdc9db2f9cd4c2b7edcf5f45a7910f321abce7 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 5 Jul 2018 14:07:03 -0400 Subject: [PATCH 37/53] Merge pull request #1559: Inconsistent Genesis Generation Key Order --- examples/democoin/cmd/democoind/main.go | 8 ++++++-- server/init.go | 26 +++++++------------------ server/util.go | 14 +++++++++---- server/util_test.go | 4 ++-- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 0bb84c146a..e74b3b700b 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -29,20 +29,24 @@ func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso if err != nil { return } + key := "cool" value := json.RawMessage(`{ "trend": "ice-cold" }`) - appState, err = server.AppendJSON(cdc, appState, key, value) + + appState, err = server.InsertKeyJSON(cdc, appState, key, value) if err != nil { return } + key = "pow" value = json.RawMessage(`{ "difficulty": 1, "count": 0 }`) - appState, err = server.AppendJSON(cdc, appState, key, value) + + appState, err = server.InsertKeyJSON(cdc, appState, key, value) return } diff --git a/server/init.go b/server/init.go index 0cc99e79fa..3c9186fba3 100644 --- a/server/init.go +++ b/server/init.go @@ -332,32 +332,20 @@ func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { return privValidator.GetPubKey() } -// create the genesis file +// writeGenesisFile creates and writes the genesis configuration to disk. An +// error is returned if building or writing the configuration to file fails. func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { genDoc := tmtypes.GenesisDoc{ - ChainID: chainID, - Validators: validators, + ChainID: chainID, + Validators: validators, + AppStateJSON: appState, } + if err := genDoc.ValidateAndComplete(); err != nil { return err } - if err := genDoc.SaveAs(genesisFile); err != nil { - return err - } - return addAppStateToGenesis(cdc, genesisFile, appState) -} -// Add one line to the genesis file -func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState json.RawMessage) error { - bz, err := ioutil.ReadFile(genesisConfigPath) - if err != nil { - return err - } - out, err := AppendJSON(cdc, bz, "app_state", appState) - if err != nil { - return err - } - return ioutil.WriteFile(genesisConfigPath, out, 0600) + return genDoc.SaveAs(genesisFile) } //_____________________________________________________________________ diff --git a/server/util.go b/server/util.go index d1ad001c52..0f1816b166 100644 --- a/server/util.go +++ b/server/util.go @@ -123,15 +123,21 @@ func AddCommands( //___________________________________________________________________________________ -// append a new json field to existing json message -func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) { +// InsertKeyJSON inserts a new JSON field/key with a given value to an existing +// JSON message. An error is returned if any serialization operation fails. +// +// NOTE: The ordering of the keys returned as the resulting JSON message is +// non-deterministic, so the client should not rely on key ordering. +func InsertKeyJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) ([]byte, error) { var jsonMap map[string]json.RawMessage - err = cdc.UnmarshalJSON(baseJSON, &jsonMap) - if err != nil { + + if err := cdc.UnmarshalJSON(baseJSON, &jsonMap); err != nil { return nil, err } + jsonMap[key] = value bz, err := wire.MarshalJSONIndent(cdc, jsonMap) + return json.RawMessage(bz), err } diff --git a/server/util_test.go b/server/util_test.go index 8f1ab21dbc..6082caa2ce 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestAppendJSON(t *testing.T) { +func TestInsertKeyJSON(t *testing.T) { cdc := wire.NewCodec() foo := map[string]string{"foo": "foofoo"} @@ -24,7 +24,7 @@ func TestAppendJSON(t *testing.T) { barRaw := json.RawMessage(bz) // make the append - appBz, err := AppendJSON(cdc, fooRaw, "barOuter", barRaw) + appBz, err := InsertKeyJSON(cdc, fooRaw, "barOuter", barRaw) require.NoError(t, err) // test the append From 28245dba900b4e67a1e48381341b455d69cbaca1 Mon Sep 17 00:00:00 2001 From: Liamsi Date: Thu, 5 Jul 2018 19:18:48 +0100 Subject: [PATCH 38/53] adhere to golint --- server/util_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/util_test.go b/server/util_test.go index 301215e1a4..dc4ba75f24 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -41,28 +41,28 @@ func TestAppendJSON(t *testing.T) { func TestSortJSON(t *testing.T) { cases := []struct { - unsortedJson string + unsortedJSON string want string wantErr bool }{ // simple case - {unsortedJson: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`, + {unsortedJSON: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`, want: `{"atom":"bar","cosmos":"foo","tendermint":"foobar"}`, wantErr: false}, // failing case (invalid JSON): - {unsortedJson: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`, + {unsortedJSON: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`, want: "", wantErr: true}, // genesis.json - {unsortedJson: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, + {unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, wantErr: false}, // from the TXSpec: - {unsortedJson: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, + {unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, want: `{"alt_bytes":null,"chain_id":"test-chain-1","fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"sequence":1}`, wantErr: false}, } for _, tc := range cases { - got, err := SortJSON([]byte(tc.unsortedJson)) + got, err := SortJSON([]byte(tc.unsortedJSON)) if tc.wantErr != (err != nil) { t.Fatalf("got %t, want: %t, err=%s", err != nil, tc.wantErr, err) } From 0f1ceb073e4cd2a1a39b377ca01def9f8a43b0e5 Mon Sep 17 00:00:00 2001 From: Liamsi Date: Fri, 6 Jul 2018 00:23:12 +0100 Subject: [PATCH 39/53] sort all relevant GetSignBytes: - call SortJSON before return JSON bytes to guarantee alphabetic ordering --- x/auth/stdtx.go | 5 +++++ x/bank/msgs.go | 17 +++++++++++++++++ x/bank/msgs_test.go | 4 ++-- x/gov/msgs.go | 13 +++++++++++++ x/stake/types/msg.go | 29 +++++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index fd55eebb95..566940db7c 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -3,6 +3,7 @@ package auth import ( "encoding/json" + "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" ) @@ -141,6 +142,10 @@ func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs if err != nil { panic(err) } + bz, err = server.SortJSON(bz) + if err != nil { + panic(err) + } return bz } diff --git a/x/bank/msgs.go b/x/bank/msgs.go index 1a871979e2..069ace9cea 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -3,6 +3,7 @@ package bank import ( "encoding/json" + "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -72,6 +73,10 @@ func (msg MsgSend) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -133,6 +138,10 @@ func (msg MsgIssue) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -162,6 +171,10 @@ func (in Input) GetSignBytes() []byte { if err != nil { panic(err) } + bin, err = server.SortJSON(bin) + if err != nil { + panic(err) + } return bin } @@ -209,6 +222,10 @@ func (out Output) GetSignBytes() []byte { if err != nil { panic(err) } + bin, err = server.SortJSON(bin) + if err != nil { + panic(err) + } return bin } diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index 3754858ec7..f4e7363d3b 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -187,7 +187,7 @@ func TestMsgSendGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"denom":"atom","amount":"10"}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"denom":"atom","amount":"10"}]}]}` + expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"amount":"10","denom":"atom"}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"amount":"10","denom":"atom"}]}]}` require.Equal(t, expected, string(res)) } @@ -257,7 +257,7 @@ func TestMsgIssueGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"denom":"atom","amount":"10"}]}]}` + expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"amount":"10","denom":"atom"}]}]}` require.Equal(t, expected, string(res)) } diff --git a/x/gov/msgs.go b/x/gov/msgs.go index f436d024b1..afe7084c48 100644 --- a/x/gov/msgs.go +++ b/x/gov/msgs.go @@ -3,6 +3,7 @@ package gov import ( "fmt" + "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -82,6 +83,10 @@ func (msg MsgSubmitProposal) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -149,6 +154,10 @@ func (msg MsgDeposit) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -213,6 +222,10 @@ func (msg MsgVote) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index 878c1ba17b..609935fb0f 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -3,6 +3,7 @@ package types import ( "math" + "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" ) @@ -63,6 +64,10 @@ func (msg MsgCreateValidator) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -114,6 +119,10 @@ func (msg MsgEditValidator) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -166,6 +175,10 @@ func (msg MsgDelegate) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -226,6 +239,10 @@ func (msg MsgBeginRedelegate) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -286,6 +303,10 @@ func (msg MsgCompleteRedelegate) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -338,6 +359,10 @@ func (msg MsgBeginUnbonding) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } @@ -387,6 +412,10 @@ func (msg MsgCompleteUnbonding) GetSignBytes() []byte { if err != nil { panic(err) } + b, err = server.SortJSON(b) + if err != nil { + panic(err) + } return b } From 66fdb9585b7903ba1c9003d495b54da5858809bf Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 6 Jul 2018 02:09:33 +0200 Subject: [PATCH 40/53] Gopkg.lock & 'make format' --- Gopkg.lock | 512 ++++++++++++++++++++++++++++++++++++++++++++ server/util_test.go | 2 +- 2 files changed, 513 insertions(+), 1 deletion(-) create mode 100644 Gopkg.lock diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000000..8794539880 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,512 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "github.com/bartekn/go-bip39" + packages = ["."] + revision = "a05967ea095d81c8fe4833776774cfaff8e5036c" + +[[projects]] + branch = "master" + name = "github.com/beorn7/perks" + packages = ["quantile"] + revision = "3a771d992973f24aa725d07868b467d1ddfceafb" + +[[projects]] + name = "github.com/bgentry/speakeasy" + packages = ["."] + revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd" + version = "v0.1.0" + +[[projects]] + branch = "master" + name = "github.com/brejski/hid" + packages = ["."] + revision = "06112dcfcc50a7e0e4fd06e17f9791e788fdaafc" + +[[projects]] + branch = "master" + name = "github.com/btcsuite/btcd" + packages = ["btcec"] + revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64" + +[[projects]] + branch = "master" + name = "github.com/btcsuite/btcutil" + packages = ["bech32"] + revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4" + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + branch = "master" + name = "github.com/ebuchman/fail-test" + packages = ["."] + revision = "95f809107225be108efcf10a3509e4ea6ceef3c4" + +[[projects]] + name = "github.com/fsnotify/fsnotify" + packages = ["."] + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + name = "github.com/go-kit/kit" + packages = [ + "log", + "log/level", + "log/term", + "metrics", + "metrics/discard", + "metrics/internal/lv", + "metrics/prometheus" + ] + revision = "4dc7be5d2d12881735283bcab7352178e190fc71" + version = "v0.6.0" + +[[projects]] + name = "github.com/go-logfmt/logfmt" + packages = ["."] + revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" + version = "v0.3.0" + +[[projects]] + name = "github.com/go-stack/stack" + packages = ["."] + revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" + version = "v1.7.0" + +[[projects]] + name = "github.com/gogo/protobuf" + packages = [ + "gogoproto", + "jsonpb", + "proto", + "protoc-gen-gogo/descriptor", + "sortkeys", + "types" + ] + revision = "1adfc126b41513cc696b209667c8656ea7aac67c" + version = "v1.0.0" + +[[projects]] + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp" + ] + revision = "925541529c1fa6821df4e44ce2723319eb2be768" + version = "v1.0.0" + +[[projects]] + branch = "master" + name = "github.com/golang/snappy" + packages = ["."] + revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" + +[[projects]] + name = "github.com/gorilla/context" + packages = ["."] + revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" + version = "v1.1.1" + +[[projects]] + name = "github.com/gorilla/mux" + packages = ["."] + revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf" + version = "v1.6.2" + +[[projects]] + name = "github.com/gorilla/websocket" + packages = ["."] + revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b" + version = "v1.2.0" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/printer", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token" + ] + revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" + +[[projects]] + name = "github.com/inconshreveable/mousetrap" + packages = ["."] + revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + version = "v1.0" + +[[projects]] + branch = "master" + name = "github.com/jmhodges/levigo" + packages = ["."] + revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" + +[[projects]] + branch = "master" + name = "github.com/kr/logfmt" + packages = ["."] + revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0" + +[[projects]] + name = "github.com/magiconair/properties" + packages = ["."] + revision = "c2353362d570a7bfa228149c62842019201cfb71" + version = "v1.8.0" + +[[projects]] + name = "github.com/mattn/go-isatty" + packages = ["."] + revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" + version = "v0.0.3" + +[[projects]] + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" + version = "v1.0.1" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b" + +[[projects]] + name = "github.com/pelletier/go-toml" + packages = ["."] + revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" + version = "v1.2.0" + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + name = "github.com/prometheus/client_golang" + packages = [ + "prometheus", + "prometheus/promhttp" + ] + revision = "c5b7fccd204277076155f10851dad72b76a49317" + version = "v0.8.0" + +[[projects]] + branch = "master" + name = "github.com/prometheus/client_model" + packages = ["go"] + revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" + +[[projects]] + branch = "master" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model" + ] + revision = "7600349dcfe1abd18d72d3a1770870d9800a7801" + +[[projects]] + branch = "master" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfs", + "xfs" + ] + revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a" + +[[projects]] + branch = "master" + name = "github.com/rcrowley/go-metrics" + packages = ["."] + revision = "e2704e165165ec55d062f5919b4b29494e9fa790" + +[[projects]] + name = "github.com/spf13/afero" + packages = [ + ".", + "mem" + ] + revision = "787d034dfe70e44075ccc060d346146ef53270ad" + version = "v1.1.1" + +[[projects]] + name = "github.com/spf13/cast" + packages = ["."] + revision = "8965335b8c7107321228e3e3702cab9832751bac" + version = "v1.2.0" + +[[projects]] + name = "github.com/spf13/cobra" + packages = ["."] + revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b" + version = "v0.0.1" + +[[projects]] + branch = "master" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" + +[[projects]] + name = "github.com/spf13/pflag" + packages = ["."] + revision = "583c0c0531f06d5278b7d917446061adc344b5cd" + version = "v1.0.1" + +[[projects]] + name = "github.com/spf13/viper" + packages = ["."] + revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" + version = "v1.0.0" + +[[projects]] + name = "github.com/stretchr/testify" + packages = [ + "assert", + "require" + ] + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" + +[[projects]] + branch = "master" + name = "github.com/syndtr/goleveldb" + packages = [ + "leveldb", + "leveldb/cache", + "leveldb/comparer", + "leveldb/errors", + "leveldb/filter", + "leveldb/iterator", + "leveldb/journal", + "leveldb/memdb", + "leveldb/opt", + "leveldb/storage", + "leveldb/table", + "leveldb/util" + ] + revision = "0d5a0ceb10cf9ab89fdd744cc8c50a83134f6697" + +[[projects]] + branch = "master" + name = "github.com/tendermint/ed25519" + packages = [ + ".", + "edwards25519", + "extra25519" + ] + revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057" + +[[projects]] + name = "github.com/tendermint/go-amino" + packages = ["."] + revision = "2106ca61d91029c931fd54968c2bb02dc96b1412" + version = "0.10.1" + +[[projects]] + name = "github.com/tendermint/iavl" + packages = ["."] + revision = "9e5dc3e61f70b285bb25414452d47aca1ff34c1d" + version = "v0.8.2-rc0" + +[[projects]] + name = "github.com/tendermint/tendermint" + packages = [ + "abci/client", + "abci/example/code", + "abci/example/kvstore", + "abci/server", + "abci/types", + "blockchain", + "cmd/tendermint/commands", + "config", + "consensus", + "consensus/types", + "crypto", + "crypto/merkle", + "crypto/tmhash", + "evidence", + "libs/autofile", + "libs/bech32", + "libs/cli", + "libs/cli/flags", + "libs/clist", + "libs/common", + "libs/db", + "libs/events", + "libs/flowrate", + "libs/log", + "libs/pubsub", + "libs/pubsub/query", + "lite", + "lite/client", + "lite/errors", + "lite/files", + "lite/proxy", + "mempool", + "node", + "p2p", + "p2p/conn", + "p2p/pex", + "p2p/upnp", + "privval", + "proxy", + "rpc/client", + "rpc/core", + "rpc/core/types", + "rpc/grpc", + "rpc/lib", + "rpc/lib/client", + "rpc/lib/server", + "rpc/lib/types", + "state", + "state/txindex", + "state/txindex/kv", + "state/txindex/null", + "types", + "version" + ] + revision = "5923b6288fe8ce9581936ee97c2bf9cf9c02c2f4" + version = "v0.22.0-rc2" + +[[projects]] + name = "github.com/zondax/ledger-goclient" + packages = ["."] + revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = [ + "blowfish", + "curve25519", + "internal/subtle", + "nacl/box", + "nacl/secretbox", + "openpgp/armor", + "openpgp/errors", + "pbkdf2", + "poly1305", + "ripemd160", + "salsa20/salsa" + ] + revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "context", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "netutil", + "trace" + ] + revision = "ed29d75add3d7c4bf7ca65aac0c6df3d1420216f" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = ["unix"] + revision = "151529c776cdc58ddbe7963ba9af779f3577b419" + +[[projects]] + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable" + ] + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + name = "google.golang.org/genproto" + packages = ["googleapis/rpc/status"] + revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" + +[[projects]] + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "codes", + "connectivity", + "credentials", + "encoding", + "encoding/proto", + "grpclb/grpc_lb_v1/messages", + "grpclog", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + "transport" + ] + revision = "d11072e7ca9811b1100b80ca0269ac831f06d024" + version = "v1.11.3" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "13ad2a57b6942729e2d08b5c37810d62108aa64a335a4822fcff1ad992c0662b" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/server/util_test.go b/server/util_test.go index 69910d26ac..09e66ab4a6 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -53,7 +53,7 @@ func TestSortJSON(t *testing.T) { want: "", wantErr: true}, // genesis.json {unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, - want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, + want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, wantErr: false}, // from the TXSpec: {unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, From b7f902fba5fcb367d82a2dd9e59600e91d2dfc72 Mon Sep 17 00:00:00 2001 From: Liamsi Date: Fri, 6 Jul 2018 01:09:23 +0100 Subject: [PATCH 41/53] sort *all* GetSignBytes: - call MustSortJSON before return JSON bytes to guarantee alphabetic ordering - moved SortJSON and MustSortJSON to types package to avoid cyclic package dep --- baseapp/baseapp_test.go | 4 +-- docs/core/examples/app1.go | 2 +- docs/core/examples/app2.go | 2 +- examples/democoin/x/cool/types.go | 4 +-- examples/democoin/x/oracle/types.go | 2 +- examples/democoin/x/pow/types.go | 2 +- examples/democoin/x/pow/types_test.go | 2 +- examples/democoin/x/simplestake/msgs.go | 2 +- examples/kvstore/tx.go | 2 +- server/util.go | 18 ----------- server/util_test.go | 31 ------------------ types/tx_msg.go | 2 +- types/utils.go | 31 ++++++++++++++++++ types/utils_test.go | 39 ++++++++++++++++++++++ x/auth/stdtx.go | 7 +--- x/bank/msgs.go | 25 +++----------- x/gov/msgs.go | 19 ++--------- x/ibc/types.go | 4 +-- x/slashing/msg.go | 2 +- x/stake/types/msg.go | 43 ++++--------------------- 20 files changed, 100 insertions(+), 143 deletions(-) create mode 100644 types/utils.go create mode 100644 types/utils_test.go diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index e919375d90..b8c42c4d2e 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -662,7 +662,7 @@ const msgType3 = "burn" func (msg testBurnMsg) Type() string { return msgType3 } func (msg testBurnMsg) GetSignBytes() []byte { bz, _ := json.Marshal(msg) - return bz + return sdk.MustSortJSON(bz) } func (msg testBurnMsg) ValidateBasic() sdk.Error { if msg.Addr == nil { @@ -685,7 +685,7 @@ const msgType4 = "send" func (msg testSendMsg) Type() string { return msgType4 } func (msg testSendMsg) GetSignBytes() []byte { bz, _ := json.Marshal(msg) - return bz + return sdk.MustSortJSON(bz) } func (msg testSendMsg) ValidateBasic() sdk.Error { if msg.Sender == nil || msg.Receiver == nil { diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index f9eceecdb5..a9580fcc29 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -85,7 +85,7 @@ func (msg MsgSend) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } // Implements Msg. Return the signer. diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index b4d44dca7b..c96a1022fa 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -100,7 +100,7 @@ func (msg MsgIssue) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } // Implements Msg. Return the signer. diff --git a/examples/democoin/x/cool/types.go b/examples/democoin/x/cool/types.go index 77f49a0ba3..82c9286c68 100644 --- a/examples/democoin/x/cool/types.go +++ b/examples/democoin/x/cool/types.go @@ -58,7 +58,7 @@ func (msg MsgSetTrend) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } //_______________________________________________________________________ @@ -102,5 +102,5 @@ func (msg MsgQuiz) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } diff --git a/examples/democoin/x/oracle/types.go b/examples/democoin/x/oracle/types.go index 041b9ab349..d06f47a4e2 100644 --- a/examples/democoin/x/oracle/types.go +++ b/examples/democoin/x/oracle/types.go @@ -18,7 +18,7 @@ func (msg Msg) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } // GetSigners implements sdk.Msg diff --git a/examples/democoin/x/pow/types.go b/examples/democoin/x/pow/types.go index cd77a68af5..3529917dce 100644 --- a/examples/democoin/x/pow/types.go +++ b/examples/democoin/x/pow/types.go @@ -76,5 +76,5 @@ func (msg MsgMine) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } diff --git a/examples/democoin/x/pow/types_test.go b/examples/democoin/x/pow/types_test.go index 9ed5dc102c..1291cb96a6 100644 --- a/examples/democoin/x/pow/types_test.go +++ b/examples/democoin/x/pow/types_test.go @@ -62,7 +62,7 @@ func TestMsgMineGetSignBytes(t *testing.T) { addr := sdk.Address([]byte("sender")) msg := MsgMine{addr, 1, 1, 1, []byte("abc")} res := msg.GetSignBytes() - require.Equal(t, string(res), `{"sender":"73656E646572","difficulty":1,"count":1,"nonce":1,"proof":"YWJj"}`) + require.Equal(t, string(res), `{"count":1,"difficulty":1,"nonce":1,"proof":"YWJj","sender":"73656E646572"}`) } func TestMsgMineGetSigners(t *testing.T) { diff --git a/examples/democoin/x/simplestake/msgs.go b/examples/democoin/x/simplestake/msgs.go index 564e0d9796..91729e3ef7 100644 --- a/examples/democoin/x/simplestake/msgs.go +++ b/examples/democoin/x/simplestake/msgs.go @@ -48,7 +48,7 @@ func (msg MsgBond) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } //_______________________________________________________________ diff --git a/examples/kvstore/tx.go b/examples/kvstore/tx.go index 0e94ace285..e1c5cab3a8 100644 --- a/examples/kvstore/tx.go +++ b/examples/kvstore/tx.go @@ -27,7 +27,7 @@ func (tx kvstoreTx) GetMemo() string { } func (tx kvstoreTx) GetSignBytes() []byte { - return tx.bytes + return sdk.MustSortJSON(tx.bytes) } // Should the app be calling this? Or only handlers? diff --git a/server/util.go b/server/util.go index c77222bfe6..d1ad001c52 100644 --- a/server/util.go +++ b/server/util.go @@ -135,24 +135,6 @@ func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMess return json.RawMessage(bz), err } -// SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces -// are removed. -// This method can be used to canonicalize JSON to be returned by GetSignBytes, -// e.g. for the ledger integration. -// If the passed JSON isn't valid it will return an error. -func SortJSON(toSortJSON []byte) ([]byte, error) { - var c interface{} - err := json.Unmarshal(toSortJSON, &c) - if err != nil { - return nil, err - } - js, err := json.Marshal(c) - if err != nil { - return nil, err - } - return js, nil -} - // https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go // TODO there must be a better way to get external IP func externalIP() (string, error) { diff --git a/server/util_test.go b/server/util_test.go index dc4ba75f24..8f1ab21dbc 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -38,34 +38,3 @@ func TestAppendJSON(t *testing.T) { require.Equal(t, bar, resBar, "appended: %v", appended) } - -func TestSortJSON(t *testing.T) { - cases := []struct { - unsortedJSON string - want string - wantErr bool - }{ - // simple case - {unsortedJSON: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`, - want: `{"atom":"bar","cosmos":"foo","tendermint":"foobar"}`, wantErr: false}, - // failing case (invalid JSON): - {unsortedJSON: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`, - want: "", wantErr: true}, - // genesis.json - {unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, - want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, - wantErr: false}, - // from the TXSpec: - {unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, - want: `{"alt_bytes":null,"chain_id":"test-chain-1","fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"sequence":1}`, - wantErr: false}, - } - - for _, tc := range cases { - got, err := SortJSON([]byte(tc.unsortedJSON)) - if tc.wantErr != (err != nil) { - t.Fatalf("got %t, want: %t, err=%s", err != nil, tc.wantErr, err) - } - require.Equal(t, string(got), tc.want) - } -} diff --git a/types/tx_msg.go b/types/tx_msg.go index c1af91df82..fbadfb49d0 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -60,7 +60,7 @@ func (msg *TestMsg) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return MustSortJSON(bz) } func (msg *TestMsg) ValidateBasic() Error { return nil } func (msg *TestMsg) GetSigners() []Address { diff --git a/types/utils.go b/types/utils.go new file mode 100644 index 0000000000..2e027676a0 --- /dev/null +++ b/types/utils.go @@ -0,0 +1,31 @@ +package types + +import "encoding/json" + +// SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces +// are removed. +// This method can be used to canonicalize JSON to be returned by GetSignBytes, +// e.g. for the ledger integration. +// If the passed JSON isn't valid it will return an error. +func SortJSON(toSortJSON []byte) ([]byte, error) { + var c interface{} + err := json.Unmarshal(toSortJSON, &c) + if err != nil { + return nil, err + } + js, err := json.Marshal(c) + if err != nil { + return nil, err + } + return js, nil +} + +// MustSortJSON is like SortJSON but panic if an error occurs, e.g., if +// the passed JSON isn't valid. +func MustSortJSON(toSortJSON []byte) []byte { + js, err := SortJSON(toSortJSON) + if err != nil { + panic(err) + } + return js +} diff --git a/types/utils_test.go b/types/utils_test.go new file mode 100644 index 0000000000..8c84e2ace2 --- /dev/null +++ b/types/utils_test.go @@ -0,0 +1,39 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSortJSON(t *testing.T) { + cases := []struct { + unsortedJSON string + want string + wantErr bool + }{ + // simple case + {unsortedJSON: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`, + want: `{"atom":"bar","cosmos":"foo","tendermint":"foobar"}`, wantErr: false}, + // failing case (invalid JSON): + {unsortedJSON: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`, + want: "", + wantErr: true}, + // genesis.json + {unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, + want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, + wantErr: false}, + // from the TXSpec: + {unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, + want: `{"alt_bytes":null,"chain_id":"test-chain-1","fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"sequence":1}`, + wantErr: false}, + } + + for _, tc := range cases { + got, err := SortJSON([]byte(tc.unsortedJSON)) + if tc.wantErr != (err != nil) { + t.Fatalf("got %t, want: %t, err=%s", err != nil, tc.wantErr, err) + } + require.Equal(t, string(got), tc.want) + } +} diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index 566940db7c..960d9855ea 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -3,7 +3,6 @@ package auth import ( "encoding/json" - "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" ) @@ -142,11 +141,7 @@ func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs if err != nil { panic(err) } - bz, err = server.SortJSON(bz) - if err != nil { - panic(err) - } - return bz + return sdk.MustSortJSON(bz) } // StdSignMsg is a convenience structure for passing along diff --git a/x/bank/msgs.go b/x/bank/msgs.go index 069ace9cea..46b1995633 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -3,7 +3,6 @@ package bank import ( "encoding/json" - "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -73,11 +72,7 @@ func (msg MsgSend) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // Implements Msg. @@ -138,11 +133,7 @@ func (msg MsgIssue) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // Implements Msg. @@ -171,11 +162,7 @@ func (in Input) GetSignBytes() []byte { if err != nil { panic(err) } - bin, err = server.SortJSON(bin) - if err != nil { - panic(err) - } - return bin + return sdk.MustSortJSON(bin) } // ValidateBasic - validate transaction input @@ -222,11 +209,7 @@ func (out Output) GetSignBytes() []byte { if err != nil { panic(err) } - bin, err = server.SortJSON(bin) - if err != nil { - panic(err) - } - return bin + return sdk.MustSortJSON(bin) } // ValidateBasic - validate transaction output diff --git a/x/gov/msgs.go b/x/gov/msgs.go index afe7084c48..75a8d51e39 100644 --- a/x/gov/msgs.go +++ b/x/gov/msgs.go @@ -3,7 +3,6 @@ package gov import ( "fmt" - "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -83,11 +82,7 @@ func (msg MsgSubmitProposal) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // Implements Msg. @@ -154,11 +149,7 @@ func (msg MsgDeposit) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // Implements Msg. @@ -222,11 +213,7 @@ func (msg MsgVote) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // Implements Msg. diff --git a/x/ibc/types.go b/x/ibc/types.go index a311b98698..33f2a9a8d3 100644 --- a/x/ibc/types.go +++ b/x/ibc/types.go @@ -59,7 +59,7 @@ func (p IBCPacket) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // validator the ibc packey @@ -131,5 +131,5 @@ func (msg IBCReceiveMsg) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } diff --git a/x/slashing/msg.go b/x/slashing/msg.go index 561c922665..6060079a49 100644 --- a/x/slashing/msg.go +++ b/x/slashing/msg.go @@ -38,7 +38,7 @@ func (msg MsgUnrevoke) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index 609935fb0f..aa9eea8cbb 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -3,7 +3,6 @@ package types import ( "math" - "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" ) @@ -64,11 +63,7 @@ func (msg MsgCreateValidator) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -119,11 +114,7 @@ func (msg MsgEditValidator) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -175,11 +166,7 @@ func (msg MsgDelegate) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -239,11 +226,7 @@ func (msg MsgBeginRedelegate) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -303,11 +286,7 @@ func (msg MsgCompleteRedelegate) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -359,11 +338,7 @@ func (msg MsgBeginUnbonding) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -412,11 +387,7 @@ func (msg MsgCompleteUnbonding) GetSignBytes() []byte { if err != nil { panic(err) } - b, err = server.SortJSON(b) - if err != nil { - panic(err) - } - return b + return sdk.MustSortJSON(b) } // quick validity check From bf8cde1d3a7c5e948c5b04dd83f96c7df17486bb Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 17:07:03 -0700 Subject: [PATCH 42/53] cli: deprecate --name in favor of --from --- CHANGELOG.md | 3 + Gopkg.lock | 512 +++++++++++++++++++++++++++++++++ client/context/viper.go | 9 +- client/flags.go | 4 +- cmd/gaia/cli_test/cli_test.go | 18 +- cmd/gaia/testnets/README.md | 12 +- docs/_attic/staking/intro.rst | 12 +- docs/_attic/staking/testnet.md | 4 +- docs/clients/ledger.md | 2 +- examples/README.md | 10 +- tests/check_basecli.sh | 2 +- x/bank/client/cli/sendtx.go | 2 +- x/ibc/client/cli/README.md | 4 +- 13 files changed, 559 insertions(+), 35 deletions(-) create mode 100644 Gopkg.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index bb9672c5e5..c62577320f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,9 @@ BREAKING CHANGES * [lcd] Switch key creation output to return bech32 * [x/stake] store-value for delegation, validator, ubd, and red do not hold duplicate information contained store-key +DEPRECATED +* [cli] Deprecate `--name` flag in commands that send txs, in favor of `--from` + FEATURES * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag * [lcd] Queried TXs now include the tx hash to identify each tx diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000000..8794539880 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,512 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "github.com/bartekn/go-bip39" + packages = ["."] + revision = "a05967ea095d81c8fe4833776774cfaff8e5036c" + +[[projects]] + branch = "master" + name = "github.com/beorn7/perks" + packages = ["quantile"] + revision = "3a771d992973f24aa725d07868b467d1ddfceafb" + +[[projects]] + name = "github.com/bgentry/speakeasy" + packages = ["."] + revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd" + version = "v0.1.0" + +[[projects]] + branch = "master" + name = "github.com/brejski/hid" + packages = ["."] + revision = "06112dcfcc50a7e0e4fd06e17f9791e788fdaafc" + +[[projects]] + branch = "master" + name = "github.com/btcsuite/btcd" + packages = ["btcec"] + revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64" + +[[projects]] + branch = "master" + name = "github.com/btcsuite/btcutil" + packages = ["bech32"] + revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4" + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + branch = "master" + name = "github.com/ebuchman/fail-test" + packages = ["."] + revision = "95f809107225be108efcf10a3509e4ea6ceef3c4" + +[[projects]] + name = "github.com/fsnotify/fsnotify" + packages = ["."] + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + name = "github.com/go-kit/kit" + packages = [ + "log", + "log/level", + "log/term", + "metrics", + "metrics/discard", + "metrics/internal/lv", + "metrics/prometheus" + ] + revision = "4dc7be5d2d12881735283bcab7352178e190fc71" + version = "v0.6.0" + +[[projects]] + name = "github.com/go-logfmt/logfmt" + packages = ["."] + revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" + version = "v0.3.0" + +[[projects]] + name = "github.com/go-stack/stack" + packages = ["."] + revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" + version = "v1.7.0" + +[[projects]] + name = "github.com/gogo/protobuf" + packages = [ + "gogoproto", + "jsonpb", + "proto", + "protoc-gen-gogo/descriptor", + "sortkeys", + "types" + ] + revision = "1adfc126b41513cc696b209667c8656ea7aac67c" + version = "v1.0.0" + +[[projects]] + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp" + ] + revision = "925541529c1fa6821df4e44ce2723319eb2be768" + version = "v1.0.0" + +[[projects]] + branch = "master" + name = "github.com/golang/snappy" + packages = ["."] + revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" + +[[projects]] + name = "github.com/gorilla/context" + packages = ["."] + revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" + version = "v1.1.1" + +[[projects]] + name = "github.com/gorilla/mux" + packages = ["."] + revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf" + version = "v1.6.2" + +[[projects]] + name = "github.com/gorilla/websocket" + packages = ["."] + revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b" + version = "v1.2.0" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/printer", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token" + ] + revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" + +[[projects]] + name = "github.com/inconshreveable/mousetrap" + packages = ["."] + revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + version = "v1.0" + +[[projects]] + branch = "master" + name = "github.com/jmhodges/levigo" + packages = ["."] + revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" + +[[projects]] + branch = "master" + name = "github.com/kr/logfmt" + packages = ["."] + revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0" + +[[projects]] + name = "github.com/magiconair/properties" + packages = ["."] + revision = "c2353362d570a7bfa228149c62842019201cfb71" + version = "v1.8.0" + +[[projects]] + name = "github.com/mattn/go-isatty" + packages = ["."] + revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" + version = "v0.0.3" + +[[projects]] + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" + version = "v1.0.1" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b" + +[[projects]] + name = "github.com/pelletier/go-toml" + packages = ["."] + revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" + version = "v1.2.0" + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + name = "github.com/prometheus/client_golang" + packages = [ + "prometheus", + "prometheus/promhttp" + ] + revision = "c5b7fccd204277076155f10851dad72b76a49317" + version = "v0.8.0" + +[[projects]] + branch = "master" + name = "github.com/prometheus/client_model" + packages = ["go"] + revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" + +[[projects]] + branch = "master" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model" + ] + revision = "7600349dcfe1abd18d72d3a1770870d9800a7801" + +[[projects]] + branch = "master" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfs", + "xfs" + ] + revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a" + +[[projects]] + branch = "master" + name = "github.com/rcrowley/go-metrics" + packages = ["."] + revision = "e2704e165165ec55d062f5919b4b29494e9fa790" + +[[projects]] + name = "github.com/spf13/afero" + packages = [ + ".", + "mem" + ] + revision = "787d034dfe70e44075ccc060d346146ef53270ad" + version = "v1.1.1" + +[[projects]] + name = "github.com/spf13/cast" + packages = ["."] + revision = "8965335b8c7107321228e3e3702cab9832751bac" + version = "v1.2.0" + +[[projects]] + name = "github.com/spf13/cobra" + packages = ["."] + revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b" + version = "v0.0.1" + +[[projects]] + branch = "master" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" + +[[projects]] + name = "github.com/spf13/pflag" + packages = ["."] + revision = "583c0c0531f06d5278b7d917446061adc344b5cd" + version = "v1.0.1" + +[[projects]] + name = "github.com/spf13/viper" + packages = ["."] + revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" + version = "v1.0.0" + +[[projects]] + name = "github.com/stretchr/testify" + packages = [ + "assert", + "require" + ] + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" + +[[projects]] + branch = "master" + name = "github.com/syndtr/goleveldb" + packages = [ + "leveldb", + "leveldb/cache", + "leveldb/comparer", + "leveldb/errors", + "leveldb/filter", + "leveldb/iterator", + "leveldb/journal", + "leveldb/memdb", + "leveldb/opt", + "leveldb/storage", + "leveldb/table", + "leveldb/util" + ] + revision = "0d5a0ceb10cf9ab89fdd744cc8c50a83134f6697" + +[[projects]] + branch = "master" + name = "github.com/tendermint/ed25519" + packages = [ + ".", + "edwards25519", + "extra25519" + ] + revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057" + +[[projects]] + name = "github.com/tendermint/go-amino" + packages = ["."] + revision = "2106ca61d91029c931fd54968c2bb02dc96b1412" + version = "0.10.1" + +[[projects]] + name = "github.com/tendermint/iavl" + packages = ["."] + revision = "9e5dc3e61f70b285bb25414452d47aca1ff34c1d" + version = "v0.8.2-rc0" + +[[projects]] + name = "github.com/tendermint/tendermint" + packages = [ + "abci/client", + "abci/example/code", + "abci/example/kvstore", + "abci/server", + "abci/types", + "blockchain", + "cmd/tendermint/commands", + "config", + "consensus", + "consensus/types", + "crypto", + "crypto/merkle", + "crypto/tmhash", + "evidence", + "libs/autofile", + "libs/bech32", + "libs/cli", + "libs/cli/flags", + "libs/clist", + "libs/common", + "libs/db", + "libs/events", + "libs/flowrate", + "libs/log", + "libs/pubsub", + "libs/pubsub/query", + "lite", + "lite/client", + "lite/errors", + "lite/files", + "lite/proxy", + "mempool", + "node", + "p2p", + "p2p/conn", + "p2p/pex", + "p2p/upnp", + "privval", + "proxy", + "rpc/client", + "rpc/core", + "rpc/core/types", + "rpc/grpc", + "rpc/lib", + "rpc/lib/client", + "rpc/lib/server", + "rpc/lib/types", + "state", + "state/txindex", + "state/txindex/kv", + "state/txindex/null", + "types", + "version" + ] + revision = "5923b6288fe8ce9581936ee97c2bf9cf9c02c2f4" + version = "v0.22.0-rc2" + +[[projects]] + name = "github.com/zondax/ledger-goclient" + packages = ["."] + revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = [ + "blowfish", + "curve25519", + "internal/subtle", + "nacl/box", + "nacl/secretbox", + "openpgp/armor", + "openpgp/errors", + "pbkdf2", + "poly1305", + "ripemd160", + "salsa20/salsa" + ] + revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "context", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "netutil", + "trace" + ] + revision = "ed29d75add3d7c4bf7ca65aac0c6df3d1420216f" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = ["unix"] + revision = "151529c776cdc58ddbe7963ba9af779f3577b419" + +[[projects]] + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable" + ] + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + name = "google.golang.org/genproto" + packages = ["googleapis/rpc/status"] + revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" + +[[projects]] + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "codes", + "connectivity", + "credentials", + "encoding", + "encoding/proto", + "grpclb/grpc_lb_v1/messages", + "grpclog", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + "transport" + ] + revision = "d11072e7ca9811b1100b80ca0269ac831f06d024" + version = "v1.11.3" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "13ad2a57b6942729e2d08b5c37810d62108aa64a335a4822fcff1ad992c0662b" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/client/context/viper.go b/client/context/viper.go index c0b48fc85d..2e3ed0dd3a 100644 --- a/client/context/viper.go +++ b/client/context/viper.go @@ -27,13 +27,20 @@ func NewCoreContextFromViper() CoreContext { chainID = def } } + // TODO: Remove the following deprecation code after Gaia-7000 is launched + keyName := viper.GetString(client.FlagName) + if keyName != "" { + fmt.Println("** Note --name is deprecated and will be removed next release. Please use --from instead **") + } else { + keyName = viper.GetString(client.FlagFrom) + } return CoreContext{ ChainID: chainID, Height: viper.GetInt64(client.FlagHeight), Gas: viper.GetInt64(client.FlagGas), Fee: viper.GetString(client.FlagFee), TrustNode: viper.GetBool(client.FlagTrustNode), - FromAddressName: viper.GetString(client.FlagName), + FromAddressName: keyName, NodeURI: nodeURI, AccountNumber: viper.GetInt64(client.FlagAccountNumber), Sequence: viper.GetInt64(client.FlagSequence), diff --git a/client/flags.go b/client/flags.go index 31e9c087bf..ef3711be95 100644 --- a/client/flags.go +++ b/client/flags.go @@ -10,6 +10,7 @@ const ( FlagHeight = "height" FlagGas = "gas" FlagTrustNode = "trust-node" + FlagFrom = "from" FlagName = "name" FlagAccountNumber = "account-number" FlagSequence = "sequence" @@ -37,7 +38,8 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { // PostCommands adds common flags for commands to post tx func PostCommands(cmds ...*cobra.Command) []*cobra.Command { for _, c := range cmds { - c.Flags().String(FlagName, "", "Name of private key with which to sign") + c.Flags().String(FlagFrom, "", "Name of private key with which to sign") + c.Flags().String(FlagName, "", "DEPRECATED - Name of private key with which to sign") c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx") c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx") c.Flags().String(FlagMemo, "", "Memo to send along with transaction") diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 0761bd08f7..93ef825aa6 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -59,7 +59,7 @@ func TestGaiaCLISend(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -68,7 +68,7 @@ func TestGaiaCLISend(t *testing.T) { require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) // test autosequencing - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -77,7 +77,7 @@ func TestGaiaCLISend(t *testing.T) { require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64()) // test memo - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo --memo 'testmemo'", flags, barCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo --memo 'testmemo'", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -111,7 +111,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { barCech := sdk.MustBech32ifyAcc(barAddr) barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -121,7 +121,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { // create validator cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags) - cvStr += fmt.Sprintf(" --name=%v", "bar") + cvStr += fmt.Sprintf(" --from=%v", "bar") cvStr += fmt.Sprintf(" --address-validator=%v", barCech) cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey) cvStr += fmt.Sprintf(" --amount=%v", "2steak") @@ -139,7 +139,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) - unbondStr += fmt.Sprintf(" --name=%v", "bar") + unbondStr += fmt.Sprintf(" --from=%v", "bar") unbondStr += fmt.Sprintf(" --address-validator=%v", barCech) unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech) unbondStr += fmt.Sprintf(" --shares-amount=%v", "1") @@ -181,7 +181,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) - executeWrite(t, fmt.Sprintf("gaiacli gov submitproposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --name=foo", flags, fooCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli gov submitproposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --from=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) @@ -191,7 +191,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, int64(1), proposal1.ProposalID) require.Equal(t, gov.StatusToString(gov.StatusDepositPeriod), proposal1.Status) - executeWrite(t, fmt.Sprintf("gaiacli gov deposit %v --depositer=%v --deposit=10steak --proposalID=1 --name=foo", flags, fooCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli gov deposit %v --depositer=%v --deposit=10steak --proposalID=1 --from=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) @@ -200,7 +200,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, int64(1), proposal1.ProposalID) require.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal1.Status) - executeWrite(t, fmt.Sprintf("gaiacli gov vote %v --proposalID=1 --voter=%v --option=Yes --name=foo", flags, fooCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli gov vote %v --proposalID=1 --voter=%v --option=Yes --from=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposalID=1 --voter=%v --output=json %v", fooCech, flags)) diff --git a/cmd/gaia/testnets/README.md b/cmd/gaia/testnets/README.md index f65b9267ec..e8d1f83e4d 100644 --- a/cmd/gaia/testnets/README.md +++ b/cmd/gaia/testnets/README.md @@ -220,7 +220,7 @@ gaiacli stake create-validator \ --address-validator= --moniker="choose a moniker" \ --chain-id=gaia-6002 \ - --name= + --from= ``` ### Edit Validator Description @@ -237,7 +237,7 @@ gaiacli stake edit-validator --keybase-sig="6A0D65E29A4CBC8E" --details="To infinity and beyond!" --chain-id=gaia-6002 \ - --name= + --from= ``` ### View Validator Description @@ -272,7 +272,7 @@ gaiad start Wait for your full node to catch up to the latest block. Next, run the following command. Note that `` is the address of your validator account, and `` is the name of the validator account. You can find this info by running `gaiacli keys list`. ```bash -gaiacli stake unrevoke --chain-id=gaia-6002 --name= +gaiacli stake unrevoke --chain-id=gaia-6002 --from= ``` **WARNING:** If you don't wait for `gaiad` to sync before running `unrevoke`, you will receive an error message telling you your validator is still jailed. @@ -321,7 +321,7 @@ gaiacli stake delegate \ --amount=10steak \ --address-delegator= \ --address-validator= \ - --name= \ + --from= \ --chain-id=gaia-6002 ``` @@ -338,7 +338,7 @@ gaiacli stake unbond \ --address-delegator= \ --address-validator= \ --shares=MAX \ - --name= \ + --from= \ --chain-id=gaia-6002 ``` @@ -361,7 +361,7 @@ gaiacli stake delegation \ gaiacli send \ --amount=10faucetToken \ --chain-id=gaia-6002 \ - --name= \ + --from= \ --to= ``` diff --git a/docs/_attic/staking/intro.rst b/docs/_attic/staking/intro.rst index 3ed20852b4..14735ef33b 100644 --- a/docs/_attic/staking/intro.rst +++ b/docs/_attic/staking/intro.rst @@ -197,9 +197,9 @@ We'll have ``alice`` send some ``mycoin`` to ``bob``, who has now joined the net :: - gaiacli send --amount=1000mycoin --sequence=0 --name=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU + gaiacli send --amount=1000mycoin --sequence=0 --from=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU -where the ``--sequence`` flag is to be incremented for each transaction, the ``--name`` flag is the sender (alice), and the ``--to`` flag takes ``bob``'s address. You'll see something like: +where the ``--sequence`` flag is to be incremented for each transaction, the ``--from`` flag is the sender (alice), and the ``--to`` flag takes ``bob``'s address. You'll see something like: :: @@ -264,7 +264,7 @@ Now ``bob`` can create a validator with that pubkey. :: - gaiacli stake create-validator --amount=10mycoin --name=bob --address-validator=
--pub-key= --moniker=bobby + gaiacli stake create-validator --amount=10mycoin --from=bob --address-validator=
--pub-key= --moniker=bobby with an output like: @@ -306,13 +306,13 @@ First let's have ``alice`` send some coins to ``charlie``: :: - gaiacli send --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF + gaiacli send --amount=1000mycoin --sequence=2 --from=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF Then ``charlie`` will delegate some mycoin to ``bob``: :: - gaiacli stake delegate --amount=10mycoin --address-delegator= --address-validator= --name=charlie + gaiacli stake delegate --amount=10mycoin --address-delegator= --address-validator= --from=charlie You'll see output like: @@ -396,7 +396,7 @@ your VotingPower reduce and your account balance increase. :: - gaiacli stake unbond --amount=5mycoin --name=charlie --address-delegator=
--address-validator=
+ gaiacli stake unbond --amount=5mycoin --from=charlie --address-delegator=
--address-validator=
gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF See the bond decrease with ``gaiacli stake delegation`` like above. diff --git a/docs/_attic/staking/testnet.md b/docs/_attic/staking/testnet.md index b2bbd8f1a3..5228070cf1 100644 --- a/docs/_attic/staking/testnet.md +++ b/docs/_attic/staking/testnet.md @@ -63,7 +63,7 @@ Then, we try to transfer some `steak` to another account: ``` gaiacli account gaiacli account -gaiacli send --amount=10steak --to= --name=foo --chain-id=test-chain +gaiacli send --amount=10steak --to= --from=foo --chain-id=test-chain ``` **Note:** We need to be careful with the `chain-id` and `sequence` @@ -84,7 +84,7 @@ Finally, to relinquish all your power, unbond some coins. You should see your VotingPower reduce and your account balance increase. ``` -gaiacli unbond --chain-id= --name=test +gaiacli unbond --chain-id= --from=test ``` That's it! diff --git a/docs/clients/ledger.md b/docs/clients/ledger.md index 9f6386715d..5ea1224eae 100644 --- a/docs/clients/ledger.md +++ b/docs/clients/ledger.md @@ -23,7 +23,7 @@ NAME: TYPE: ADDRESS: PUBKEY: This key will only be accessible while the Ledger is plugged in and unlocked. To send some coins with this key, run the following: ```bash -$ gaiacli send --name {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000 +$ gaiacli send --from {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000 ``` You will be asked to review and confirm the transaction on the Ledger. Once you do this you should see the result in the console! Now you can use your Ledger to manage your Atoms and Stake! diff --git a/examples/README.md b/examples/README.md index a8a483ee62..e3016fb707 100644 --- a/examples/README.md +++ b/examples/README.md @@ -123,12 +123,12 @@ Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alice's address we got from The following command will send coins from alice, to bob: ``` -basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D +basecli send --from=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D --sequence=0 --chain-id=test-chain-AE4XQo ``` Flag Descriptions: -- `name` is the name you gave your key +- `from` is the name you gave your key - `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file - `sequence` is a tally of how many transactions have been made by this account. Since this is the first tx on this account, it is 0 - `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/genesis.json` @@ -142,16 +142,16 @@ basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail: ``` -basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E +basecli send --from=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E --sequence=0 --chain-id=test-chain-AE4XQo ``` -Note how we use the ``--name`` flag to select a different account to send from. +Note how we use the ``--from`` flag to select a different account to send from. Lets now try to send from bob back to alice: ``` -basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD +basecli send --from=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD --sequence=1 --chain-id=test-chain-AE4XQo ``` diff --git a/tests/check_basecli.sh b/tests/check_basecli.sh index ec2c458cb6..ffcf39a517 100755 --- a/tests/check_basecli.sh +++ b/tests/check_basecli.sh @@ -36,7 +36,7 @@ echo; echo "Empty account:" $TO ./build/basecli account $TO # send some money -TX=`echo $PASS | ./build/basecli send --to=$TO --amount=1000mycoin --name=demo --seq=0` +TX=`echo $PASS | ./build/basecli send --to=$TO --amount=1000mycoin --from=demo --seq=0` echo; echo "SendTx"; echo $TX HASH=`echo $TX | cut -d' ' -f6` echo "tx hash:" $HASH diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index e3ce4c4d2f..11f25b4bac 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -78,7 +78,7 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { if err != nil { return err } - fmt.Println("Async tx sent. tx hash: ", res.Hash.String()) + fmt.Printf("Async tx sent. tx hash: %s\n", res.Hash.String()) return nil } res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) diff --git a/x/ibc/client/cli/README.md b/x/ibc/client/cli/README.md index e91fb55bfc..ab9e8e5558 100644 --- a/x/ibc/client/cli/README.md +++ b/x/ibc/client/cli/README.md @@ -109,7 +109,7 @@ key2 DC26002735D3AA9573707CFA6D77C12349E49868 ## Transfer coins (addr1:chain1 -> addr2:chain2) ```console -> basecli transfer --name key1 --to $ADDR2 --amount 10mycoin --chain $ID2 --chain-id $ID1 --node $NODE1 +> basecli transfer --from key1 --to $ADDR2 --amount 10mycoin --chain $ID2 --chain-id $ID1 --node $NODE1 Password to sign with 'key1': Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0 > basecli account $ADDR1 --node $NODE1 @@ -133,7 +133,7 @@ Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0 ## Relay IBC packets ```console -> basecli relay --name key2 --from-chain-id $ID1 --from-chain-node $NODE1 --to-chain-id $ID2 --to-chain-node $NODE2 --chain-id $ID2 +> basecli relay --from key2 --from-chain-id $ID1 --from-chain-node $NODE1 --to-chain-id $ID2 --to-chain-node $NODE2 --chain-id $ID2 Password to sign with 'key2': I[04-03|16:18:59.984] Detected IBC packet number=0 I[04-03|16:19:00.869] Relayed IBC packet number=0 From 0b10430d65f8313d5a387c0aaf1d26a73d912e1d Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 18:03:41 -0700 Subject: [PATCH 43/53] gaiacli, keys: Improve error message when deleting non-existant key --- CHANGELOG.md | 3 ++- client/keys/delete.go | 13 +++++++++---- crypto/keys/keybase.go | 3 +++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb9672c5e5..f46475843f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,8 +80,9 @@ IMPROVEMENTS * [stake] module reorganized to include `types` and `keeper` package * [stake] keeper always loads the store (instead passing around which doesn't really boost efficiency) * [stake] edit-validator changes now can use the keyword [do-not-modify] to not modify unspecified `--flag` (aka won't set them to `""` value) -* [types] added common tag constants * [stake] offload more generic functionality from the handler into the keeper +* [types] added common tag constants +* [keys] improve error message when deleting non-existent key * added contributing guidelines BUG FIXES diff --git a/client/keys/delete.go b/client/keys/delete.go index f38c529a6f..944feb4b19 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -25,14 +25,19 @@ func deleteKeyCommand() *cobra.Command { func runDeleteCmd(cmd *cobra.Command, args []string) error { name := args[0] - buf := client.BufferStdin() - oldpass, err := client.GetPassword( - "DANGER - enter password to permanently delete key:", buf) + kb, err := GetKeyBase() if err != nil { return err } - kb, err := GetKeyBase() + _, err = kb.Get(name) + if err != nil { + return err + } + + buf := client.BufferStdin() + oldpass, err := client.GetPassword( + "DANGER - enter password to permanently delete key:", buf) if err != nil { return err } diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index 82adc53dda..7cf43eea67 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -188,6 +188,9 @@ func (kb dbKeybase) List() ([]Info, error) { // Get returns the public information about one key. func (kb dbKeybase) Get(name string) (Info, error) { bs := kb.db.Get(infoKey(name)) + if len(bs) == 0 { + return nil, fmt.Errorf("Key %s not found", name) + } return readInfo(bs) } From 8fc6e685111ff1168af533eb2214b0de2796a4e3 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 18:24:00 -0700 Subject: [PATCH 44/53] stake/client: Fix panic on if validator doesn't exist Closes #1505 --- CHANGELOG.md | 1 + x/stake/client/cli/query.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb9672c5e5..57bea2f9a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -101,6 +101,7 @@ BUG FIXES * \#1258 - printing big.rat's can no longer overflow int64 * \#887 - limit the size of rationals that can be passed in from user input * \#1461 - CLI tests now no longer reset your local environment data +* \#1505 - `gaiacli stake validator` no longer panics if validator doesn't exist ## 0.19.0 diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 82149a2fa5..30f833c020 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -31,8 +31,9 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { res, err := ctx.QueryStore(key, storeName) if err != nil { return err + } else if len(res) == 0 { + return fmt.Errorf("No validator found with address %s", args[0]) } - validator := types.MustUnmarshalValidator(cdc, addr, res) switch viper.Get(cli.OutputFlag) { From 1fabaee2dd0fe53c233c8929ffe94cc11a51726b Mon Sep 17 00:00:00 2001 From: Liamsi Date: Fri, 6 Jul 2018 02:37:55 +0100 Subject: [PATCH 45/53] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b356641404..7b5834035e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ *TBD* BREAKING CHANGES +* msg.GetSignBytes() returns sorted JSON (by key) * Update Tendermint to v0.22.0 * Default ports changed from 466xx to 266xx * Amino JSON uses type names instead of prefix bytes From 6f94dd64c0bafdd31f0c7b751f12d2449c7cff14 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 19:15:35 -0700 Subject: [PATCH 46/53] cli: Add async flag to all broadcasting txs closes #1436 --- client/context/helpers.go | 25 ++++++++++--------- client/flags.go | 2 ++ examples/democoin/x/cool/client/cli/tx.go | 8 ++---- examples/democoin/x/pow/client/cli/tx.go | 6 ++--- .../x/simplestake/client/cli/commands.go | 4 +-- x/bank/client/cli/sendtx.go | 20 +++------------ x/gov/client/cli/tx.go | 11 +++----- x/ibc/client/cli/ibctx.go | 5 +--- x/slashing/client/cli/tx.go | 8 +++--- x/stake/client/cli/tx.go | 22 ++++++---------- 10 files changed, 41 insertions(+), 70 deletions(-) diff --git a/client/context/helpers.go b/client/context/helpers.go index 89c1713533..06914be8c4 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -224,25 +224,26 @@ func (ctx CoreContext) ensureSignBuild(name string, msgs []sdk.Msg, cdc *wire.Co } // sign and build the transaction from the msg -func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) { +func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec, async bool, printResponse bool) (err error) { txBytes, err := ctx.ensureSignBuild(name, msgs, cdc) if err != nil { - return nil, err + return err } - return ctx.BroadcastTx(txBytes) -} - -// sign and build the async transaction from the msg -func (ctx CoreContext) EnsureSignBuildBroadcastAsync(name string, msgs []sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTx, err error) { - - txBytes, err := ctx.ensureSignBuild(name, msgs, cdc) - if err != nil { - return nil, err + if async { + res, err := ctx.BroadcastTxAsync(txBytes) + fmt.Println("Async tx sent. tx hash: ", res.Hash.String()) + return err } + res, err := ctx.BroadcastTx(txBytes) + if printResponse { + fmt.Printf("Committed at block %d. Hash: %s Response:%+v \n", res.Height, res.Hash.String(), res.DeliverTx) + } else { - return ctx.BroadcastTxAsync(txBytes) + fmt.Printf("Committed at block %d. Hash: %s \n", res.Height, res.Hash.String()) + } + return err } // get the next sequence for the account address diff --git a/client/flags.go b/client/flags.go index 31e9c087bf..9fb73ad412 100644 --- a/client/flags.go +++ b/client/flags.go @@ -15,6 +15,7 @@ const ( FlagSequence = "sequence" FlagMemo = "memo" FlagFee = "fee" + FlagAsync = "async" ) // LineBreak can be included in a command list to provide a blank line @@ -46,6 +47,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().String(FlagNode, "tcp://localhost:26657", ": to tendermint rpc interface for this chain") c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device") c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction") + c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously") } return cmds } diff --git a/examples/democoin/x/cool/client/cli/tx.go b/examples/democoin/x/cool/client/cli/tx.go index cb65830c93..a6ad09b614 100644 --- a/examples/democoin/x/cool/client/cli/tx.go +++ b/examples/democoin/x/cool/client/cli/tx.go @@ -1,8 +1,6 @@ package cli import ( - "fmt" - "github.com/spf13/cobra" "github.com/spf13/viper" @@ -37,12 +35,11 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command { name := viper.GetString(client.FlagName) // build and sign the transaction, then broadcast to Tendermint - res, err := ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } @@ -70,12 +67,11 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command { msg := cool.NewMsgSetTrend(from, args[0]) // build and sign the transaction, then broadcast to Tendermint - res, err := ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } diff --git a/examples/democoin/x/pow/client/cli/tx.go b/examples/democoin/x/pow/client/cli/tx.go index 49527c8c08..7953c31774 100644 --- a/examples/democoin/x/pow/client/cli/tx.go +++ b/examples/democoin/x/pow/client/cli/tx.go @@ -1,11 +1,12 @@ package cli import ( - "fmt" "strconv" "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/examples/democoin/x/pow" @@ -49,12 +50,11 @@ func MineCmd(cdc *wire.Codec) *cobra.Command { name := ctx.FromAddressName // build and sign the transaction, then broadcast to Tendermint - res, err := ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } diff --git a/examples/democoin/x/simplestake/client/cli/commands.go b/examples/democoin/x/simplestake/client/cli/commands.go index fcd0c84b45..a895a41543 100644 --- a/examples/democoin/x/simplestake/client/cli/commands.go +++ b/examples/democoin/x/simplestake/client/cli/commands.go @@ -9,6 +9,7 @@ import ( "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -87,11 +88,10 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command { func sendMsg(cdc *wire.Codec, msg sdk.Msg) error { ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil } diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index e3ce4c4d2f..6b5a54b264 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -2,23 +2,21 @@ package cli import ( "errors" - "fmt" - - "github.com/spf13/cobra" - "github.com/spf13/viper" + baseClient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/bank/client" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) const ( flagTo = "to" flagAmount = "amount" - flagAsync = "async" ) // SendTxCmd will create a send tx and sign it with the given key @@ -73,19 +71,10 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint msg := client.BuildMsg(from, to, coins) - if viper.GetBool(flagAsync) { - res, err := ctx.EnsureSignBuildBroadcastAsync(ctx.FromAddressName, []sdk.Msg{msg}, cdc) - if err != nil { - return err - } - fmt.Println("Async tx sent. tx hash: ", res.Hash.String()) - return nil - } - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(baseClient.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, @@ -93,7 +82,6 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { cmd.Flags().String(flagTo, "", "Address to send coins") cmd.Flags().String(flagAmount, "", "Amount of coins to send") - cmd.Flags().Bool(flagAsync, false, "Pass the async flag to send a tx without waiting for the tx to be included in a block") return cmd } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 00933284e9..8b0be208d7 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -64,12 +65,10 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), true) if err != nil { return err } - - fmt.Printf("Committed at block:%d. Hash:%s.Response:%+v \n", res.Height, res.Hash.String(), res.DeliverTx) return nil }, } @@ -113,11 +112,10 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } @@ -164,11 +162,10 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } diff --git a/x/ibc/client/cli/ibctx.go b/x/ibc/client/cli/ibctx.go index 9df58d6a8a..7e56fc4cfd 100644 --- a/x/ibc/client/cli/ibctx.go +++ b/x/ibc/client/cli/ibctx.go @@ -2,7 +2,6 @@ package cli import ( "encoding/hex" - "fmt" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -43,12 +42,10 @@ func IBCTransferCmd(cdc *wire.Codec) *cobra.Command { } // get password - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index de390ce239..7a04116284 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -1,10 +1,10 @@ package cli import ( - "fmt" - "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -29,12 +29,10 @@ func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command { msg := slashing.NewMsgUnrevoke(validatorAddr) // build and sign the transaction, then broadcast to Tendermint - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 7200caef3f..c633d83df4 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -53,12 +53,10 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) // build and sign the transaction, then broadcast to Tendermint - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } @@ -92,12 +90,11 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } @@ -132,12 +129,11 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } @@ -197,12 +193,11 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } @@ -282,12 +277,11 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } @@ -340,12 +334,11 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } @@ -377,12 +370,11 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) if err != nil { return err } - fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil }, } From 27a31cae44da7738de909da67cf016ae6e2b2a17 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 20:05:17 -0700 Subject: [PATCH 47/53] add Async to context --- client/context/types.go | 1 + client/context/viper.go | 1 + examples/democoin/x/cool/client/cli/tx.go | 4 ++-- examples/democoin/x/pow/client/cli/tx.go | 4 +--- .../democoin/x/simplestake/client/cli/commands.go | 3 +-- x/bank/client/cli/sendtx.go | 3 +-- x/gov/client/cli/tx.go | 7 +++---- x/ibc/client/cli/ibctx.go | 2 +- x/slashing/client/cli/tx.go | 4 +--- x/stake/client/cli/tx.go | 14 +++++++------- 10 files changed, 19 insertions(+), 24 deletions(-) diff --git a/client/context/types.go b/client/context/types.go index 58df9b5bf2..017ed9565c 100644 --- a/client/context/types.go +++ b/client/context/types.go @@ -22,6 +22,7 @@ type CoreContext struct { Decoder auth.AccountDecoder AccountStore string UseLedger bool + Async bool } // WithChainID - return a copy of the context with an updated chainID diff --git a/client/context/viper.go b/client/context/viper.go index c0b48fc85d..948cd7a7dd 100644 --- a/client/context/viper.go +++ b/client/context/viper.go @@ -42,6 +42,7 @@ func NewCoreContextFromViper() CoreContext { Decoder: nil, AccountStore: "acc", UseLedger: viper.GetBool(client.FlagUseLedger), + Async: viper.GetBool(client.FlagAsync), } } diff --git a/examples/democoin/x/cool/client/cli/tx.go b/examples/democoin/x/cool/client/cli/tx.go index a6ad09b614..5148e05611 100644 --- a/examples/democoin/x/cool/client/cli/tx.go +++ b/examples/democoin/x/cool/client/cli/tx.go @@ -35,7 +35,7 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command { name := viper.GetString(client.FlagName) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } @@ -67,7 +67,7 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command { msg := cool.NewMsgSetTrend(from, args[0]) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } diff --git a/examples/democoin/x/pow/client/cli/tx.go b/examples/democoin/x/pow/client/cli/tx.go index 7953c31774..bc6588f034 100644 --- a/examples/democoin/x/pow/client/cli/tx.go +++ b/examples/democoin/x/pow/client/cli/tx.go @@ -4,9 +4,7 @@ import ( "strconv" "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/examples/democoin/x/pow" @@ -50,7 +48,7 @@ func MineCmd(cdc *wire.Codec) *cobra.Command { name := ctx.FromAddressName // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } diff --git a/examples/democoin/x/simplestake/client/cli/commands.go b/examples/democoin/x/simplestake/client/cli/commands.go index a895a41543..c907a8b8ff 100644 --- a/examples/democoin/x/simplestake/client/cli/commands.go +++ b/examples/democoin/x/simplestake/client/cli/commands.go @@ -9,7 +9,6 @@ import ( "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -88,7 +87,7 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command { func sendMsg(cdc *wire.Codec, msg sdk.Msg) error { ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index 6b5a54b264..4d142b90d7 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -3,7 +3,6 @@ package cli import ( "errors" - baseClient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -71,7 +70,7 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint msg := client.BuildMsg(from, to, coins) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(baseClient.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 8b0be208d7..626259ad06 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -6,7 +6,6 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -65,7 +64,7 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), true) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, true) if err != nil { return err } @@ -112,7 +111,7 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } @@ -162,7 +161,7 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } diff --git a/x/ibc/client/cli/ibctx.go b/x/ibc/client/cli/ibctx.go index 7e56fc4cfd..4ab5217a0a 100644 --- a/x/ibc/client/cli/ibctx.go +++ b/x/ibc/client/cli/ibctx.go @@ -42,7 +42,7 @@ func IBCTransferCmd(cdc *wire.Codec) *cobra.Command { } // get password - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 7a04116284..133ddf090f 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -2,9 +2,7 @@ package cli import ( "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -29,7 +27,7 @@ func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command { msg := slashing.NewMsgUnrevoke(validatorAddr) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index c633d83df4..ce35c3de82 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -53,7 +53,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } @@ -90,7 +90,7 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } @@ -129,7 +129,7 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } @@ -193,7 +193,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } @@ -277,7 +277,7 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } @@ -334,7 +334,7 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } @@ -370,7 +370,7 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, viper.GetBool(client.FlagAsync), false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) if err != nil { return err } From 8857b69d02ebceb8d07058fee9c0be90a93b47fe Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 20:15:40 -0700 Subject: [PATCH 48/53] Use async flag directly from context --- client/context/helpers.go | 2 +- examples/democoin/x/cool/client/cli/tx.go | 4 ++-- examples/democoin/x/pow/client/cli/tx.go | 2 +- .../democoin/x/simplestake/client/cli/commands.go | 2 +- x/bank/client/cli/sendtx.go | 2 +- x/gov/client/cli/tx.go | 6 +++--- x/ibc/client/cli/ibctx.go | 2 +- x/slashing/client/cli/tx.go | 2 +- x/stake/client/cli/tx.go | 14 +++++++------- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/client/context/helpers.go b/client/context/helpers.go index 06914be8c4..9b7891431d 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -231,7 +231,7 @@ func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc return err } - if async { + if ctx.Async { res, err := ctx.BroadcastTxAsync(txBytes) fmt.Println("Async tx sent. tx hash: ", res.Hash.String()) return err diff --git a/examples/democoin/x/cool/client/cli/tx.go b/examples/democoin/x/cool/client/cli/tx.go index 5148e05611..9300f46c21 100644 --- a/examples/democoin/x/cool/client/cli/tx.go +++ b/examples/democoin/x/cool/client/cli/tx.go @@ -35,7 +35,7 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command { name := viper.GetString(client.FlagName) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, false) if err != nil { return err } @@ -67,7 +67,7 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command { msg := cool.NewMsgSetTrend(from, args[0]) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, false) if err != nil { return err } diff --git a/examples/democoin/x/pow/client/cli/tx.go b/examples/democoin/x/pow/client/cli/tx.go index bc6588f034..43b33bd6e9 100644 --- a/examples/democoin/x/pow/client/cli/tx.go +++ b/examples/democoin/x/pow/client/cli/tx.go @@ -48,7 +48,7 @@ func MineCmd(cdc *wire.Codec) *cobra.Command { name := ctx.FromAddressName // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, false) if err != nil { return err } diff --git a/examples/democoin/x/simplestake/client/cli/commands.go b/examples/democoin/x/simplestake/client/cli/commands.go index c907a8b8ff..197d986711 100644 --- a/examples/democoin/x/simplestake/client/cli/commands.go +++ b/examples/democoin/x/simplestake/client/cli/commands.go @@ -87,7 +87,7 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command { func sendMsg(cdc *wire.Codec, msg sdk.Msg) error { ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index 4d142b90d7..aa51c5a194 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -70,7 +70,7 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint msg := client.BuildMsg(from, to, coins) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 626259ad06..cde0d74988 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -64,7 +64,7 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, true) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, true) if err != nil { return err } @@ -111,7 +111,7 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } @@ -161,7 +161,7 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } diff --git a/x/ibc/client/cli/ibctx.go b/x/ibc/client/cli/ibctx.go index 4ab5217a0a..e4e6a5b76d 100644 --- a/x/ibc/client/cli/ibctx.go +++ b/x/ibc/client/cli/ibctx.go @@ -42,7 +42,7 @@ func IBCTransferCmd(cdc *wire.Codec) *cobra.Command { } // get password - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 133ddf090f..eaeaf3eb81 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -27,7 +27,7 @@ func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command { msg := slashing.NewMsgUnrevoke(validatorAddr) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index ce35c3de82..d7f91e29db 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -53,7 +53,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } @@ -90,7 +90,7 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } @@ -129,7 +129,7 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } @@ -193,7 +193,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } @@ -277,7 +277,7 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } @@ -334,7 +334,7 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } @@ -370,7 +370,7 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, ctx.Async, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) if err != nil { return err } From 8e20200abe4ad42c319c95713d5bd1d418c925fa Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 20:42:41 -0700 Subject: [PATCH 49/53] Add --json flag --- CHANGELOG.md | 3 ++- client/context/helpers.go | 41 ++++++++++++++++++++++++++++++++++++--- client/context/types.go | 1 + client/context/viper.go | 1 + client/flags.go | 2 ++ 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ebcd32218..d914eb9fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,7 +75,7 @@ FEATURES - You can now use a Ledger with `gaiacli --ledger` for all key-related commands - Ledger keys can be named and tracked locally in the key DB * [gaiacli] added an --async flag to the cli to deliver transactions without waiting for a tendermint response -* [gaiacli] improve error messages on `send` and `account` commands +* [gaiacli] added a --json flag to the cli for deliver transactions IMPROVEMENTS * bank module uses go-wire codec instead of 'encoding/json' @@ -87,6 +87,7 @@ IMPROVEMENTS * [stake] offload more generic functionality from the handler into the keeper * [types] added common tag constants * [keys] improve error message when deleting non-existent key +* [gaiacli] improve error messages on `send` and `account` commands * added contributing guidelines BUG FIXES diff --git a/client/context/helpers.go b/client/context/helpers.go index e5002e0b50..e567eea7d9 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -233,17 +233,52 @@ func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc if ctx.Async { res, err := ctx.BroadcastTxAsync(txBytes) - fmt.Println("Async tx sent. tx hash: ", res.Hash.String()) - return err + if err != nil { + return err + } + if ctx.JSON { + type toJSON struct { + TxHash string + } + valueToJSON := toJSON{res.Hash.String()} + JSON, err := cdc.MarshalJSON(valueToJSON) + if err != nil { + return err + } + fmt.Println(string(JSON)) + } else { + fmt.Println("Async tx sent. tx hash: ", res.Hash.String()) + } + return nil } res, err := ctx.BroadcastTx(txBytes) + if err != nil { + return err + } + if ctx.JSON { + type toJSON struct { + Height int64 + TxHash string + Response string + } + valueToJSON := toJSON{res.Height, res.Hash.String(), ""} + if printResponse { + valueToJSON.Response = fmt.Sprintf("%+v", res.DeliverTx) + } + JSON, err := cdc.MarshalJSON(valueToJSON) + if err != nil { + return err + } + fmt.Println(string(JSON)) + return nil + } if printResponse { fmt.Printf("Committed at block %d. Hash: %s Response:%+v \n", res.Height, res.Hash.String(), res.DeliverTx) } else { fmt.Printf("Committed at block %d. Hash: %s \n", res.Height, res.Hash.String()) } - return err + return nil } // get the next sequence for the account address diff --git a/client/context/types.go b/client/context/types.go index 017ed9565c..fd407883b3 100644 --- a/client/context/types.go +++ b/client/context/types.go @@ -23,6 +23,7 @@ type CoreContext struct { AccountStore string UseLedger bool Async bool + JSON bool } // WithChainID - return a copy of the context with an updated chainID diff --git a/client/context/viper.go b/client/context/viper.go index c3b83c63a3..7b8546cd31 100644 --- a/client/context/viper.go +++ b/client/context/viper.go @@ -50,6 +50,7 @@ func NewCoreContextFromViper() CoreContext { AccountStore: "acc", UseLedger: viper.GetBool(client.FlagUseLedger), Async: viper.GetBool(client.FlagAsync), + JSON: viper.GetBool(client.FlagJson), } } diff --git a/client/flags.go b/client/flags.go index a8cf15e531..985359de85 100644 --- a/client/flags.go +++ b/client/flags.go @@ -17,6 +17,7 @@ const ( FlagMemo = "memo" FlagFee = "fee" FlagAsync = "async" + FlagJson = "json" ) // LineBreak can be included in a command list to provide a blank line @@ -50,6 +51,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device") c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction") c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously") + c.Flags().Bool(FlagJson, false, "return output in json format") } return cmds } From c708c799fd5d013620569bef3c4cda76d54d7686 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 22:19:50 -0700 Subject: [PATCH 50/53] Add print-response flag --- CHANGELOG.md | 6 ++++-- client/context/helpers.go | 11 ++++------- client/context/types.go | 1 + client/context/viper.go | 1 + client/flags.go | 2 ++ examples/democoin/x/cool/client/cli/tx.go | 4 ++-- examples/democoin/x/pow/client/cli/tx.go | 2 +- .../democoin/x/simplestake/client/cli/commands.go | 2 +- x/bank/client/cli/sendtx.go | 2 +- x/gov/client/cli/tx.go | 8 +++++--- x/ibc/client/cli/ibctx.go | 2 +- x/slashing/client/cli/tx.go | 2 +- x/stake/client/cli/tx.go | 14 +++++++------- 13 files changed, 31 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d914eb9fe4..6c06a7c032 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,8 +74,10 @@ FEATURES * [gaiacli] Ledger support added - You can now use a Ledger with `gaiacli --ledger` for all key-related commands - Ledger keys can be named and tracked locally in the key DB -* [gaiacli] added an --async flag to the cli to deliver transactions without waiting for a tendermint response -* [gaiacli] added a --json flag to the cli for deliver transactions +* [gaiacli] added the following flags for commands that post transactions to the chain: + * async -- send the tx without waiting for a tendermint response + * json -- return the output in json format for increased readability + * print-response -- return the tx response. (includes fields like gas cost) IMPROVEMENTS * bank module uses go-wire codec instead of 'encoding/json' diff --git a/client/context/helpers.go b/client/context/helpers.go index e567eea7d9..e0fa45580b 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -224,7 +224,7 @@ func (ctx CoreContext) ensureSignBuild(name string, msgs []sdk.Msg, cdc *wire.Co } // sign and build the transaction from the msg -func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec, printResponse bool) (err error) { +func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec) (err error) { txBytes, err := ctx.ensureSignBuild(name, msgs, cdc) if err != nil { @@ -256,15 +256,13 @@ func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc return err } if ctx.JSON { + // Since JSON is intended for automated scripts, always include response in JSON mode type toJSON struct { Height int64 TxHash string Response string } - valueToJSON := toJSON{res.Height, res.Hash.String(), ""} - if printResponse { - valueToJSON.Response = fmt.Sprintf("%+v", res.DeliverTx) - } + valueToJSON := toJSON{res.Height, res.Hash.String(), fmt.Sprintf("%+v", res.DeliverTx)} JSON, err := cdc.MarshalJSON(valueToJSON) if err != nil { return err @@ -272,10 +270,9 @@ func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc fmt.Println(string(JSON)) return nil } - if printResponse { + if ctx.PrintResponse { fmt.Printf("Committed at block %d. Hash: %s Response:%+v \n", res.Height, res.Hash.String(), res.DeliverTx) } else { - fmt.Printf("Committed at block %d. Hash: %s \n", res.Height, res.Hash.String()) } return nil diff --git a/client/context/types.go b/client/context/types.go index fd407883b3..03dd6b9d03 100644 --- a/client/context/types.go +++ b/client/context/types.go @@ -24,6 +24,7 @@ type CoreContext struct { UseLedger bool Async bool JSON bool + PrintResponse bool } // WithChainID - return a copy of the context with an updated chainID diff --git a/client/context/viper.go b/client/context/viper.go index 7b8546cd31..611ad1b92f 100644 --- a/client/context/viper.go +++ b/client/context/viper.go @@ -51,6 +51,7 @@ func NewCoreContextFromViper() CoreContext { UseLedger: viper.GetBool(client.FlagUseLedger), Async: viper.GetBool(client.FlagAsync), JSON: viper.GetBool(client.FlagJson), + PrintResponse: viper.GetBool(client.FlagPrintResponse), } } diff --git a/client/flags.go b/client/flags.go index 985359de85..b96012da7d 100644 --- a/client/flags.go +++ b/client/flags.go @@ -18,6 +18,7 @@ const ( FlagFee = "fee" FlagAsync = "async" FlagJson = "json" + FlagPrintResponse = "print-response" ) // LineBreak can be included in a command list to provide a blank line @@ -52,6 +53,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction") c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously") c.Flags().Bool(FlagJson, false, "return output in json format") + c.Flags().Bool(FlagPrintResponse, false, "return tx response (only works with async = false)") } return cmds } diff --git a/examples/democoin/x/cool/client/cli/tx.go b/examples/democoin/x/cool/client/cli/tx.go index 9300f46c21..3e034600bd 100644 --- a/examples/democoin/x/cool/client/cli/tx.go +++ b/examples/democoin/x/cool/client/cli/tx.go @@ -35,7 +35,7 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command { name := viper.GetString(client.FlagName) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -67,7 +67,7 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command { msg := cool.NewMsgSetTrend(from, args[0]) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) if err != nil { return err } diff --git a/examples/democoin/x/pow/client/cli/tx.go b/examples/democoin/x/pow/client/cli/tx.go index 43b33bd6e9..bc958ffaeb 100644 --- a/examples/democoin/x/pow/client/cli/tx.go +++ b/examples/democoin/x/pow/client/cli/tx.go @@ -48,7 +48,7 @@ func MineCmd(cdc *wire.Codec) *cobra.Command { name := ctx.FromAddressName // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) if err != nil { return err } diff --git a/examples/democoin/x/simplestake/client/cli/commands.go b/examples/democoin/x/simplestake/client/cli/commands.go index 197d986711..20b5d95221 100644 --- a/examples/democoin/x/simplestake/client/cli/commands.go +++ b/examples/democoin/x/simplestake/client/cli/commands.go @@ -87,7 +87,7 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command { func sendMsg(cdc *wire.Codec, msg sdk.Msg) error { ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index aa51c5a194..8731de40e9 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -70,7 +70,7 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint msg := client.BuildMsg(from, to, coins) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index cde0d74988..633890f4be 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -63,8 +63,10 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + // proposalID must be returned, and it is a part of response + ctx.PrintResponse = true - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, true) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -111,7 +113,7 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -161,7 +163,7 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } diff --git a/x/ibc/client/cli/ibctx.go b/x/ibc/client/cli/ibctx.go index e4e6a5b76d..21aa3a3089 100644 --- a/x/ibc/client/cli/ibctx.go +++ b/x/ibc/client/cli/ibctx.go @@ -42,7 +42,7 @@ func IBCTransferCmd(cdc *wire.Codec) *cobra.Command { } // get password - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index eaeaf3eb81..c73b2e162f 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -27,7 +27,7 @@ func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command { msg := slashing.NewMsgUnrevoke(validatorAddr) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index d7f91e29db..9b8acb8cc8 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -53,7 +53,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) // build and sign the transaction, then broadcast to Tendermint - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -90,7 +90,7 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -129,7 +129,7 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -193,7 +193,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -277,7 +277,7 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -334,7 +334,7 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } @@ -370,7 +370,7 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc, false) + err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } From 12c1eb4d319da41f40438a68cd7ebd526d6ce393 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 5 Jul 2018 22:22:50 -0700 Subject: [PATCH 51/53] gov/client: rename submitproposal to submit-proposal It is standard in the sdk to use a dash for subcommands / flags with multiple words. This makes submitproposal comply with that. --- cmd/gaia/cli_test/cli_test.go | 2 +- x/gov/client/cli/tx.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 93ef825aa6..18e967bd3f 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -181,7 +181,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) - executeWrite(t, fmt.Sprintf("gaiacli gov submitproposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --from=foo", flags, fooCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli gov submit-proposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --from=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 00933284e9..9b918fb652 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -29,7 +29,7 @@ const ( // submit a proposal tx func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "submitproposal", + Use: "submit-proposal", Short: "Submit a proposal along with an initial deposit", RunE: func(cmd *cobra.Command, args []string) error { title := viper.GetString(flagTitle) From 6f8f222ef67bb39d4dfc3bd22128ccca985ee800 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 6 Jul 2018 13:19:11 -0700 Subject: [PATCH 52/53] Merge pull request #1175: Randomized Module Testing * WIP, ammend this later * Add randomized testing suite * Fix linting * Auth invariant check, method to take in seed, way to run invariant check less frequently * Fix merge conflicts * Update bank * Fix error on zero input by skipping it * Add PeriodicInvariant Function * Abstract verification / send functionality * Fix liniting errors (PeriodicInvariant godoc) * Update formatting and docs of randomization * Minor refactor, update godocs * Update godoc for mock * Export TestAndRunTx * fix cyclic dependencies * Address PR most pr comments * Fix merge conflict: Bring back codec.seal * remove debug code, fix linting * Fix merge conflicts --- CHANGELOG.md | 3 + baseapp/baseapp_test.go | 320 ---------------------------- baseapp/multimsg_test.go | 352 +++++++++++++++++++++++++++++++ x/bank/app_test.go | 24 ++- x/bank/bench_test.go | 13 ++ x/bank/test_helpers.go | 150 +++++++++++++ x/mock/app.go | 85 +++++++- x/mock/doc.go | 15 ++ x/mock/random_simulate_blocks.go | 95 +++++++++ x/mock/types.go | 38 ++++ 10 files changed, 757 insertions(+), 338 deletions(-) create mode 100644 baseapp/multimsg_test.go create mode 100644 x/bank/test_helpers.go create mode 100644 x/mock/doc.go create mode 100644 x/mock/random_simulate_blocks.go create mode 100644 x/mock/types.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c06a7c032..7012336d94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,9 @@ FEATURES * [gaiacli] Ledger support added - You can now use a Ledger with `gaiacli --ledger` for all key-related commands - Ledger keys can be named and tracked locally in the key DB +* [testing] created a randomized testing framework. + - Currently bank has limited functionality in the framework + - Auth has its invariants checked within the framework * [gaiacli] added the following flags for commands that post transactions to the chain: * async -- send the tx without waiting for a tendermint response * json -- return the output in json format for increased readability diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index b8c42c4d2e..2ed89c53ff 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -1,7 +1,6 @@ package baseapp import ( - "encoding/json" "fmt" "os" "testing" @@ -19,7 +18,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" ) func defaultLogger() log.Logger { @@ -651,324 +649,6 @@ func TestValidatorChange(t *testing.T) { //---------------------------------------- -// Use burn and send msg types to test multiple msgs in one tx -type testBurnMsg struct { - Addr sdk.Address - Amount sdk.Coins -} - -const msgType3 = "burn" - -func (msg testBurnMsg) Type() string { return msgType3 } -func (msg testBurnMsg) GetSignBytes() []byte { - bz, _ := json.Marshal(msg) - return sdk.MustSortJSON(bz) -} -func (msg testBurnMsg) ValidateBasic() sdk.Error { - if msg.Addr == nil { - return sdk.ErrInvalidAddress("Cannot use nil as Address") - } - return nil -} -func (msg testBurnMsg) GetSigners() []sdk.Address { - return []sdk.Address{msg.Addr} -} - -type testSendMsg struct { - Sender sdk.Address - Receiver sdk.Address - Amount sdk.Coins -} - -const msgType4 = "send" - -func (msg testSendMsg) Type() string { return msgType4 } -func (msg testSendMsg) GetSignBytes() []byte { - bz, _ := json.Marshal(msg) - return sdk.MustSortJSON(bz) -} -func (msg testSendMsg) ValidateBasic() sdk.Error { - if msg.Sender == nil || msg.Receiver == nil { - return sdk.ErrInvalidAddress("Cannot use nil as Address") - } - return nil -} -func (msg testSendMsg) GetSigners() []sdk.Address { - return []sdk.Address{msg.Sender} -} - -// Simple Handlers for burn and send - -func newHandleBurn(keeper bank.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - burnMsg := msg.(testBurnMsg) - _, _, err := keeper.SubtractCoins(ctx, burnMsg.Addr, burnMsg.Amount) - if err != nil { - return err.Result() - } - return sdk.Result{} - } -} - -func newHandleSpend(keeper bank.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - spendMsg := msg.(testSendMsg) - _, _, err := keeper.SubtractCoins(ctx, spendMsg.Sender, spendMsg.Amount) - if err != nil { - return err.Result() - } - _, _, err = keeper.AddCoins(ctx, spendMsg.Receiver, spendMsg.Amount) - if err != nil { - return err.Result() - } - return sdk.Result{} - } -} - -// generate a signed transaction -func GenTx(chainID string, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx { - // make the transaction free - fee := auth.StdFee{ - sdk.Coins{{"foocoin", sdk.NewInt(0)}}, - 100000, - } - - sigs := make([]auth.StdSignature, len(priv)) - for i, p := range priv { - sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, "")) - // TODO: replace with proper error handling: - if err != nil { - panic(err) - } - sigs[i] = auth.StdSignature{ - PubKey: p.PubKey(), - Signature: sig, - AccountNumber: accnums[i], - Sequence: seq[i], - } - } - return auth.NewStdTx(msgs, fee, sigs, "") -} - -// spin up simple app for testing -type testApp struct { - *BaseApp - accountMapper auth.AccountMapper - accountKeeper bank.Keeper -} - -func newTestApp(name string) testApp { - return testApp{ - BaseApp: newBaseApp(name), - } -} - -func MakeCodec() *wire.Codec { - cdc := wire.NewCodec() - cdc.RegisterInterface((*sdk.Msg)(nil), nil) - crypto.RegisterAmino(cdc) - cdc.RegisterInterface((*auth.Account)(nil), nil) - cdc.RegisterConcrete(&auth.BaseAccount{}, "cosmos-sdk/BaseAccount", nil) - cdc.Seal() - return cdc -} - -// tests multiple msgs of same type from same address in single tx -func TestMultipleBurn(t *testing.T) { - // Create app. - app := newTestApp(t.Name()) - capKey := sdk.NewKVStoreKey("key") - app.MountStoresIAVL(capKey) - app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx auth.StdTx - fromJSON(txBytes, &tx) - return tx, nil - }) - - err := app.LoadLatestVersion(capKey) - if err != nil { - panic(err) - } - - app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{}) - app.accountKeeper = bank.NewKeeper(app.accountMapper) - - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{})) - - app.Router(). - AddRoute("burn", newHandleBurn(app.accountKeeper)). - AddRoute("send", newHandleSpend(app.accountKeeper)) - - app.InitChain(abci.RequestInitChain{}) - app.BeginBlock(abci.RequestBeginBlock{}) - - // Set chain-id - app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) - - priv := makePrivKey("my secret") - addr := priv.PubKey().Address() - - app.accountKeeper.AddCoins(app.deliverState.ctx, addr, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) - require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr), "Balance did not update") - - msg := testBurnMsg{addr, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} - tx := GenTx(t.Name(), []sdk.Msg{msg, msg}, []int64{0}, []int64{0}, priv) - - res := app.Deliver(tx) - - require.Equal(t, true, res.IsOK(), res.Log) - require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr), "Double burn did not work") -} - -// tests multiples msgs of same type from different addresses in single tx -func TestBurnMultipleOwners(t *testing.T) { - // Create app. - app := newTestApp(t.Name()) - capKey := sdk.NewKVStoreKey("key") - app.MountStoresIAVL(capKey) - app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx auth.StdTx - fromJSON(txBytes, &tx) - return tx, nil - }) - - err := app.LoadLatestVersion(capKey) - if err != nil { - panic(err) - } - - app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{}) - app.accountKeeper = bank.NewKeeper(app.accountMapper) - - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{})) - - app.Router(). - AddRoute("burn", newHandleBurn(app.accountKeeper)). - AddRoute("send", newHandleSpend(app.accountKeeper)) - - app.InitChain(abci.RequestInitChain{}) - app.BeginBlock(abci.RequestBeginBlock{}) - - // Set chain-id - app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) - - priv1 := makePrivKey("my secret 1") - addr1 := priv1.PubKey().Address() - - priv2 := makePrivKey("my secret 2") - addr2 := priv2.PubKey().Address() - - // fund accounts - app.accountKeeper.AddCoins(app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) - app.accountKeeper.AddCoins(app.deliverState.ctx, addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) - - require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not update") - require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not update") - - msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}} - msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}}} - - // test wrong signers: Address 1 signs both messages - tx := GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 0}, []int64{0, 0}, priv1, priv1) - - res := app.Deliver(tx) - require.Equal(t, sdk.ABCICodeType(0x10003), res.Code, "Wrong signatures passed") - - require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 changed after invalid sig") - require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 changed after invalid sig") - - // test valid tx - tx = GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 1}, []int64{1, 0}, priv1, priv2) - - res = app.Deliver(tx) - require.Equal(t, true, res.IsOK(), res.Log) - - require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not change after valid tx") - require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not change after valid tx") -} - -// tests different msg types in single tx with different addresses -func TestSendBurn(t *testing.T) { - // Create app. - app := newTestApp(t.Name()) - capKey := sdk.NewKVStoreKey("key") - app.MountStoresIAVL(capKey) - app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx auth.StdTx - fromJSON(txBytes, &tx) - return tx, nil - }) - - err := app.LoadLatestVersion(capKey) - if err != nil { - panic(err) - } - - app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{}) - app.accountKeeper = bank.NewKeeper(app.accountMapper) - - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{})) - - app.Router(). - AddRoute("burn", newHandleBurn(app.accountKeeper)). - AddRoute("send", newHandleSpend(app.accountKeeper)) - - app.InitChain(abci.RequestInitChain{}) - app.BeginBlock(abci.RequestBeginBlock{}) - - // Set chain-id - app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) - - priv1 := makePrivKey("my secret 1") - addr1 := priv1.PubKey().Address() - - priv2 := makePrivKey("my secret 2") - addr2 := priv2.PubKey().Address() - - // fund accounts - app.accountKeeper.AddCoins(app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) - acc := app.accountMapper.NewAccountWithAddress(app.deliverState.ctx, addr2) - app.accountMapper.SetAccount(app.deliverState.ctx, acc) - - require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not update") - - sendMsg := testSendMsg{addr1, addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} - - msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} - msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} - - // send then burn - tx := GenTx(t.Name(), []sdk.Msg{sendMsg, msg2, msg1}, []int64{0, 1}, []int64{0, 0}, priv1, priv2) - - res := app.Deliver(tx) - require.Equal(t, true, res.IsOK(), res.Log) - - require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not change after valid tx") - require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not change after valid tx") - - // Check that state is only updated if all msgs in tx pass. - app.accountKeeper.AddCoins(app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}}) - - // burn then send - tx = GenTx(t.Name(), []sdk.Msg{msg1, sendMsg}, []int64{0}, []int64{1}, priv1) - - res = app.Deliver(tx) - - // Double check that state is correct after Commit. - app.EndBlock(abci.RequestEndBlock{}) - app.Commit() - - app.BeginBlock(abci.RequestBeginBlock{}) - app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) - - require.Equal(t, sdk.ABCICodeType(0x1000a), res.Code, "Allowed tx to pass with insufficient funds") - - require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(50)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Allowed valid msg to pass in invalid tx") - require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 changed after invalid tx") -} - -//---------------------------------------- - func randPower() int64 { return cmn.RandInt64() } diff --git a/baseapp/multimsg_test.go b/baseapp/multimsg_test.go new file mode 100644 index 0000000000..581da4b176 --- /dev/null +++ b/baseapp/multimsg_test.go @@ -0,0 +1,352 @@ +package baseapp + +import ( + "encoding/json" + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" +) + +// tests multiple msgs of same type from same address in single tx +func TestMultipleBurn(t *testing.T) { + // Create app. + app := newTestApp(t.Name()) + capKey := sdk.NewKVStoreKey("key") + app.MountStoresIAVL(capKey) + app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx auth.StdTx + fromJSON(txBytes, &tx) + return tx, nil + }) + + err := app.LoadLatestVersion(capKey) + if err != nil { + panic(err) + } + + app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{}) + + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{})) + + app.Router(). + AddRoute("burn", newHandleBurn(app.accountMapper)). + AddRoute("send", newHandleSpend(app.accountMapper)) + + app.InitChain(abci.RequestInitChain{}) + app.BeginBlock(abci.RequestBeginBlock{}) + + // Set chain-id + app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) + + priv := makePrivKey("my secret") + addr := priv.PubKey().Address() + + addCoins(app.accountMapper, app.deliverState.ctx, addr, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) + + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountMapper.GetAccount(app.deliverState.ctx, addr).GetCoins(), "Balance did not update") + + msg := testBurnMsg{addr, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} + tx := GenTx(t.Name(), []sdk.Msg{msg, msg}, []int64{0}, []int64{0}, priv) + + res := app.Deliver(tx) + + require.Equal(t, true, res.IsOK(), res.Log) + require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr), "Double burn did not work") +} + +// tests multiples msgs of same type from different addresses in single tx +func TestBurnMultipleOwners(t *testing.T) { + // Create app. + app := newTestApp(t.Name()) + capKey := sdk.NewKVStoreKey("key") + app.MountStoresIAVL(capKey) + app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx auth.StdTx + fromJSON(txBytes, &tx) + return tx, nil + }) + + err := app.LoadLatestVersion(capKey) + if err != nil { + panic(err) + } + + app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{}) + + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{})) + + app.Router(). + AddRoute("burn", newHandleBurn(app.accountMapper)). + AddRoute("send", newHandleSpend(app.accountMapper)) + + app.InitChain(abci.RequestInitChain{}) + app.BeginBlock(abci.RequestBeginBlock{}) + + // Set chain-id + app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) + + priv1 := makePrivKey("my secret 1") + addr1 := priv1.PubKey().Address() + + priv2 := makePrivKey("my secret 2") + addr2 := priv2.PubKey().Address() + + // fund accounts + addCoins(app.accountMapper, app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) + addCoins(app.accountMapper, app.deliverState.ctx, addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) + + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 did not update") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 did not update") + + msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}} + msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}}} + + // test wrong signers: Address 1 signs both messages + tx := GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 0}, []int64{0, 0}, priv1, priv1) + + res := app.Deliver(tx) + require.Equal(t, sdk.ABCICodeType(0x10003), res.Code, "Wrong signatures passed") + + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 changed after invalid sig") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 changed after invalid sig") + + // test valid tx + tx = GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 1}, []int64{1, 0}, priv1, priv2) + + res = app.Deliver(tx) + require.Equal(t, true, res.IsOK(), res.Log) + + require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 did not change after valid tx") + require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 did not change after valid tx") +} + +func getCoins(am auth.AccountMapper, ctx sdk.Context, addr sdk.Address) sdk.Coins { + return am.GetAccount(ctx, addr).GetCoins() +} + +func addCoins(am auth.AccountMapper, ctx sdk.Context, addr sdk.Address, coins sdk.Coins) sdk.Error { + acc := am.GetAccount(ctx, addr) + if acc == nil { + acc = am.NewAccountWithAddress(ctx, addr) + } + err := acc.SetCoins(acc.GetCoins().Plus(coins)) + if err != nil { + fmt.Println(err) + return sdk.ErrInternal(err.Error()) + } + am.SetAccount(ctx, acc) + return nil +} + +// tests different msg types in single tx with different addresses +func TestSendBurn(t *testing.T) { + // Create app. + app := newTestApp(t.Name()) + capKey := sdk.NewKVStoreKey("key") + app.MountStoresIAVL(capKey) + app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx auth.StdTx + fromJSON(txBytes, &tx) + return tx, nil + }) + + err := app.LoadLatestVersion(capKey) + if err != nil { + panic(err) + } + + app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{}) + + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{})) + + app.Router(). + AddRoute("burn", newHandleBurn(app.accountMapper)). + AddRoute("send", newHandleSpend(app.accountMapper)) + + app.InitChain(abci.RequestInitChain{}) + app.BeginBlock(abci.RequestBeginBlock{}) + + // Set chain-id + app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) + + priv1 := makePrivKey("my secret 1") + addr1 := priv1.PubKey().Address() + + priv2 := makePrivKey("my secret 2") + addr2 := priv2.PubKey().Address() + + // fund accounts + addCoins(app.accountMapper, app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) + acc := app.accountMapper.NewAccountWithAddress(app.deliverState.ctx, addr2) + app.accountMapper.SetAccount(app.deliverState.ctx, acc) + + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 did not update") + + sendMsg := testSendMsg{addr1, addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} + + msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} + msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} + + // send then burn + tx := GenTx(t.Name(), []sdk.Msg{sendMsg, msg2, msg1}, []int64{0, 1}, []int64{0, 0}, priv1, priv2) + + res := app.Deliver(tx) + require.Equal(t, true, res.IsOK(), res.Log) + + require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 did not change after valid tx") + require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 did not change after valid tx") + + // Check that state is only updated if all msgs in tx pass. + addCoins(app.accountMapper, app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}}) + + // burn then send, with fee thats greater than individual tx, but less than combination + tx = GenTxWithFeeAmt(50000, t.Name(), []sdk.Msg{msg1, sendMsg}, []int64{0}, []int64{1}, priv1) + + res = app.Deliver(tx) + require.Equal(t, sdk.ABCICodeType(0x1000c), res.Code, "Allowed tx to pass with insufficient funds") + + // Double check that state is correct after Commit. + app.EndBlock(abci.RequestEndBlock{}) + app.Commit() + + app.BeginBlock(abci.RequestBeginBlock{}) + app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) + + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(50)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Allowed valid msg to pass in invalid tx") + require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 changed after invalid tx") +} + +// Use burn and send msg types to test multiple msgs in one tx +type testBurnMsg struct { + Addr sdk.Address + Amount sdk.Coins +} + +const msgType3 = "burn" + +func (msg testBurnMsg) Type() string { return msgType3 } +func (msg testBurnMsg) GetSignBytes() []byte { + bz, _ := json.Marshal(msg) + return sdk.MustSortJSON(bz) +} +func (msg testBurnMsg) ValidateBasic() sdk.Error { + if msg.Addr == nil { + return sdk.ErrInvalidAddress("Cannot use nil as Address") + } + return nil +} +func (msg testBurnMsg) GetSigners() []sdk.Address { + return []sdk.Address{msg.Addr} +} + +type testSendMsg struct { + Sender sdk.Address + Receiver sdk.Address + Amount sdk.Coins +} + +const msgType4 = "send" + +func (msg testSendMsg) Type() string { return msgType4 } +func (msg testSendMsg) GetSignBytes() []byte { + bz, _ := json.Marshal(msg) + return sdk.MustSortJSON(bz) +} +func (msg testSendMsg) ValidateBasic() sdk.Error { + if msg.Sender == nil || msg.Receiver == nil { + return sdk.ErrInvalidAddress("Cannot use nil as Address") + } + return nil +} +func (msg testSendMsg) GetSigners() []sdk.Address { + return []sdk.Address{msg.Sender} +} + +// Simple Handlers for burn and send + +func newHandleBurn(am auth.AccountMapper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + ctx.GasMeter().ConsumeGas(20000, "burning coins") + burnMsg := msg.(testBurnMsg) + err := addCoins(am, ctx, burnMsg.Addr, burnMsg.Amount.Negative()) + if err != nil { + return err.Result() + } + return sdk.Result{} + } +} + +func newHandleSpend(am auth.AccountMapper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + ctx.GasMeter().ConsumeGas(40000, "spending coins") + spendMsg := msg.(testSendMsg) + err := addCoins(am, ctx, spendMsg.Sender, spendMsg.Amount.Negative()) + if err != nil { + return err.Result() + } + + err = addCoins(am, ctx, spendMsg.Receiver, spendMsg.Amount) + if err != nil { + return err.Result() + } + return sdk.Result{} + } +} + +// generate a signed transaction +func GenTx(chainID string, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx { + return GenTxWithFeeAmt(100000, chainID, msgs, accnums, seq, priv...) +} + +// generate a signed transaction with the given fee amount +func GenTxWithFeeAmt(feeAmt int64, chainID string, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx { + // make the transaction free + fee := auth.StdFee{ + sdk.Coins{{"foocoin", sdk.NewInt(0)}}, + feeAmt, + } + + sigs := make([]auth.StdSignature, len(priv)) + for i, p := range priv { + sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, "")) + // TODO: replace with proper error handling: + if err != nil { + panic(err) + } + sigs[i] = auth.StdSignature{ + PubKey: p.PubKey(), + Signature: sig, + AccountNumber: accnums[i], + Sequence: seq[i], + } + } + return auth.NewStdTx(msgs, fee, sigs, "") +} + +// spin up simple app for testing +type testApp struct { + *BaseApp + accountMapper auth.AccountMapper +} + +func newTestApp(name string) testApp { + return testApp{ + BaseApp: newBaseApp(name), + } +} + +func MakeCodec() *wire.Codec { + cdc := wire.NewCodec() + cdc.RegisterInterface((*sdk.Msg)(nil), nil) + crypto.RegisterAmino(cdc) + cdc.RegisterInterface((*auth.Account)(nil), nil) + cdc.RegisterConcrete(&auth.BaseAccount{}, "cosmos-sdk/BaseAccount", nil) + cdc.Seal() + return cdc +} diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 425e9aa2d9..a89806d123 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -5,6 +5,8 @@ import ( "github.com/stretchr/testify/require" + "math/rand" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/mock" @@ -81,17 +83,19 @@ func getMockApp(t *testing.T) *mock.App { return mapp } -// getBenchmarkMockApp initializes a mock application for this module, for purposes of benchmarking -// Any long term API support commitments do not apply to this function. -func getBenchmarkMockApp() (*mock.App, error) { - mapp := mock.NewApp() +func TestBankWithRandomMessages(t *testing.T) { + mapp := getMockApp(t) + setup := func(r *rand.Rand, keys []crypto.PrivKey) { + return + } - RegisterWire(mapp.Cdc) - coinKeeper := NewKeeper(mapp.AccountMapper) - mapp.Router().AddRoute("bank", NewHandler(coinKeeper)) - - err := mapp.CompleteSetup([]*sdk.KVStoreKey{}) - return mapp, err + mapp.RandomizedTesting( + t, + []mock.TestAndRunTx{TestAndRunSingleInputMsgSend}, + []mock.RandSetup{setup}, + []mock.Invariant{ModuleInvariants}, + 100, 30, 30, + ) } func TestMsgSendWithAccounts(t *testing.T) { diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index be8319f9fd..b90d569551 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -10,6 +10,19 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) +// getBenchmarkMockApp initializes a mock application for this module, for purposes of benchmarking +// Any long term API support commitments do not apply to this function. +func getBenchmarkMockApp() (*mock.App, error) { + mapp := mock.NewApp() + + RegisterWire(mapp.Cdc) + coinKeeper := NewKeeper(mapp.AccountMapper) + mapp.Router().AddRoute("bank", NewHandler(coinKeeper)) + + err := mapp.CompleteSetup([]*sdk.KVStoreKey{}) + return mapp, err +} + func BenchmarkOneBankSendTxPerBlock(b *testing.B) { benchmarkApp, _ := getBenchmarkMockApp() diff --git a/x/bank/test_helpers.go b/x/bank/test_helpers.go new file mode 100644 index 0000000000..ecaae62817 --- /dev/null +++ b/x/bank/test_helpers.go @@ -0,0 +1,150 @@ +package bank + +import ( + "errors" + "fmt" + "math/big" + "math/rand" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/mock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" +) + +// ModuleInvariants runs all invariants of the bank module. +// Currently runs non-negative balance invariant and TotalCoinsInvariant +func ModuleInvariants(t *testing.T, app *mock.App, log string) { + NonnegativeBalanceInvariant(t, app, log) + TotalCoinsInvariant(t, app, log) +} + +// NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances +func NonnegativeBalanceInvariant(t *testing.T, app *mock.App, log string) { + ctx := app.NewContext(false, abci.Header{}) + accts := mock.GetAllAccounts(app.AccountMapper, ctx) + for _, acc := range accts { + coins := acc.GetCoins() + assert.True(t, coins.IsNotNegative(), + fmt.Sprintf("%s has a negative denomination of %s\n%s", + acc.GetAddress().String(), + coins.String(), + log), + ) + } +} + +// TotalCoinsInvariant checks that the sum of the coins across all accounts +// is what is expected +func TotalCoinsInvariant(t *testing.T, app *mock.App, log string) { + ctx := app.BaseApp.NewContext(false, abci.Header{}) + totalCoins := sdk.Coins{} + + chkAccount := func(acc auth.Account) bool { + coins := acc.GetCoins() + totalCoins = totalCoins.Plus(coins) + return false + } + + app.AccountMapper.IterateAccounts(ctx, chkAccount) + require.Equal(t, app.TotalCoinsSupply, totalCoins, log) +} + +// TestAndRunSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both +// accounts already exist. +func TestAndRunSingleInputMsgSend(t *testing.T, r *rand.Rand, app *mock.App, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) { + fromKey := keys[r.Intn(len(keys))] + fromAddr := fromKey.PubKey().Address() + toKey := keys[r.Intn(len(keys))] + // Disallow sending money to yourself + for { + if !fromKey.Equals(toKey) { + break + } + toKey = keys[r.Intn(len(keys))] + } + toAddr := toKey.PubKey().Address() + initFromCoins := app.AccountMapper.GetAccount(ctx, fromAddr).GetCoins() + + denomIndex := r.Intn(len(initFromCoins)) + amt, goErr := randPositiveInt(r, initFromCoins[denomIndex].Amount) + if goErr != nil { + return "skipping bank send due to account having no coins of denomination " + initFromCoins[denomIndex].Denom, nil + } + + action = fmt.Sprintf("%s is sending %s %s to %s", + fromAddr.String(), + amt.String(), + initFromCoins[denomIndex].Denom, + toAddr.String(), + ) + log = fmt.Sprintf("%s\n%s", log, action) + + coins := sdk.Coins{{initFromCoins[denomIndex].Denom, amt}} + var msg = MsgSend{ + Inputs: []Input{NewInput(fromAddr, coins)}, + Outputs: []Output{NewOutput(toAddr, coins)}, + } + sendAndVerifyMsgSend(t, app, msg, ctx, log, []crypto.PrivKey{fromKey}) + + return action, nil +} + +// Sends and verifies the transition of a msg send. This fails if there are repeated inputs or outputs +func sendAndVerifyMsgSend(t *testing.T, app *mock.App, msg MsgSend, ctx sdk.Context, log string, privkeys []crypto.PrivKey) { + initialInputAddrCoins := make([]sdk.Coins, len(msg.Inputs)) + initialOutputAddrCoins := make([]sdk.Coins, len(msg.Outputs)) + AccountNumbers := make([]int64, len(msg.Inputs)) + SequenceNumbers := make([]int64, len(msg.Inputs)) + + for i := 0; i < len(msg.Inputs); i++ { + acc := app.AccountMapper.GetAccount(ctx, msg.Inputs[i].Address) + AccountNumbers[i] = acc.GetAccountNumber() + SequenceNumbers[i] = acc.GetSequence() + initialInputAddrCoins[i] = acc.GetCoins() + } + for i := 0; i < len(msg.Outputs); i++ { + acc := app.AccountMapper.GetAccount(ctx, msg.Outputs[i].Address) + initialOutputAddrCoins[i] = acc.GetCoins() + } + tx := mock.GenTx([]sdk.Msg{msg}, + AccountNumbers, + SequenceNumbers, + privkeys...) + res := app.Deliver(tx) + if !res.IsOK() { + // TODO: Do this in a more 'canonical' way + fmt.Println(res) + fmt.Println(log) + t.FailNow() + } + + for i := 0; i < len(msg.Inputs); i++ { + terminalInputCoins := app.AccountMapper.GetAccount(ctx, msg.Inputs[i].Address).GetCoins() + require.Equal(t, + initialInputAddrCoins[i].Minus(msg.Inputs[i].Coins), + terminalInputCoins, + fmt.Sprintf("Input #%d had an incorrect amount of coins\n%s", i, log), + ) + } + for i := 0; i < len(msg.Outputs); i++ { + terminalOutputCoins := app.AccountMapper.GetAccount(ctx, msg.Outputs[i].Address).GetCoins() + require.Equal(t, + initialOutputAddrCoins[i].Plus(msg.Outputs[i].Coins), + terminalOutputCoins, + fmt.Sprintf("Output #%d had an incorrect amount of coins\n%s", i, log), + ) + } +} + +func randPositiveInt(r *rand.Rand, max sdk.Int) (sdk.Int, error) { + if !max.GT(sdk.OneInt()) { + return sdk.Int{}, errors.New("max too small") + } + max = max.Sub(sdk.OneInt()) + return sdk.NewIntFromBigInt(new(big.Int).Rand(r, max.BigInt())).Add(sdk.OneInt()), nil +} diff --git a/x/mock/app.go b/x/mock/app.go index e16a322688..dd8edb102f 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -1,6 +1,7 @@ package mock import ( + "math/rand" "os" bam "github.com/cosmos/cosmos-sdk/baseapp" @@ -15,7 +16,9 @@ import ( const chainID = "" -// App extends an ABCI application. +// App extends an ABCI application, but with most of its parameters exported. +// They are exported for convenience in creating helper functions, as object +// capabilities aren't needed for testing. type App struct { *bam.BaseApp Cdc *wire.Codec // Cdc is public since the codec is passed into the module anyways @@ -26,7 +29,8 @@ type App struct { AccountMapper auth.AccountMapper FeeCollectionKeeper auth.FeeCollectionKeeper - GenesisAccounts []auth.Account + GenesisAccounts []auth.Account + TotalCoinsSupply sdk.Coins } // NewApp partially constructs a new app on the memstore for module and genesis @@ -43,10 +47,11 @@ func NewApp() *App { // Create your application object app := &App{ - BaseApp: bam.NewBaseApp("mock", cdc, logger, db), - Cdc: cdc, - KeyMain: sdk.NewKVStoreKey("main"), - KeyAccount: sdk.NewKVStoreKey("acc"), + BaseApp: bam.NewBaseApp("mock", cdc, logger, db), + Cdc: cdc, + KeyMain: sdk.NewKVStoreKey("main"), + KeyAccount: sdk.NewKVStoreKey("acc"), + TotalCoinsSupply: sdk.Coins{}, } // Define the accountMapper @@ -124,8 +129,8 @@ func SetGenesis(app *App, accs []auth.Account) { func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx { // Make the transaction free fee := auth.StdFee{ - sdk.Coins{sdk.NewCoin("foocoin", 0)}, - 100000, + Amount: sdk.Coins{sdk.NewCoin("foocoin", 0)}, + Gas: 100000, } sigs := make([]auth.StdSignature, len(priv)) @@ -148,6 +153,70 @@ func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) return auth.NewStdTx(msgs, fee, sigs, memo) } +// GeneratePrivKeys generates a total n Ed25519 private keys. +func GeneratePrivKeys(n int) (keys []crypto.PrivKey) { + // TODO: Randomize this between ed25519 and secp256k1 + keys = make([]crypto.PrivKey, n, n) + for i := 0; i < n; i++ { + keys[i] = crypto.GenPrivKeyEd25519() + } + + return +} + +// GeneratePrivKeyAddressPairs generates a total of n private key, address +// pairs. +func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.Address) { + keys = make([]crypto.PrivKey, n, n) + addrs = make([]sdk.Address, n, n) + for i := 0; i < n; i++ { + keys[i] = crypto.GenPrivKeyEd25519() + addrs[i] = keys[i].PubKey().Address() + } + return +} + +// RandomSetGenesis set genesis accounts with random coin values using the +// provided addresses and coin denominations. +func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.Address, denoms []string) { + accts := make([]auth.Account, len(addrs), len(addrs)) + randCoinIntervals := []BigInterval{ + {sdk.NewIntWithDecimal(1, 0), sdk.NewIntWithDecimal(1, 1)}, + {sdk.NewIntWithDecimal(1, 2), sdk.NewIntWithDecimal(1, 3)}, + {sdk.NewIntWithDecimal(1, 40), sdk.NewIntWithDecimal(1, 50)}, + } + + for i := 0; i < len(accts); i++ { + coins := make([]sdk.Coin, len(denoms), len(denoms)) + + // generate a random coin for each denomination + for j := 0; j < len(denoms); j++ { + coins[j] = sdk.Coin{Denom: denoms[j], + Amount: RandFromBigInterval(r, randCoinIntervals), + } + } + + app.TotalCoinsSupply = app.TotalCoinsSupply.Plus(coins) + baseAcc := auth.NewBaseAccountWithAddress(addrs[i]) + + (&baseAcc).SetCoins(coins) + accts[i] = &baseAcc + } + + SetGenesis(app, accts) +} + +// GetAllAccounts returns all accounts in the accountMapper. +func GetAllAccounts(mapper auth.AccountMapper, ctx sdk.Context) []auth.Account { + accounts := []auth.Account{} + appendAccount := func(acc auth.Account) (stop bool) { + accounts = append(accounts, acc) + return false + } + mapper.IterateAccounts(ctx, appendAccount) + return accounts +} + // GenSequenceOfTxs generates a set of signed transactions of messages, such // that they differ only by having the sequence numbers incremented between // every transaction. diff --git a/x/mock/doc.go b/x/mock/doc.go new file mode 100644 index 0000000000..d23aac3936 --- /dev/null +++ b/x/mock/doc.go @@ -0,0 +1,15 @@ +/* +Package mock provides functions for creating applications for testing. + +This module also features randomized testing, so that various modules can test +that their operations are interoperable. + +The intended method of using this randomized testing framework is that every +module provides TestAndRunTx methods for each of its desired methods of fuzzing +its own txs, and it also provides the invariants that it assumes to be true. +You then pick and choose from these tx types and invariants. To pick and choose +these, you first build a mock app with the correct keepers. Then you call the +app.RandomizedTesting method with the set of desired txs, invariants, along +with the setups each module requires. +*/ +package mock diff --git a/x/mock/random_simulate_blocks.go b/x/mock/random_simulate_blocks.go new file mode 100644 index 0000000000..a37913065d --- /dev/null +++ b/x/mock/random_simulate_blocks.go @@ -0,0 +1,95 @@ +package mock + +import ( + "fmt" + "math/big" + "math/rand" + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" +) + +// RandomizedTesting tests application by sending random messages. +func (app *App) RandomizedTesting( + t *testing.T, ops []TestAndRunTx, setups []RandSetup, + invariants []Invariant, numKeys int, numBlocks int, blockSize int, +) { + time := time.Now().UnixNano() + app.RandomizedTestingFromSeed(t, time, ops, setups, invariants, numKeys, numBlocks, blockSize) +} + +// RandomizedTestingFromSeed tests an application by running the provided +// operations, testing the provided invariants, but using the provided seed. +func (app *App) RandomizedTestingFromSeed( + t *testing.T, seed int64, ops []TestAndRunTx, setups []RandSetup, + invariants []Invariant, numKeys int, numBlocks int, blockSize int, +) { + log := fmt.Sprintf("Starting SingleModuleTest with randomness created with seed %d", int(seed)) + keys, addrs := GeneratePrivKeyAddressPairs(numKeys) + r := rand.New(rand.NewSource(seed)) + + for i := 0; i < len(setups); i++ { + setups[i](r, keys) + } + + RandomSetGenesis(r, app, addrs, []string{"foocoin"}) + header := abci.Header{Height: 0} + + for i := 0; i < numBlocks; i++ { + app.BeginBlock(abci.RequestBeginBlock{}) + + // Make sure invariants hold at beginning of block and when nothing was + // done. + app.assertAllInvariants(t, invariants, log) + + ctx := app.NewContext(false, header) + + // TODO: Add modes to simulate "no load", "medium load", and + // "high load" blocks. + for j := 0; j < blockSize; j++ { + logUpdate, err := ops[r.Intn(len(ops))](t, r, app, ctx, keys, log) + log += "\n" + logUpdate + + require.Nil(t, err, log) + app.assertAllInvariants(t, invariants, log) + } + + app.EndBlock(abci.RequestEndBlock{}) + header.Height++ + } +} + +func (app *App) assertAllInvariants(t *testing.T, tests []Invariant, log string) { + for i := 0; i < len(tests); i++ { + tests[i](t, app, log) + } +} + +// BigInterval is a representation of the interval [lo, hi), where +// lo and hi are both of type sdk.Int +type BigInterval struct { + lo sdk.Int + hi sdk.Int +} + +// RandFromBigInterval chooses an interval uniformly from the provided list of +// BigIntervals, and then chooses an element from an interval uniformly at random. +func RandFromBigInterval(r *rand.Rand, intervals []BigInterval) sdk.Int { + if len(intervals) == 0 { + return sdk.ZeroInt() + } + + interval := intervals[r.Intn(len(intervals))] + + lo := interval.lo + hi := interval.hi + + diff := hi.Sub(lo) + result := sdk.NewIntFromBigInt(new(big.Int).Rand(r, diff.BigInt())) + result = result.Add(lo) + + return result +} diff --git a/x/mock/types.go b/x/mock/types.go new file mode 100644 index 0000000000..50957e1c46 --- /dev/null +++ b/x/mock/types.go @@ -0,0 +1,38 @@ +package mock + +import ( + "math/rand" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/crypto" +) + +type ( + // TestAndRunTx produces a fuzzed transaction, and ensures the state + // transition was as expected. It returns a descriptive message "action" + // about what this fuzzed tx actually did, for ease of debugging. + TestAndRunTx func( + t *testing.T, r *rand.Rand, app *App, ctx sdk.Context, + privKeys []crypto.PrivKey, log string, + ) (action string, err sdk.Error) + + // RandSetup performs the random setup the mock module needs. + RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey) + + // An Invariant is a function which tests a particular invariant. + // If the invariant has been broken, the function should halt the + // test and output the log. + Invariant func(t *testing.T, app *App, log string) +) + +// PeriodicInvariant returns an Invariant function closure that asserts +// a given invariant if the mock application's last block modulo the given +// period is congruent to the given offset. +func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant { + return func(t *testing.T, app *App, log string) { + if int(app.LastBlockHeight())%period == offset { + invariant(t, app, log) + } + } +} From 723e057d955e23852b4b3ea8a1cc5da3e72bb227 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sat, 7 Jul 2018 00:00:00 +0200 Subject: [PATCH 53/53] Merge pull request #1566: Fix validator power decrease bug * Demonstrative testcase * Update when decreasing but still bonded * Only update when decreasing, not when equal * Cleanup conditional; changelog * Clarify comments * Simplify conditional --- CHANGELOG.md | 1 + x/stake/keeper/validator.go | 7 ++++++ x/stake/keeper/validator_test.go | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7012336d94..4808b6db84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -97,6 +97,7 @@ IMPROVEMENTS BUG FIXES * [x/slashing] \#1510 Unrevoked validators cannot un-revoke themselves +* [x/stake] \#1567 Validators decreased in power but not unbonded are now updated in Tendermint * [gaia] Added self delegation for validators in the genesis creation * [lcd] tests now don't depend on raw json text * [stake] error strings lower case diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 164c500492..c32b536cea 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -261,6 +261,13 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type if updatedVal.Owner != nil { // updates to validator occurred to be updated validator = updatedVal } + // if decreased in power but still bonded, update Tendermint validator + // (if updatedVal is set, the validator has changed bonding status) + stillBonded := oldFound && oldValidator.Status() == sdk.Bonded && updatedVal.Owner == nil + if stillBonded && oldValidator.PoolShares.Bonded().GT(validator.PoolShares.Bonded()) { + bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) + store.Set(GetTendermintUpdatesKey(ownerAddr), bz) + } return validator } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index c4d197a36b..9ad6e12bc0 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -674,3 +674,43 @@ func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) { require.Equal(t, validators[0].ABCIValidatorZero(), updates[0]) require.Equal(t, validators[2].ABCIValidator(), updates[1]) } + +func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { + ctx, _, keeper := CreateTestInput(t, false, 1000) + + amts := []int64{100, 100} + var validators [2]types.Validator + for i, amt := range amts { + pool := keeper.GetPool(ctx) + validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt) + keeper.SetPool(ctx, pool) + } + validators[0] = keeper.UpdateValidator(ctx, validators[0]) + validators[1] = keeper.UpdateValidator(ctx, validators[1]) + keeper.ClearTendermintUpdates(ctx) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + + // check initial power + require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[1].GetPower().RoundInt64()) + + // test multiple value change + // tendermintUpdate set: {c1, c3} -> {c1', c3'} + pool := keeper.GetPool(ctx) + validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewRat(20)) + validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewRat(30)) + keeper.SetPool(ctx, pool) + validators[0] = keeper.UpdateValidator(ctx, validators[0]) + validators[1] = keeper.UpdateValidator(ctx, validators[1]) + + // power has changed + require.Equal(t, sdk.NewRat(80).RoundInt64(), validators[0].GetPower().RoundInt64()) + require.Equal(t, sdk.NewRat(70).RoundInt64(), validators[1].GetPower().RoundInt64()) + + // Tendermint updates should reflect power change + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 2, len(updates)) + require.Equal(t, validators[0].ABCIValidator(), updates[0]) + require.Equal(t, validators[1].ABCIValidator(), updates[1]) +}