From d195cc15ed50e798d8e2b6a8c3d8711ff456f8be Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Thu, 13 Sep 2018 23:23:44 +0200 Subject: [PATCH] Merge PR #2249: Staking Querier pt1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Cherry picked commits from prev branch * Added new keepers for querier functionalities * Renaming * Fixed gov errors and messages * Added Querier to stake and app * Update delegation keepers * REST Queriers not working * Fix marshalling error * Querier tests working * Pool and params working * sdk.NewCoin for test handler * Refactor and renaming * Update LCD queries and added more tests for queriers * use sdk.NewCoin * Delegator summary query and tests * Added more tests for keeper * Update PENDING.md * Update stake rest query * Format and replaced panics for sdk.Error * Refactor and addressed comments from Sunny and Aleks * Fixed some of the errors produced by addr type change * Fixed remaining errors * Updated and fixed lite tests * JSON Header and consistency on errors * Increased cov for genesis * Added comment for maxRetrieve param in keepers * Comment on DelegationWithoutDec * Bech32Validator Keepers * Changed Bech validator * Updated remaining tests and bech32 validator * Addressed most of Rigel's comments * Updated tests and types * Make codec to be unexported from keeper * Moved logic to query_utils and updated tests * Fix linter err and PENDING * Fix err * Fix err * Fixed tests * Update PENDING description * Update UpdateBondedValidatorsFull * Update iterator * defer iterator.Close() * delete comment * Address some of Aleks comments, need to fix tests * export querier * Fixed tests * Address Rigel's comments * More tests * return error for GetDelegatorValidator * Fixed conflicts * Fix linter warnings * Address @rigelrozanski comments * Delete comments * wire ––> codec --- Gopkg.lock | 42 +-- Makefile | 4 +- PENDING.md | 3 +- client/lcd/lcd_test.go | 46 +-- client/utils/utils.go | 1 + cmd/gaia/app/app.go | 3 +- x/auth/client/rest/sign.go | 1 + x/stake/app_test.go | 4 +- x/stake/client/rest/query.go | 486 +++++++++++------------------- x/stake/client/rest/utils.go | 144 --------- x/stake/genesis_test.go | 6 + x/stake/handler_test.go | 6 +- x/stake/keeper/delegation.go | 122 +++++--- x/stake/keeper/delegation_test.go | 84 +++++- x/stake/keeper/query_utils.go | 101 +++++++ x/stake/keeper/validator.go | 62 ++-- x/stake/keeper/validator_test.go | 18 +- x/stake/querier/queryable.go | 227 ++++++++++++++ x/stake/querier/queryable_test.go | 215 +++++++++++++ x/stake/stake.go | 7 + x/stake/types/delegation.go | 7 + 21 files changed, 968 insertions(+), 621 deletions(-) create mode 100644 x/stake/keeper/query_utils.go create mode 100644 x/stake/querier/queryable.go create mode 100644 x/stake/querier/queryable_test.go diff --git a/Gopkg.lock b/Gopkg.lock index d5ccc6589..a3aab3a86 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -34,7 +34,7 @@ [[projects]] branch = "master" - digest = "1:6aabc1566d6351115d561d038da82a4c19b46c3b6e17f4a0a2fa60260663dc79" + digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8" name = "github.com/btcsuite/btcd" packages = ["btcec"] pruneopts = "UT" @@ -71,7 +71,7 @@ version = "v1.4.7" [[projects]] - digest = "1:fa30c0652956e159cdb97dcb2ef8b8db63ed668c02a5c3a40961c8f0641252fe" + digest = "1:fdf5169073fb0ad6dc12a70c249145e30f4058647bea25f0abd48b6d9f228a11" name = "github.com/go-kit/kit" packages = [ "log", @@ -103,7 +103,7 @@ version = "v1.7.0" [[projects]] - digest = "1:212285efb97b9ec2e20550d81f0446cb7897e57cbdfd7301b1363ab113d8be45" + digest = "1:35621fe20f140f05a0c4ef662c26c0ab4ee50bca78aa30fe87d33120bd28165e" name = "github.com/gogo/protobuf" packages = [ "gogoproto", @@ -118,7 +118,7 @@ version = "v1.1.1" [[projects]] - digest = "1:cb22af0ed7c72d495d8be1106233ee553898950f15fd3f5404406d44c2e86888" + digest = "1:17fe264ee908afc795734e8c4e63db2accabaf57326dbf21763a7d6b86096260" name = "github.com/golang/protobuf" packages = [ "proto", @@ -165,7 +165,7 @@ [[projects]] branch = "master" - digest = "1:8951fe6e358876736d8fa1f3992624fdbb2dec6bc49401c1381d1ef8abbb544f" + digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240" name = "github.com/hashicorp/hcl" packages = [ ".", @@ -262,7 +262,7 @@ version = "v1.0.0" [[projects]] - digest = "1:98225904b7abff96c052b669b25788f18225a36673fba022fb93514bb9a2a64e" + digest = "1:c1a04665f9613e082e1209cf288bf64f4068dcd6c87a64bf1c4ff006ad422ba0" name = "github.com/prometheus/client_golang" packages = [ "prometheus", @@ -273,7 +273,7 @@ [[projects]] branch = "master" - digest = "1:0f37e09b3e92aaeda5991581311f8dbf38944b36a3edec61cc2d1991f527554a" + digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4" name = "github.com/prometheus/client_model" packages = ["go"] pruneopts = "UT" @@ -281,7 +281,7 @@ [[projects]] branch = "master" - digest = "1:dad2e5a2153ee7a6c9ab8fc13673a16ee4fb64434a7da980965a3741b0c981a3" + digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5" name = "github.com/prometheus/common" packages = [ "expfmt", @@ -293,7 +293,7 @@ [[projects]] branch = "master" - digest = "1:a37c98f4b7a66bb5c539c0539f0915a74ef1c8e0b3b6f45735289d94cae92bfd" + digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290" name = "github.com/prometheus/procfs" packages = [ ".", @@ -312,7 +312,7 @@ revision = "e2704e165165ec55d062f5919b4b29494e9fa790" [[projects]] - digest = "1:37ace7f35375adec11634126944bdc45a673415e2fcc07382d03b75ec76ea94c" + digest = "1:bd1ae00087d17c5a748660b8e89e1043e1e5479d0fea743352cda2f8dd8c4f84" name = "github.com/spf13/afero" packages = [ ".", @@ -331,7 +331,7 @@ version = "v1.2.0" [[projects]] - digest = "1:627ab2f549a6a55c44f46fa24a4307f4d0da81bfc7934ed0473bf38b24051d26" + digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e" name = "github.com/spf13/cobra" packages = ["."] pruneopts = "UT" @@ -363,7 +363,7 @@ version = "v1.0.0" [[projects]] - digest = "1:73697231b93fb74a73ebd8384b68b9a60c57ea6b13c56d2425414566a72c8e6d" + digest = "1:7e8d267900c7fa7f35129a2a37596e38ed0f11ca746d6d9ba727980ee138f9f6" name = "github.com/stretchr/testify" packages = [ "assert", @@ -375,7 +375,7 @@ [[projects]] branch = "master" - digest = "1:442d2ffa75ffae302ce8800bf4144696b92bef02917923ea132ce2d39efe7d65" + digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5" name = "github.com/syndtr/goleveldb" packages = [ "leveldb", @@ -396,7 +396,7 @@ [[projects]] branch = "master" - digest = "1:203b409c21115233a576f99e8f13d8e07ad82b25500491f7e1cca12588fb3232" + digest = "1:087aaa7920e5d0bf79586feb57ce01c35c830396ab4392798112e8aae8c47722" name = "github.com/tendermint/ed25519" packages = [ ".", @@ -423,7 +423,7 @@ version = "v0.11.0" [[projects]] - digest = "1:963f6c04345ce36f900c1d6367200eebc3cc2db6ee632ff865ea8dcf64b748a0" + digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6" name = "github.com/tendermint/tendermint" packages = [ "abci/client", @@ -490,7 +490,7 @@ version = "v0.23.1-rc0" [[projects]] - digest = "1:ad879bb8c71020a3f92f0c61f414d93eae1d5dc2f37023b6abaa3cc84b00165e" + digest = "1:bf6d9a827ea3cad964c2f863302e4f6823170d0b5ed16f72cf1184a7c615067e" name = "github.com/tendermint/tmlibs" packages = ["cli"] pruneopts = "UT" @@ -507,7 +507,7 @@ [[projects]] branch = "master" - digest = "1:2a3ce1f08dcae8bac666deb6e4c88b5d7170c510da38fd746231144cac351704" + digest = "1:27507554c6d4f060d8d700c31c624a43d3a92baa634e178ddc044bdf7d13b44a" name = "golang.org/x/crypto" packages = [ "blowfish", @@ -529,7 +529,7 @@ revision = "614d502a4dac94afa3a6ce146bd1736da82514c6" [[projects]] - digest = "1:04dda8391c3e2397daf254ac68003f30141c069b228d06baec8324a5f81dc1e9" + digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1" name = "golang.org/x/net" packages = [ "context", @@ -546,7 +546,7 @@ [[projects]] branch = "master" - digest = "1:9d9e5fc87553258c36ee18d38023587edd61e4b2521f4473da34b47a83a492e5" + digest = "1:ead82e3e398388679f3ad77633a087ac31a47a6be59ae20841e1d1b3a3fbbd22" name = "golang.org/x/sys" packages = [ "cpu", @@ -556,7 +556,7 @@ revision = "4ea2f632f6e912459fe60b26b1749377f0d889d5" [[projects]] - digest = "1:7509ba4347d1f8de6ae9be8818b0cd1abc3deeffe28aeaf4be6d4b6b5178d9ca" + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -587,7 +587,7 @@ revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4" [[projects]] - digest = "1:4515e3030c440845b046354fd5d57671238428b820deebce2e9dabb5cd3c51ac" + digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74" name = "google.golang.org/grpc" packages = [ ".", diff --git a/Makefile b/Makefile index a015e5a6b..a2c51b6df 100644 --- a/Makefile +++ b/Makefile @@ -160,8 +160,8 @@ test_sim_gaia_fast: @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=400 -SimulationBlockSize=200 -SimulationCommit=true -v -timeout 24h test_sim_gaia_slow: - @echo "Running full Gaia simulation. This may take awhile!" - @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationVerbose=true -SimulationCommit=true -v -timeout 24h + @echo "Running full Gaia simulation. This may take a while!" + @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationVerbose=true -SimulationCommit=true -v -timeout 24h SIM_NUM_BLOCKS ?= 210 SIM_BLOCK_SIZE ?= 200 diff --git a/PENDING.md b/PENDING.md index 6d6754dc5..f94d1653e 100644 --- a/PENDING.md +++ b/PENDING.md @@ -101,7 +101,7 @@ IMPROVEMENTS * [x/stake] Improve speed of GetValidator, which was shown to be a performance bottleneck. [#2046](https://github.com/tendermint/tendermint/pull/2200) * [genesis] \#2229 Ensure that there are no duplicate accounts or validators in the genesis state. * Add SDK validation to `config.toml` (namely disabling `create_empty_blocks`) \#1571 - + * SDK * [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present. * [spec] Added simple piggy bank distribution spec @@ -113,6 +113,7 @@ IMPROVEMENTS * [simulation] Add a concept of weighting the operations \#2303 * [simulation] Logs get written to file if large, and also get printed on panics \#2285 * [gaiad] \#1992 Add optional flag to `gaiad testnet` to make config directory of daemon (default `gaiad`) and cli (default `gaiacli`) configurable + * [x/stake] Add stake `Queriers` for Gaia-lite endpoints. This increases the staking endpoints performance by reusing the staking `keeper` logic for queries. [#2249](https://github.com/cosmos/cosmos-sdk/pull/2149) * Tendermint diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 312ac397b..3d51ca6db 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -30,7 +30,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" - "github.com/cosmos/cosmos-sdk/x/stake/client/rest" ) func init() { @@ -510,6 +509,7 @@ func TestBonding(t *testing.T) { cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}) defer cleanup() + amt := sdk.NewDec(60) validator1Operator := sdk.ValAddress(pks[0].Address()) validator := getValidator(t, port, validator1Operator) @@ -527,18 +527,18 @@ func TestBonding(t *testing.T) { // query validator bond := getDelegation(t, port, addr, validator1Operator) - require.Equal(t, "60.0000000000", bond.Shares) + require.Equal(t, amt, bond.Shares) summary := getDelegationSummary(t, port, addr) require.Len(t, summary.Delegations, 1, "Delegation summary holds all delegations") - require.Equal(t, "60.0000000000", summary.Delegations[0].Shares) + require.Equal(t, amt, summary.Delegations[0].Shares) require.Len(t, summary.UnbondingDelegations, 0, "Delegation summary holds all unbonding-delegations") bondedValidators := getDelegatorValidators(t, port, addr) require.Len(t, bondedValidators, 1) require.Equal(t, validator1Operator, bondedValidators[0].OperatorAddr) - require.Equal(t, validator.DelegatorShares.Add(sdk.NewDec(60)).String(), bondedValidators[0].DelegatorShares.String()) + require.Equal(t, validator.DelegatorShares.Add(amt).String(), bondedValidators[0].DelegatorShares.String()) bondedValidator := getDelegatorValidator(t, port, addr, validator1Operator) require.Equal(t, validator1Operator, bondedValidator.OperatorAddr) @@ -558,9 +558,8 @@ func TestBonding(t *testing.T) { coins = acc.GetCoins() require.Equal(t, int64(40), coins.AmountOf("steak").Int64()) - unbondings := getUndelegations(t, port, addr, validator1Operator) - require.Len(t, unbondings, 1, "Unbondings holds all unbonding-delegations") - require.Equal(t, "60", unbondings[0].Balance.Amount.String()) + unbonding := getUndelegation(t, port, addr, validator1Operator) + require.Equal(t, "60", unbonding.Balance.Amount.String()) summary = getDelegationSummary(t, port, addr) @@ -895,43 +894,43 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.ValidatorSigningInfo { res, body := Request(t, port, "GET", fmt.Sprintf("/slashing/signing_info/%s", validatorPubKey), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) + var signingInfo slashing.ValidatorSigningInfo err := cdc.UnmarshalJSON([]byte(body), &signingInfo) require.Nil(t, err) + return signingInfo } // ============= Stake Module ================ -func getDelegation(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) rest.DelegationWithoutRat { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delAddr, valAddr), nil) +func getDelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.Delegation { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var bond rest.DelegationWithoutRat - + var bond stake.Delegation err := cdc.UnmarshalJSON([]byte(body), &bond) require.Nil(t, err) return bond } -func getUndelegations(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) []stake.UnbondingDelegation { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delAddr, valAddr), nil) +func getUndelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.UnbondingDelegation { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var unbondings []stake.UnbondingDelegation - + var unbondings stake.UnbondingDelegation err := cdc.UnmarshalJSON([]byte(body), &unbondings) require.Nil(t, err) return unbondings } -func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) rest.DelegationSummary { +func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) stake.DelegationSummary { res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s", delegatorAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var summary rest.DelegationSummary + var summary stake.DelegationSummary err := cdc.UnmarshalJSON([]byte(body), &summary) require.Nil(t, err) @@ -970,8 +969,8 @@ func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddr return bondedValidators } -func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.Validator { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delAddr, valAddr), nil) +func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.Validator { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delegatorAddr, validatorAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var bondedValidator stake.Validator @@ -1097,18 +1096,22 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, func getValidators(t *testing.T, port string) []stake.Validator { res, body := Request(t, port, "GET", "/stake/validators", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) + var validators []stake.Validator err := cdc.UnmarshalJSON([]byte(body), &validators) require.Nil(t, err) + return validators } -func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.Validator { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", valAddr.String()), nil) +func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake.Validator { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", validatorAddr.String()), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) + var validator stake.Validator err := cdc.UnmarshalJSON([]byte(body), &validator) require.Nil(t, err) + return validator } @@ -1284,7 +1287,6 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ac } }`, proposerAddr, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), jsonStr) - fmt.Println(res) require.Equal(t, http.StatusOK, res.StatusCode, body) var results ctypes.ResultBroadcastTxCommit diff --git a/client/utils/utils.go b/client/utils/utils.go index 52472ba1e..81fd13859 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -133,6 +133,7 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, return txBldr.SignStdTx(name, passphrase, stdTx, appendSig) } +// nolint // SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value. func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (estimated, adjusted int64, err error) { txBytes, err := txBldr.BuildWithPubKey(name, msgs) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 627fb5987..da79a055a 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -109,7 +109,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio AddRoute("gov", gov.NewHandler(app.govKeeper)) app.QueryRouter(). - AddRoute("gov", gov.NewQuerier(app.govKeeper)) + AddRoute("gov", gov.NewQuerier(app.govKeeper)). + AddRoute("stake", stake.NewQuerier(app.stakeKeeper, app.cdc)) // initialize BaseApp app.SetInitChainer(app.initChainer) diff --git a/x/auth/client/rest/sign.go b/x/auth/client/rest/sign.go index 7ded69dc5..6894d1c5d 100644 --- a/x/auth/client/rest/sign.go +++ b/x/auth/client/rest/sign.go @@ -22,6 +22,7 @@ type SignBody struct { AppendSig bool `json:"append_sig"` } +// nolint: unparam // sign tx REST handler func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc { diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 6542fb196..922ce8ac3 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -20,9 +20,9 @@ var ( addr3 = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) priv4 = ed25519.GenPrivKey() addr4 = sdk.AccAddress(priv4.PubKey().Address()) - coins = sdk.Coins{{"foocoin", sdk.NewInt(10)}} + coins = sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(10))} fee = auth.StdFee{ - sdk.Coins{{"foocoin", sdk.NewInt(0)}}, + sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(0))}, 100000, } ) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index ca1d71b9a..c6e39ebd2 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -11,7 +11,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake/tags" - "github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/gorilla/mux" ) @@ -50,16 +49,16 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co delegationHandlerFn(cliCtx, cdc), ).Methods("GET") - // Query all unbonding_delegations between a delegator and a validator + // Query all unbonding delegations between a delegator and a validator r.HandleFunc( "/stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}", - unbondingDelegationsHandlerFn(cliCtx, cdc), + unbondingDelegationHandlerFn(cliCtx, cdc), ).Methods("GET") // Get all validators r.HandleFunc( "/stake/validators", - validatorsHandlerFn(cliCtx, cdc), + validatorsHandlerFn(cliCtx), ).Methods("GET") // Get a single validator info @@ -71,107 +70,53 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co // Get the current state of the staking pool r.HandleFunc( "/stake/pool", - poolHandlerFn(cliCtx, cdc), + poolHandlerFn(cliCtx), ).Methods("GET") // Get the current staking parameter values r.HandleFunc( "/stake/parameters", - paramsHandlerFn(cliCtx, cdc), + paramsHandlerFn(cliCtx), ).Methods("GET") } -// already resolve the rational shares to not handle this in the client - -// defines a delegation without type Rat for shares -type DelegationWithoutRat struct { - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorAddr sdk.ValAddress `json:"validator_addr"` - Shares string `json:"shares"` - Height int64 `json:"height"` -} - -// aggregation of all delegations, unbondings and redelegations -type DelegationSummary struct { - Delegations []DelegationWithoutRat `json:"delegations"` - UnbondingDelegations []stake.UnbondingDelegation `json:"unbonding_delegations"` - Redelegations []stake.Redelegation `json:"redelegations"` -} - // HTTP request handler to query a delegator delegations func delegatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var valAddr sdk.ValAddress - var delegationSummary = DelegationSummary{} - - // read parameters vars := mux.Vars(r) bech32delegator := vars["delegatorAddr"] - delAddr, err := sdk.AccAddressFromBech32(bech32delegator) + w.Header().Set("Content-Type", "application/json") + + delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - // Get all validators using key - validators, statusCode, errMsg, err := getBech32Validators(storeName, cliCtx, cdc) - if err != nil { - w.WriteHeader(statusCode) - w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) - return + params := stake.QueryDelegatorParams{ + DelegatorAddr: delegatorAddr, } - for _, validator := range validators { - valAddr = validator.OperatorAddr - - // Delegations - delegations, statusCode, errMsg, err := getDelegatorDelegations(cliCtx, cdc, delAddr, valAddr) - if err != nil { - w.WriteHeader(statusCode) - w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) - return - } - if statusCode != http.StatusNoContent { - delegationSummary.Delegations = append(delegationSummary.Delegations, delegations) - } - - // Undelegations - unbondingDelegation, statusCode, errMsg, err := getDelegatorUndelegations(cliCtx, cdc, delAddr, valAddr) - if err != nil { - w.WriteHeader(statusCode) - w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) - return - } - if statusCode != http.StatusNoContent { - delegationSummary.UnbondingDelegations = append(delegationSummary.UnbondingDelegations, unbondingDelegation) - } - - // Redelegations - // only querying redelegations to a validator as this should give us already all relegations - // if we also would put in redelegations from, we would have every redelegation double - redelegations, statusCode, errMsg, err := getDelegatorRedelegations(cliCtx, cdc, delAddr, valAddr) - if err != nil { - w.WriteHeader(statusCode) - w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) - return - } - if statusCode != http.StatusNoContent { - delegationSummary.Redelegations = append(delegationSummary.Redelegations, redelegations) - } - } - - output, err := cdc.MarshalJSON(delegationSummary) + bz, err := cdc.MarshalJSON(params) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - w.Write(output) + res, err := cliCtx.QueryWithData("custom/stake/delegator", bz) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + + return + } + + w.Write(res) } } @@ -184,6 +129,8 @@ func delegatorTxsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Han vars := mux.Vars(r) delegatorAddr := vars["delegatorAddr"] + w.Header().Set("Content-Type", "application/json") + _, err := sdk.AccAddressFromBech32(delegatorAddr) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -237,7 +184,7 @@ func delegatorTxsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Han foundTxs, errQuery := queryTxs(node, cdc, action, delegatorAddr) if errQuery != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("error querying transactions. Error: %s", errQuery.Error()))) + w.Write([]byte(errQuery.Error())) } txs = append(txs, foundTxs...) } @@ -253,59 +200,49 @@ func delegatorTxsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Han } // HTTP request handler to query an unbonding-delegation -func unbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { +func unbondingDelegationHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bech32delegator := vars["delegatorAddr"] bech32validator := vars["validatorAddr"] - delAddr, err := sdk.AccAddressFromBech32(bech32delegator) + w.Header().Set("Content-Type", "application/json") + + delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - valAddr, err := sdk.ValAddressFromBech32(bech32validator) + validatorAddr, err := sdk.ValAddressFromBech32(bech32validator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - key := stake.GetUBDKey(delAddr, valAddr) + params := stake.QueryBondsParams{ + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + } - res, err := cliCtx.QueryStore(key, storeName) + bz, err := cdc.MarshalJSON(params) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + res, err := cliCtx.QueryWithData("custom/stake/unbondingDelegation", bz) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) + w.Write([]byte(err.Error())) + return } - // the query will return empty if there is no data for this record - if len(res) == 0 { - w.WriteHeader(http.StatusNoContent) - return - } - - ubd, err := types.UnmarshalUBD(cdc, key, res) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't unmarshall unbonding-delegation. Error: %s", err.Error()))) - return - } - - // unbondings will be a list in the future but is not yet, but we want to keep the API consistent - ubdArray := []stake.UnbondingDelegation{ubd} - - output, err := cdc.MarshalJSON(ubdArray) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't marshall unbonding-delegation. Error: %s", err.Error()))) - return - } - - w.Write(output) + w.Write(res) } } @@ -317,70 +254,7 @@ func delegationHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Handl bech32delegator := vars["delegatorAddr"] bech32validator := vars["validatorAddr"] - delAddr, err := sdk.AccAddressFromBech32(bech32delegator) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) - return - } - - valAddr, err := sdk.ValAddressFromBech32(bech32validator) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) - return - } - - key := stake.GetDelegationKey(delAddr, valAddr) - - res, err := cliCtx.QueryStore(key, storeName) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query delegation. Error: %s", err.Error()))) - return - } - - // the query will return empty if there is no data for this record - if len(res) == 0 { - w.WriteHeader(http.StatusNoContent) - return - } - - delegation, err := types.UnmarshalDelegation(cdc, key, res) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) - return - } - - outputDelegation := DelegationWithoutRat{ - DelegatorAddr: delegation.DelegatorAddr, - ValidatorAddr: delegation.ValidatorAddr, - Height: delegation.Height, - Shares: delegation.Shares.String(), - } - - output, err := cdc.MarshalJSON(outputDelegation) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - - w.Write(output) - } -} - -// HTTP request handler to query all delegator bonded validators -func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - - var valAddr sdk.ValAddress - var bondedValidators []types.Validator - - // read parameters - vars := mux.Vars(r) - bech32delegator := vars["delegatorAddr"] + w.Header().Set("Content-Type", "application/json") delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { @@ -389,120 +263,134 @@ func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) h return } - // Get all validators using key - kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) + validatorAddr, err := sdk.ValAddressFromBech32(bech32validator) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query validators. Error: %s", err.Error()))) - return - } else if len(kvs) == 0 { - // the query will return empty if there are no validators - w.WriteHeader(http.StatusNoContent) - return - } - - validators, err := getValidators(kvs, cdc) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) - return - } - - for _, validator := range validators { - // get all transactions from the delegator to val and append - valAddr = validator.OperatorAddr - - validator, statusCode, errMsg, errRes := getDelegatorValidator(cliCtx, cdc, delegatorAddr, valAddr) - if errRes != nil { - w.WriteHeader(statusCode) - w.Write([]byte(fmt.Sprintf("%s%s", errMsg, errRes.Error()))) - return - } else if statusCode == http.StatusNoContent { - continue - } - - bondedValidators = append(bondedValidators, validator) - } - output, err := cdc.MarshalJSON(bondedValidators) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - w.Write(output) + + params := stake.QueryBondsParams{ + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + } + + bz, err := cdc.MarshalJSON(params) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + res, err := cliCtx.QueryWithData("custom/stake/delegation", bz) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + + return + } + + w.Write(res) + } +} + +// HTTP request handler to query all delegator bonded validators +func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // read parameters + vars := mux.Vars(r) + bech32delegator := vars["delegatorAddr"] + + w.Header().Set("Content-Type", "application/json") + + delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + params := stake.QueryDelegatorParams{ + DelegatorAddr: delegatorAddr, + } + + bz, err := cdc.MarshalJSON(params) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + res, err := cliCtx.QueryWithData("custom/stake/delegatorValidators", bz) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + + return + } + + w.Write(res) } } // HTTP request handler to get information from a currently bonded validator func delegatorValidatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // read parameters - var output []byte + vars := mux.Vars(r) bech32delegator := vars["delegatorAddr"] bech32validator := vars["validatorAddr"] - delAddr, err := sdk.AccAddressFromBech32(bech32delegator) - valAddr, err := sdk.ValAddressFromBech32(bech32validator) + w.Header().Set("Content-Type", "application/json") + + delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) + validatorAddr, err := sdk.ValAddressFromBech32(bech32validator) if err != nil { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) - return - } - - // Check if there if the delegator is bonded or redelegated to the validator - - validator, statusCode, errMsg, err := getDelegatorValidator(cliCtx, cdc, delAddr, valAddr) - if err != nil { - w.WriteHeader(statusCode) - w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) - return - } else if statusCode == http.StatusNoContent { - w.WriteHeader(statusCode) - return - } - output, err = cdc.MarshalJSON(validator) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } - w.Write(output) + + params := stake.QueryBondsParams{ + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + } + + bz, err := cdc.MarshalJSON(params) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + res, err := cliCtx.QueryWithData("custom/stake/delegatorValidator", bz) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + + return + } + + w.Write(res) } } -// TODO bech32 -// http request handler to query list of validators -func validatorsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { +// HTTP request handler to query list of validators +func validatorsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query validators. Error: %s", err.Error()))) - return - } - // the query will return empty if there are no validators - if len(kvs) == 0 { - w.WriteHeader(http.StatusNoContent) - return - } + w.Header().Set("Content-Type", "application/json") - validators, err := getValidators(kvs, cdc) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) - return - } - - output, err := cdc.MarshalJSON(validators) + res, err := cliCtx.QueryWithData("custom/stake/validators", nil) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) + return } - w.Write(output) + w.Header().Set("Content-Type", "application/json") + w.Write(res) } } @@ -510,111 +398,73 @@ func validatorsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Handl func validatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var output []byte - // read parameters vars := mux.Vars(r) bech32validatorAddr := vars["addr"] - valAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(fmt.Sprintf("error: %s", err.Error()))) - return - } + w.Header().Set("Content-Type", "application/json") - key := stake.GetValidatorKey(valAddr) - - res, err := cliCtx.QueryStore(key, storeName) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query validator, error: %s", err.Error()))) - return - } - - // the query will return empty if there is no data for this record - if len(res) == 0 { - w.WriteHeader(http.StatusNoContent) - return - } - - validator, err := types.UnmarshalValidator(cdc, valAddr, res) + validatorAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - output, err = cdc.MarshalJSON(validator) + params := stake.QueryValidatorParams{ + ValidatorAddr: validatorAddr, + } + + bz, err := cdc.MarshalJSON(params) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) return } - if output == nil { - w.WriteHeader(http.StatusNoContent) + res, err := cliCtx.QueryWithData("custom/stake/validator", bz) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return } - w.Write(output) + + w.Write(res) } } // HTTP request handler to query the pool information -func poolHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { +func poolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - key := stake.PoolKey - res, err := cliCtx.QueryStore(key, storeName) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query pool. Error: %s", err.Error()))) - return - } + w.Header().Set("Content-Type", "application/json") - pool, err := types.UnmarshalPool(cdc, res) + res, err := cliCtx.QueryWithData("custom/stake/pool", nil) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) + return } - output, err := cdc.MarshalJSON(pool) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - - w.Write(output) + w.Write(res) } } // HTTP request handler to query the staking params values -func paramsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { +func paramsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - key := stake.ParamKey - res, err := cliCtx.QueryStore(key, storeName) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't query parameters. Error: %s", err.Error()))) - return - } + w.Header().Set("Content-Type", "application/json") - params, err := types.UnmarshalParams(cdc, res) + res, err := cliCtx.QueryWithData("custom/stake/parameters", nil) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) + return } - output, err := cdc.MarshalJSON(params) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - - w.Write(output) + w.Write(res) } } diff --git a/x/stake/client/rest/utils.go b/x/stake/client/rest/utils.go index 6bd91e740..afe672840 100644 --- a/x/stake/client/rest/utils.go +++ b/x/stake/client/rest/utils.go @@ -2,15 +2,10 @@ package rest import ( "fmt" - "net/http" - "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake/tags" - "github.com/cosmos/cosmos-sdk/x/stake/types" rpcclient "github.com/tendermint/tendermint/rpc/client" ) @@ -24,106 +19,6 @@ func contains(stringSlice []string, txType string) bool { return false } -func getDelegatorValidator(cliCtx context.CLIContext, cdc *codec.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( - validator types.Validator, httpStatusCode int, errMsg string, err error) { - - key := stake.GetDelegationKey(delAddr, valAddr) - res, err := cliCtx.QueryStore(key, storeName) - if err != nil { - return types.Validator{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err - } - if len(res) == 0 { - return types.Validator{}, http.StatusNoContent, "", nil - } - - key = stake.GetValidatorKey(valAddr) - res, err = cliCtx.QueryStore(key, storeName) - if err != nil { - return types.Validator{}, http.StatusInternalServerError, "couldn't query validator. Error: ", err - } - if len(res) == 0 { - return types.Validator{}, http.StatusNoContent, "", nil - } - validator, err = types.UnmarshalValidator(cdc, valAddr, res) - if err != nil { - return types.Validator{}, http.StatusBadRequest, "", err - } - - return validator, http.StatusOK, "", nil -} - -func getDelegatorDelegations( - cliCtx context.CLIContext, cdc *codec.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( - outputDelegation DelegationWithoutRat, httpStatusCode int, errMsg string, err error) { - - delegationKey := stake.GetDelegationKey(delAddr, valAddr) - marshalledDelegation, err := cliCtx.QueryStore(delegationKey, storeName) - if err != nil { - return DelegationWithoutRat{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err - } - - if len(marshalledDelegation) == 0 { - return DelegationWithoutRat{}, http.StatusNoContent, "", nil - } - - delegation, err := types.UnmarshalDelegation(cdc, delegationKey, marshalledDelegation) - if err != nil { - return DelegationWithoutRat{}, http.StatusInternalServerError, "couldn't unmarshall delegation. Error: ", err - } - - outputDelegation = DelegationWithoutRat{ - DelegatorAddr: delegation.DelegatorAddr, - ValidatorAddr: delegation.ValidatorAddr, - Height: delegation.Height, - Shares: delegation.Shares.String(), - } - - return outputDelegation, http.StatusOK, "", nil -} - -func getDelegatorUndelegations( - cliCtx context.CLIContext, cdc *codec.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( - unbonds types.UnbondingDelegation, httpStatusCode int, errMsg string, err error) { - - undelegationKey := stake.GetUBDKey(delAddr, valAddr) - marshalledUnbondingDelegation, err := cliCtx.QueryStore(undelegationKey, storeName) - if err != nil { - return types.UnbondingDelegation{}, http.StatusInternalServerError, "couldn't query unbonding-delegation. Error: ", err - } - - if len(marshalledUnbondingDelegation) == 0 { - return types.UnbondingDelegation{}, http.StatusNoContent, "", nil - } - - unbondingDelegation, err := types.UnmarshalUBD(cdc, undelegationKey, marshalledUnbondingDelegation) - if err != nil { - return types.UnbondingDelegation{}, http.StatusInternalServerError, "couldn't unmarshall unbonding-delegation. Error: ", err - } - return unbondingDelegation, http.StatusOK, "", nil -} - -func getDelegatorRedelegations( - cliCtx context.CLIContext, cdc *codec.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( - regelegations types.Redelegation, httpStatusCode int, errMsg string, err error) { - - key := stake.GetREDsByDelToValDstIndexKey(delAddr, valAddr) - marshalledRedelegations, err := cliCtx.QueryStore(key, storeName) - if err != nil { - return types.Redelegation{}, http.StatusInternalServerError, "couldn't query redelegation. Error: ", err - } - - if len(marshalledRedelegations) == 0 { - return types.Redelegation{}, http.StatusNoContent, "", nil - } - - redelegations, err := types.UnmarshalRED(cdc, key, marshalledRedelegations) - if err != nil { - return types.Redelegation{}, http.StatusInternalServerError, "couldn't unmarshall redelegations. Error: ", err - } - - return redelegations, http.StatusOK, "", nil -} - // queries staking txs func queryTxs(node rpcclient.Client, cdc *codec.Codec, tag string, delegatorAddr string) ([]tx.Info, error) { page := 0 @@ -137,42 +32,3 @@ func queryTxs(node rpcclient.Client, cdc *codec.Codec, tag string, delegatorAddr return tx.FormatTxResults(cdc, res.Txs) } - -// gets all validators -func getValidators(validatorKVs []sdk.KVPair, cdc *codec.Codec) ([]types.Validator, error) { - validators := make([]types.Validator, len(validatorKVs)) - for i, kv := range validatorKVs { - - addr := kv.Key[1:] - validator, err := types.UnmarshalValidator(cdc, addr, kv.Value) - if err != nil { - return nil, err - } - - validators[i] = validator - } - return validators, nil -} - -// gets all Bech32 validators from a key -// nolint: unparam -func getBech32Validators(storeName string, cliCtx context.CLIContext, cdc *codec.Codec) ( - validators []types.Validator, httpStatusCode int, errMsg string, err error) { - - // Get all validators using key - kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) - if err != nil { - return nil, http.StatusInternalServerError, "couldn't query validators. Error: ", err - } - - // the query will return empty if there are no validators - if len(kvs) == 0 { - return nil, http.StatusNoContent, "", nil - } - - validators, err = getValidators(kvs, cdc) - if err != nil { - return nil, http.StatusInternalServerError, "Error: ", err - } - return validators, http.StatusOK, "", nil -} diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index ddd29f6f8..947bb2e18 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -42,6 +42,12 @@ func TestInitGenesis(t *testing.T) { vals, err := InitGenesis(ctx, keeper, genesisState) require.NoError(t, err) + actualGenesis := WriteGenesis(ctx, keeper) + require.Equal(t, genesisState.Pool, actualGenesis.Pool) + require.Equal(t, genesisState.Params, actualGenesis.Params) + require.Equal(t, genesisState.Bonds, actualGenesis.Bonds) + require.EqualValues(t, keeper.GetAllValidators(ctx), actualGenesis.Validators) + // now make sure the validators are bonded and intra-tx counters are correct resVal, found := keeper.GetValidator(ctx, sdk.ValAddress(keep.Addrs[0])) require.True(t, found) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 4862b14c3..70a21c171 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -17,14 +17,14 @@ import ( //______________________________________________________________________ func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator { - return types.NewMsgCreateValidator(address, pubKey, sdk.Coin{"steak", sdk.NewInt(amt)}, Description{}) + return types.NewMsgCreateValidator(address, pubKey, sdk.NewCoin("steak", sdk.NewInt(amt)), Description{}) } func newTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt int64) MsgDelegate { return MsgDelegate{ DelegatorAddr: delAddr, ValidatorAddr: valAddr, - Delegation: sdk.Coin{"steak", sdk.NewInt(amt)}, + Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)), } } @@ -34,7 +34,7 @@ func newTestMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.Val DelegatorAddr: delAddr, ValidatorAddr: valAddr, PubKey: valPubKey, - Delegation: sdk.Coin{"steak", sdk.NewInt(amt)}, + Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)), } } diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 0ef3eb9cf..ef09a307e 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake/types" ) -// load a delegation +// return a specific delegation func (k Keeper) GetDelegation(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( delegation types.Delegation, found bool) { @@ -24,44 +24,37 @@ func (k Keeper) GetDelegation(ctx sdk.Context, return delegation, true } -// load all delegations used during genesis dump +// return all delegations used during genesis dump func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, DelegationKey) + defer iterator.Close() - i := 0 - for ; ; i++ { - if !iterator.Valid() { - break - } + for ; iterator.Valid(); iterator.Next() { delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) delegations = append(delegations, delegation) - iterator.Next() } - iterator.Close() return delegations } -// load all delegations for a delegator -func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.AccAddress, - maxRetrieve int16) (delegations []types.Delegation) { +// return a given amount of all the delegations from a delegator +func (k Keeper) GetDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAddress, + maxRetrieve uint16) (delegations []types.Delegation) { + + delegations = make([]types.Delegation, maxRetrieve) store := ctx.KVStore(k.storeKey) delegatorPrefixKey := GetDelegationsKey(delegator) - iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) + defer iterator.Close() - delegations = make([]types.Delegation, maxRetrieve) i := 0 - for ; ; i++ { - if !iterator.Valid() || i > int(maxRetrieve-1) { - break - } + for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) delegations[i] = delegation - iterator.Next() + i++ } - iterator.Close() - return delegations[:i] // trim + return delegations[:i] // trim if the array length < maxRetrieve } // set the delegation @@ -71,7 +64,7 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b) } -// remove the delegation +// remove a delegation from store func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey) store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr)) @@ -79,7 +72,27 @@ func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { //_____________________________________________________________________________________ -// load a unbonding delegation +// return a given amount of all the delegator unbonding-delegations +func (k Keeper) GetUnbondingDelegations(ctx sdk.Context, delegator sdk.AccAddress, + maxRetrieve uint16) (unbondingDelegations []types.UnbondingDelegation) { + + unbondingDelegations = make([]types.UnbondingDelegation, maxRetrieve) + + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := GetUBDsKey(delegator) + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) + defer iterator.Close() + + i := 0 + for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { + unbondingDelegation := types.MustUnmarshalUBD(k.cdc, iterator.Key(), iterator.Value()) + unbondingDelegations[i] = unbondingDelegation + i++ + } + return unbondingDelegations[:i] // trim if the array length < maxRetrieve +} + +// return a unbonding delegation func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (ubd types.UnbondingDelegation, found bool) { @@ -94,21 +107,18 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, return ubd, true } -// load all unbonding delegations from a particular validator +// return all unbonding delegations from a particular validator func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (ubds []types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr)) - for { - if !iterator.Valid() { - break - } + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { key := GetUBDKeyFromValIndexKey(iterator.Key()) value := store.Get(key) ubd := types.MustUnmarshalUBD(k.cdc, key, value) ubds = append(ubds, ubd) - iterator.Next() } - iterator.Close() return ubds } @@ -116,16 +126,15 @@ func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sd func (k Keeper) IterateUnbondingDelegations(ctx sdk.Context, fn func(index int64, ubd types.UnbondingDelegation) (stop bool)) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, UnbondingDelegationKey) - i := int64(0) - for ; iterator.Valid(); iterator.Next() { + defer iterator.Close() + + for i := int64(0); iterator.Valid(); iterator.Next() { ubd := types.MustUnmarshalUBD(k.cdc, iterator.Key(), iterator.Value()) - stop := fn(i, ubd) - if stop { + if stop := fn(i, ubd); stop { break } i++ } - iterator.Close() } // set the unbonding delegation and associated index @@ -147,7 +156,26 @@ func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDe //_____________________________________________________________________________________ -// load a redelegation +// return a given amount of all the delegator redelegations +func (k Keeper) GetRedelegations(ctx sdk.Context, delegator sdk.AccAddress, + maxRetrieve uint16) (redelegations []types.Redelegation) { + redelegations = make([]types.Redelegation, maxRetrieve) + + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := GetREDsKey(delegator) + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) + defer iterator.Close() + + i := 0 + for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { + redelegation := types.MustUnmarshalRED(k.cdc, iterator.Key(), iterator.Value()) + redelegations[i] = redelegation + i++ + } + return redelegations[:i] // trim if the array length < maxRetrieve +} + +// return a redelegation func (k Keeper) GetRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (red types.Redelegation, found bool) { @@ -162,38 +190,34 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, return red, true } -// load all redelegations from a particular validator +// return all redelegations from a particular validator func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []types.Redelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr)) - for { - if !iterator.Valid() { - break - } + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { key := GetREDKeyFromValSrcIndexKey(iterator.Key()) value := store.Get(key) red := types.MustUnmarshalRED(k.cdc, key, value) reds = append(reds, red) - iterator.Next() } - iterator.Close() return reds } -// has a redelegation +// check if validator is receiving a redelegation func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) bool { store := ctx.KVStore(k.storeKey) prefix := GetREDsByDelToValDstIndexKey(delAddr, valDstAddr) - iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest + iterator := sdk.KVStorePrefixIterator(store, prefix) + defer iterator.Close() found := false if iterator.Valid() { - //record found found = true } - iterator.Close() return found } @@ -358,7 +382,7 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, // create the unbonding delegation params := k.GetParams(ctx) minTime, height, completeNow := k.getBeginInfo(ctx, params, valAddr) - balance := sdk.Coin{params.BondDenom, returnAmount.RoundInt()} + balance := sdk.NewCoin(params.BondDenom, returnAmount.RoundInt()) // no need to create the ubd object just complete now if completeNow { @@ -418,7 +442,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, } params := k.GetParams(ctx) - returnCoin := sdk.Coin{params.BondDenom, returnAmount.RoundInt()} + returnCoin := sdk.NewCoin(params.BondDenom, returnAmount.RoundInt()) dstValidator, found := k.GetValidator(ctx, valDstAddr) if !found { return types.ErrBadRedelegationDst(k.Codespace()) diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 023642bb2..ed65f1f40 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" ) -// tests GetDelegation, GetDelegations, SetDelegation, RemoveDelegation, GetDelegations +// tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations func TestDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 10) pool := keeper.GetPool(ctx) @@ -30,6 +30,7 @@ func TestDelegation(t *testing.T) { validators[2] = keeper.UpdateValidator(ctx, validators[2]) // first add a validators[0] to delegate too + bond1to1 := types.Delegation{ DelegatorAddr: addrDels[0], ValidatorAddr: addrVals[0], @@ -66,16 +67,16 @@ func TestDelegation(t *testing.T) { keeper.SetDelegation(ctx, bond2to3) // test all bond retrieve capabilities - resBonds := keeper.GetDelegations(ctx, addrDels[0], 5) + resBonds := keeper.GetDelegatorDelegations(ctx, addrDels[0], 5) require.Equal(t, 3, len(resBonds)) require.True(t, bond1to1.Equal(resBonds[0])) require.True(t, bond1to2.Equal(resBonds[1])) require.True(t, bond1to3.Equal(resBonds[2])) - resBonds = keeper.GetDelegations(ctx, addrDels[0], 3) + resBonds = keeper.GetAllDelegatorDelegations(ctx, addrDels[0]) require.Equal(t, 3, len(resBonds)) - resBonds = keeper.GetDelegations(ctx, addrDels[0], 2) + resBonds = keeper.GetDelegatorDelegations(ctx, addrDels[0], 2) require.Equal(t, 2, len(resBonds)) - resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) + resBonds = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 3, len(resBonds)) require.True(t, bond2to1.Equal(resBonds[0])) require.True(t, bond2to2.Equal(resBonds[1])) @@ -89,15 +90,34 @@ func TestDelegation(t *testing.T) { require.True(t, bond2to2.Equal(allBonds[4])) require.True(t, bond2to3.Equal(allBonds[5])) + resVals := keeper.GetDelegatorValidators(ctx, addrDels[0], 3) + require.Equal(t, 3, len(resVals)) + resVals = keeper.GetDelegatorValidators(ctx, addrDels[1], 4) + require.Equal(t, 3, len(resVals)) + + for i := 0; i < 3; i++ { + + resVal, err := keeper.GetDelegatorValidator(ctx, addrDels[0], addrVals[i]) + require.Nil(t, err) + require.Equal(t, addrVals[i], resVal.GetOperator()) + + resVal, err = keeper.GetDelegatorValidator(ctx, addrDels[1], addrVals[i]) + require.Nil(t, err) + require.Equal(t, addrVals[i], resVal.GetOperator()) + } + // delete a record keeper.RemoveDelegation(ctx, bond2to3) _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[2]) require.False(t, found) - resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) + resBonds = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 2, len(resBonds)) require.True(t, bond2to1.Equal(resBonds[0])) require.True(t, bond2to2.Equal(resBonds[1])) + resBonds = keeper.GetAllDelegatorDelegations(ctx, addrDels[1]) + require.Equal(t, 2, len(resBonds)) + // delete all the records from delegator 2 keeper.RemoveDelegation(ctx, bond2to1) keeper.RemoveDelegation(ctx, bond2to2) @@ -105,7 +125,7 @@ func TestDelegation(t *testing.T) { require.False(t, found) _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[1]) require.False(t, found) - resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) + resBonds = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.Equal(t, 0, len(resBonds)) } @@ -123,21 +143,35 @@ func TestUnbondingDelegation(t *testing.T) { // set and retrieve a record keeper.SetUnbondingDelegation(ctx, ubd) - resBond, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + resUnbond, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) - require.True(t, ubd.Equal(resBond)) + require.True(t, ubd.Equal(resUnbond)) // modify a records, save, and retrieve ubd.Balance = sdk.NewInt64Coin("steak", 21) keeper.SetUnbondingDelegation(ctx, ubd) - resBond, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + + resUnbonds := keeper.GetUnbondingDelegations(ctx, addrDels[0], 5) + require.Equal(t, 1, len(resUnbonds)) + + resUnbonds = keeper.GetAllUnbondingDelegations(ctx, addrDels[0]) + require.Equal(t, 1, len(resUnbonds)) + + resUnbond, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) - require.True(t, ubd.Equal(resBond)) + require.True(t, ubd.Equal(resUnbond)) // delete a record keeper.RemoveUnbondingDelegation(ctx, ubd) _, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.False(t, found) + + resUnbonds = keeper.GetUnbondingDelegations(ctx, addrDels[0], 5) + require.Equal(t, 0, len(resUnbonds)) + + resUnbonds = keeper.GetAllUnbondingDelegations(ctx, addrDels[0]) + require.Equal(t, 0, len(resUnbonds)) + } func TestUnbondDelegation(t *testing.T) { @@ -413,12 +447,20 @@ func TestRedelegation(t *testing.T) { // set and retrieve a record keeper.SetRedelegation(ctx, rd) - resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + resRed, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resBond)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = keeper.GetAllRedelegations(ctx, addrDels[0]) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) // check if has the redelegation has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) @@ -429,18 +471,28 @@ func TestRedelegation(t *testing.T) { rd.SharesDst = sdk.NewDec(21) keeper.SetRedelegation(ctx, rd) - resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + resRed, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) - require.True(t, rd.Equal(resBond)) + require.True(t, rd.Equal(resRed)) redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0]) require.Equal(t, 1, len(redelegations)) - require.True(t, redelegations[0].Equal(resBond)) + require.True(t, redelegations[0].Equal(resRed)) + + redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 1, len(redelegations)) + require.True(t, redelegations[0].Equal(resRed)) // delete a record keeper.RemoveRedelegation(ctx, rd) _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.False(t, found) + + redelegations = keeper.GetRedelegations(ctx, addrDels[0], 5) + require.Equal(t, 0, len(redelegations)) + + redelegations = keeper.GetAllRedelegations(ctx, addrDels[0]) + require.Equal(t, 0, len(redelegations)) } func TestRedelegateSelfDelegation(t *testing.T) { diff --git a/x/stake/keeper/query_utils.go b/x/stake/keeper/query_utils.go new file mode 100644 index 000000000..c1575cd42 --- /dev/null +++ b/x/stake/keeper/query_utils.go @@ -0,0 +1,101 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake/types" +) + +// Return all validators that a delegator is bonded to. If maxRetrieve is supplied, the respective amount will be returned. +func (k Keeper) GetDelegatorValidators(ctx sdk.Context, delegatorAddr sdk.AccAddress, + maxRetrieve uint16) (validators []types.Validator) { + validators = make([]types.Validator, maxRetrieve) + + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := GetDelegationsKey(delegatorAddr) + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest + defer iterator.Close() + + i := 0 + for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { + addr := iterator.Key() + delegation := types.MustUnmarshalDelegation(k.cdc, addr, iterator.Value()) + + validator, found := k.GetValidator(ctx, delegation.ValidatorAddr) + if !found { + panic(types.ErrNoValidatorFound(types.DefaultCodespace)) + } + validators[i] = validator + i++ + } + return validators[:i] // trim +} + +// return a validator that a delegator is bonded to +func (k Keeper) GetDelegatorValidator(ctx sdk.Context, delegatorAddr sdk.AccAddress, + validatorAddr sdk.ValAddress) (validator types.Validator, err sdk.Error) { + + delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) + if !found { + return validator, types.ErrNoDelegation(types.DefaultCodespace) + } + + validator, found = k.GetValidator(ctx, delegation.ValidatorAddr) + if !found { + panic(types.ErrNoValidatorFound(types.DefaultCodespace)) + } + return +} + +//_____________________________________________________________________________________ + +// return all delegations for a delegator +func (k Keeper) GetAllDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAddress) ( + delegations []types.Delegation) { + + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := GetDelegationsKey(delegator) + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest + defer iterator.Close() + + i := 0 + for ; iterator.Valid(); iterator.Next() { + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + delegations = append(delegations, delegation) + i++ + } + return delegations +} + +// return all unbonding-delegations for a delegator +func (k Keeper) GetAllUnbondingDelegations(ctx sdk.Context, delegator sdk.AccAddress) ( + unbondingDelegations []types.UnbondingDelegation) { + + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := GetUBDsKey(delegator) + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest + defer iterator.Close() + + i := 0 + for ; iterator.Valid(); iterator.Next() { + unbondingDelegation := types.MustUnmarshalUBD(k.cdc, iterator.Key(), iterator.Value()) + unbondingDelegations = append(unbondingDelegations, unbondingDelegation) + i++ + } + return unbondingDelegations +} + +// return all redelegations for a delegator +func (k Keeper) GetAllRedelegations(ctx sdk.Context, delegator sdk.AccAddress) (redelegations []types.Redelegation) { + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := GetREDsKey(delegator) + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest + defer iterator.Close() + + i := 0 + for ; iterator.Valid(); iterator.Next() { + redelegation := types.MustUnmarshalRED(k.cdc, iterator.Key(), iterator.Value()) + redelegations = append(redelegations, redelegation) + i++ + } + return redelegations +} diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 1f65aaa95..996bf06bf 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -103,39 +103,32 @@ func (k Keeper) validatorByPowerIndexExists(ctx sdk.Context, power []byte) bool func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey) + defer iterator.Close() - i := 0 - for ; ; i++ { - if !iterator.Valid() { - break - } + for ; iterator.Valid(); iterator.Next() { addr := iterator.Key()[1:] validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) validators = append(validators, validator) - iterator.Next() } - iterator.Close() return validators } -// Get the set of all validators, retrieve a maxRetrieve number of records -func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators []types.Validator) { +// return a given amount of all the validators +func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve uint16) (validators []types.Validator) { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey) - validators = make([]types.Validator, maxRetrieve) + + iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey) + defer iterator.Close() + i := 0 - for ; ; i++ { - if !iterator.Valid() || i > int(maxRetrieve-1) { - break - } + for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { addr := iterator.Key()[1:] validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) validators[i] = validator - iterator.Next() + i++ } - iterator.Close() - return validators[:i] // trim + return validators[:i] // trim if the array length < maxRetrieve } //___________________________________________________________________________ @@ -149,6 +142,8 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat validators = make([]types.Validator, maxValidators) iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) + defer iterator.Close() + i := 0 for ; iterator.Valid(); iterator.Next() { @@ -163,7 +158,6 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat validators[i] = validator i++ } - iterator.Close() return validators[:i] // trim } @@ -174,12 +168,12 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators validators := make([]types.Validator, maxValidators) - iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest + + iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) + defer iterator.Close() + i := 0 - for { - if !iterator.Valid() || i > int(maxValidators-1) { - break - } + for ; iterator.Valid() && i < int(maxValidators); iterator.Next() { address := iterator.Value() validator, found := k.GetValidator(ctx, address) ensureValidatorFound(found, address) @@ -188,9 +182,7 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { validators[i] = validator i++ } - iterator.Next() } - iterator.Close() return validators[:i] // trim } @@ -206,6 +198,8 @@ func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Valid tstore := ctx.TransientStore(k.storeTKey) iterator := sdk.KVStorePrefixIterator(tstore, TendermintUpdatesTKey) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { var abciVal abci.Validator @@ -228,8 +222,6 @@ func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Valid updates = append(updates, abciVal) } } - - iterator.Close() return } @@ -447,10 +439,7 @@ func (k Keeper) UpdateBondedValidators( // create a validator iterator ranging from largest to smallest by power iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) - for { - if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) { - break - } + for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() { // either retrieve the original validator from the store, or under the // situation that this is the "affected validator" just use the @@ -484,7 +473,6 @@ func (k Keeper) UpdateBondedValidators( } bondedValidatorsCount++ - iterator.Next() } iterator.Close() @@ -551,11 +539,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) { bondedValidatorsCount := 0 iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) - for { - if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) { - break - } - + for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() { var found bool ownerAddr := iterator.Value() @@ -578,12 +562,10 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) { if validator.Status == sdk.Bonded { panic(fmt.Sprintf("jailed validator cannot be bonded for address: %s\n", ownerAddr)) } - break } bondedValidatorsCount++ - iterator.Next() } iterator.Close() diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 89dd40677..e23d3b0aa 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -59,11 +59,22 @@ func TestSetValidator(t *testing.T) { resVals = keeper.GetValidatorsByPower(ctx) require.Equal(t, 1, len(resVals)) - assert.True(ValEq(t, validator, resVals[0])) + require.True(ValEq(t, validator, resVals[0])) + + resVals = keeper.GetValidators(ctx, 1) + require.Equal(t, 1, len(resVals)) + require.True(ValEq(t, validator, resVals[0])) + + resVals = keeper.GetValidators(ctx, 10) + require.Equal(t, 1, len(resVals)) + require.True(ValEq(t, validator, resVals[0])) updates := keeper.GetValidTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) require.Equal(t, validator.ABCIValidator(), updates[0]) + + allVals := keeper.GetAllValidators(ctx) + require.Equal(t, 1, len(allVals)) } func TestUpdateValidatorByPowerIndex(t *testing.T) { @@ -283,7 +294,10 @@ func TestValidatorBasics(t *testing.T) { _, found := keeper.GetValidator(ctx, addrVals[0]) require.False(t, found) resVals := keeper.GetValidatorsBonded(ctx) - assert.Zero(t, len(resVals)) + require.Zero(t, len(resVals)) + + resVals = keeper.GetValidators(ctx, 2) + require.Zero(t, len(resVals)) pool = keeper.GetPool(ctx) assert.True(sdk.DecEq(t, sdk.ZeroDec(), pool.BondedTokens)) diff --git a/x/stake/querier/queryable.go b/x/stake/querier/queryable.go new file mode 100644 index 000000000..8537f2bd4 --- /dev/null +++ b/x/stake/querier/queryable.go @@ -0,0 +1,227 @@ +package querier + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + keep "github.com/cosmos/cosmos-sdk/x/stake/keeper" + "github.com/cosmos/cosmos-sdk/x/stake/types" + abci "github.com/tendermint/tendermint/abci/types" +) + +// query endpoints supported by the staking Querier +const ( + QueryValidators = "validators" + QueryValidator = "validator" + QueryDelegator = "delegator" + QueryDelegation = "delegation" + QueryUnbondingDelegation = "unbondingDelegation" + QueryDelegatorValidators = "delegatorValidators" + QueryDelegatorValidator = "delegatorValidator" + QueryPool = "pool" + QueryParameters = "parameters" +) + +// creates a querier for staking REST endpoints +func NewQuerier(k keep.Keeper, cdc *codec.Codec) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + switch path[0] { + case QueryValidators: + return queryValidators(ctx, cdc, k) + case QueryValidator: + return queryValidator(ctx, cdc, req, k) + case QueryDelegator: + return queryDelegator(ctx, cdc, req, k) + case QueryDelegation: + return queryDelegation(ctx, cdc, req, k) + case QueryUnbondingDelegation: + return queryUnbondingDelegation(ctx, cdc, req, k) + case QueryDelegatorValidators: + return queryDelegatorValidators(ctx, cdc, req, k) + case QueryDelegatorValidator: + return queryDelegatorValidator(ctx, cdc, req, k) + case QueryPool: + return queryPool(ctx, cdc, k) + case QueryParameters: + return queryParameters(ctx, cdc, k) + default: + return nil, sdk.ErrUnknownRequest("unknown stake query endpoint") + } + } +} + +// defines the params for the following queries: +// - 'custom/stake/delegator' +// - 'custom/stake/delegatorValidators' +type QueryDelegatorParams struct { + DelegatorAddr sdk.AccAddress +} + +// defines the params for the following queries: +// - 'custom/stake/validator' +type QueryValidatorParams struct { + ValidatorAddr sdk.ValAddress +} + +// defines the params for the following queries: +// - 'custom/stake/delegation' +// - 'custom/stake/unbondingDelegation' +// - 'custom/stake/delegatorValidator' +type QueryBondsParams struct { + DelegatorAddr sdk.AccAddress + ValidatorAddr sdk.ValAddress +} + +func queryValidators(ctx sdk.Context, cdc *codec.Codec, k keep.Keeper) (res []byte, err sdk.Error) { + stakeParams := k.GetParams(ctx) + validators := k.GetValidators(ctx, stakeParams.MaxValidators) + + res, errRes := codec.MarshalJSONIndent(cdc, validators) + if err != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} + +func queryValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { + var params QueryValidatorParams + + errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + if errRes != nil { + return []byte{}, sdk.ErrUnknownAddress(fmt.Sprintf("incorrectly formatted request address: %s", err.Error())) + } + + validator, found := k.GetValidator(ctx, params.ValidatorAddr) + if !found { + return []byte{}, types.ErrNoValidatorFound(types.DefaultCodespace) + } + + res, errRes = codec.MarshalJSONIndent(cdc, validator) + if errRes != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} + +func queryDelegator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { + var params QueryDelegatorParams + errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + if errRes != nil { + return []byte{}, sdk.ErrUnknownAddress(fmt.Sprintf("incorrectly formatted request address: %s", errRes.Error())) + } + delegations := k.GetAllDelegatorDelegations(ctx, params.DelegatorAddr) + unbondingDelegations := k.GetAllUnbondingDelegations(ctx, params.DelegatorAddr) + redelegations := k.GetAllRedelegations(ctx, params.DelegatorAddr) + + summary := types.DelegationSummary{ + Delegations: delegations, + UnbondingDelegations: unbondingDelegations, + Redelegations: redelegations, + } + + res, errRes = codec.MarshalJSONIndent(cdc, summary) + if errRes != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} + +func queryDelegatorValidators(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { + var params QueryDelegatorParams + + stakeParams := k.GetParams(ctx) + + errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + if errRes != nil { + return []byte{}, sdk.ErrUnknownAddress(fmt.Sprintf("incorrectly formatted request address: %s", errRes.Error())) + } + + validators := k.GetDelegatorValidators(ctx, params.DelegatorAddr, stakeParams.MaxValidators) + + res, errRes = codec.MarshalJSONIndent(cdc, validators) + if errRes != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} + +func queryDelegatorValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { + var params QueryBondsParams + + errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + if errRes != nil { + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request address: %s", errRes.Error())) + } + + validator, err := k.GetDelegatorValidator(ctx, params.DelegatorAddr, params.ValidatorAddr) + if err != nil { + return + } + + res, errRes = codec.MarshalJSONIndent(cdc, validator) + if errRes != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} + +func queryDelegation(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { + var params QueryBondsParams + + errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + if errRes != nil { + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request address: %s", errRes.Error())) + } + + delegation, found := k.GetDelegation(ctx, params.DelegatorAddr, params.ValidatorAddr) + if !found { + return []byte{}, types.ErrNoDelegation(types.DefaultCodespace) + } + + res, errRes = codec.MarshalJSONIndent(cdc, delegation) + if errRes != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} + +func queryUnbondingDelegation(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { + var params QueryBondsParams + + errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + if errRes != nil { + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request address: %s", errRes.Error())) + } + + unbond, found := k.GetUnbondingDelegation(ctx, params.DelegatorAddr, params.ValidatorAddr) + if !found { + return []byte{}, types.ErrNoUnbondingDelegation(types.DefaultCodespace) + } + + res, errRes = codec.MarshalJSONIndent(cdc, unbond) + if errRes != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} + +func queryPool(ctx sdk.Context, cdc *codec.Codec, k keep.Keeper) (res []byte, err sdk.Error) { + pool := k.GetPool(ctx) + + res, errRes := codec.MarshalJSONIndent(cdc, pool) + if errRes != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} + +func queryParameters(ctx sdk.Context, cdc *codec.Codec, k keep.Keeper) (res []byte, err sdk.Error) { + params := k.GetParams(ctx) + + res, errRes := codec.MarshalJSONIndent(cdc, params) + if errRes != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", errRes.Error())) + } + return res, nil +} diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go new file mode 100644 index 000000000..ee52773c6 --- /dev/null +++ b/x/stake/querier/queryable_test.go @@ -0,0 +1,215 @@ +package querier + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + keep "github.com/cosmos/cosmos-sdk/x/stake/keeper" + "github.com/cosmos/cosmos-sdk/x/stake/types" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" +) + +var ( + addrAcc1, addrAcc2 = keep.Addrs[0], keep.Addrs[1] + addrVal1, addrVal2 = sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) + pk1, pk2 = keep.PKs[0], keep.PKs[1] +) + +func newTestDelegatorQuery(delegatorAddr sdk.AccAddress) QueryDelegatorParams { + return QueryDelegatorParams{ + DelegatorAddr: delegatorAddr, + } +} + +func newTestValidatorQuery(validatorAddr sdk.ValAddress) QueryValidatorParams { + return QueryValidatorParams{ + ValidatorAddr: validatorAddr, + } +} + +func newTestBondQuery(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) QueryBondsParams { + return QueryBondsParams{ + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + } +} + +func TestQueryParametersPool(t *testing.T) { + cdc := codec.New() + ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + + res, err := queryParameters(ctx, cdc, keeper) + require.Nil(t, err) + + var params types.Params + errRes := cdc.UnmarshalJSON(res, ¶ms) + require.Nil(t, errRes) + require.Equal(t, keeper.GetParams(ctx), params) + + res, err = queryPool(ctx, cdc, keeper) + require.Nil(t, err) + + var pool types.Pool + errRes = cdc.UnmarshalJSON(res, &pool) + require.Nil(t, errRes) + require.Equal(t, keeper.GetPool(ctx), pool) +} + +func TestQueryValidators(t *testing.T) { + cdc := codec.New() + ctx, _, keeper := keep.CreateTestInput(t, false, 10000) + pool := keeper.GetPool(ctx) + params := keeper.GetParams(ctx) + + // Create Validators + amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8)} + var validators [2]types.Validator + for i, amt := range amts { + validators[i] = types.NewValidator(sdk.ValAddress(keep.Addrs[i]), keep.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]) + + // Query Validators + queriedValidators := keeper.GetValidators(ctx, params.MaxValidators) + + res, err := queryValidators(ctx, cdc, keeper) + require.Nil(t, err) + + var validatorsResp []types.Validator + errRes := cdc.UnmarshalJSON(res, &validatorsResp) + require.Nil(t, errRes) + + require.Equal(t, len(queriedValidators), len(validatorsResp)) + require.ElementsMatch(t, queriedValidators, validatorsResp) + + // Query each validator + queryParams := newTestValidatorQuery(addrVal1) + bz, errRes := cdc.MarshalJSON(queryParams) + require.Nil(t, errRes) + + query := abci.RequestQuery{ + Path: "/custom/stake/validator", + Data: bz, + } + res, err = queryValidator(ctx, cdc, query, keeper) + require.Nil(t, err) + + var validator types.Validator + errRes = cdc.UnmarshalJSON(res, &validator) + require.Nil(t, errRes) + + require.Equal(t, queriedValidators[0], validator) +} + +func TestQueryDelegation(t *testing.T) { + cdc := codec.New() + ctx, _, keeper := keep.CreateTestInput(t, false, 10000) + params := keeper.GetParams(ctx) + + // Create Validators and Delegation + val1 := types.NewValidator(addrVal1, pk1, types.Description{}) + keeper.SetValidator(ctx, val1) + + keeper.Delegate(ctx, addrAcc2, sdk.NewCoin("steak", sdk.NewInt(20)), val1, true) + + // Query Delegator bonded validators + queryParams := newTestDelegatorQuery(addrAcc2) + bz, errRes := cdc.MarshalJSON(queryParams) + require.Nil(t, errRes) + + query := abci.RequestQuery{ + Path: "/custom/stake/delegatorValidators", + Data: bz, + } + + delValidators := keeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) + + res, err := queryDelegatorValidators(ctx, cdc, query, keeper) + require.Nil(t, err) + + var validatorsResp []types.Validator + errRes = cdc.UnmarshalJSON(res, &validatorsResp) + require.Nil(t, errRes) + + require.Equal(t, len(delValidators), len(validatorsResp)) + require.ElementsMatch(t, delValidators, validatorsResp) + + // Query bonded validator + queryBondParams := newTestBondQuery(addrAcc2, addrVal1) + bz, errRes = cdc.MarshalJSON(queryBondParams) + require.Nil(t, errRes) + + query = abci.RequestQuery{ + Path: "/custom/stake/delegatorValidator", + Data: bz, + } + + res, err = queryDelegatorValidator(ctx, cdc, query, keeper) + require.Nil(t, err) + + var validator types.Validator + errRes = cdc.UnmarshalJSON(res, &validator) + require.Nil(t, errRes) + + require.Equal(t, delValidators[0], validator) + + // Query delegation + + query = abci.RequestQuery{ + Path: "/custom/stake/delegation", + Data: bz, + } + + delegation, found := keeper.GetDelegation(ctx, addrAcc2, addrVal1) + require.True(t, found) + + res, err = queryDelegation(ctx, cdc, query, keeper) + require.Nil(t, err) + + var delegationRes types.Delegation + errRes = cdc.UnmarshalJSON(res, &delegationRes) + require.Nil(t, errRes) + + require.Equal(t, delegation, delegationRes) + + // Query unbonging delegation + keeper.BeginUnbonding(ctx, addrAcc2, val1.OperatorAddr, sdk.NewDec(10)) + + query = abci.RequestQuery{ + Path: "/custom/stake/unbondingDelegation", + Data: bz, + } + + unbond, found := keeper.GetUnbondingDelegation(ctx, addrAcc2, addrVal1) + require.True(t, found) + + res, err = queryUnbondingDelegation(ctx, cdc, query, keeper) + require.Nil(t, err) + + var unbondRes types.UnbondingDelegation + errRes = cdc.UnmarshalJSON(res, &unbondRes) + require.Nil(t, errRes) + + require.Equal(t, unbond, unbondRes) + + // Query Delegator Summary + + query = abci.RequestQuery{ + Path: "/custom/stake/delegator", + Data: bz, + } + + res, err = queryDelegator(ctx, cdc, query, keeper) + require.Nil(t, err) + + var summary types.DelegationSummary + errRes = cdc.UnmarshalJSON(res, &summary) + require.Nil(t, errRes) + + require.Equal(t, unbond, summary.UnbondingDelegations[0]) +} diff --git a/x/stake/stake.go b/x/stake/stake.go index 74be3a702..18b99fd4a 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -3,6 +3,7 @@ package stake import ( "github.com/cosmos/cosmos-sdk/x/stake/keeper" + "github.com/cosmos/cosmos-sdk/x/stake/querier" "github.com/cosmos/cosmos-sdk/x/stake/tags" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -12,6 +13,7 @@ type ( Validator = types.Validator Description = types.Description Delegation = types.Delegation + DelegationSummary = types.DelegationSummary UnbondingDelegation = types.UnbondingDelegation Redelegation = types.Redelegation Params = types.Params @@ -24,6 +26,9 @@ type ( MsgBeginRedelegate = types.MsgBeginRedelegate MsgCompleteRedelegate = types.MsgCompleteRedelegate GenesisState = types.GenesisState + QueryDelegatorParams = querier.QueryDelegatorParams + QueryValidatorParams = querier.QueryValidatorParams + QueryBondsParams = querier.QueryBondsParams ) var ( @@ -75,6 +80,8 @@ var ( NewMsgCompleteUnbonding = types.NewMsgCompleteUnbonding NewMsgBeginRedelegate = types.NewMsgBeginRedelegate NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate + + NewQuerier = querier.NewQuerier ) const ( diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index e6bf11e73..38a94c369 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -24,6 +24,13 @@ type delegationValue struct { Height int64 } +// aggregates of all delegations, unbondings and redelegations +type DelegationSummary struct { + Delegations []Delegation `json:"delegations"` + UnbondingDelegations []UnbondingDelegation `json:"unbonding_delegations"` + Redelegations []Redelegation `json:"redelegations"` +} + // return the delegation without fields contained within the key for the store func MustMarshalDelegation(cdc *codec.Codec, delegation Delegation) []byte { val := delegationValue{