From 20cc13e5bf271010fdc641cf622dd1474134c169 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Tue, 16 Oct 2018 09:29:32 -0700 Subject: [PATCH 01/13] types: Dec.MarshalJSON now marshals as a normal decimal string Closes #2475 --- PENDING.md | 2 ++ types/decimal.go | 33 +++++++++++++++++++++++++++++---- types/decimal_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/PENDING.md b/PENDING.md index eb61a5468e..2f0f9c2d71 100644 --- a/PENDING.md +++ b/PENDING.md @@ -72,6 +72,8 @@ BREAKING CHANGES * [x/stake] \#2412 Added an unbonding validator queue to EndBlock to automatically update validator.Status when finished Unbonding * [x/stake] \#2500 Block conflicting redelegations until we add an index * [x/params] Global Paramstore refactored + * [types] \#2506 sdk.Dec MarshalJSON now marshals as a normal Decimal, with 10 digits of decimal precision + * Tendermint * Update tendermint version from v0.23.0 to v0.25.0, notable changes diff --git a/types/decimal.go b/types/decimal.go index e9623995f0..a3cd7cc0e3 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -407,17 +407,36 @@ func (d *Dec) UnmarshalAmino(text string) (err error) { return nil } -// MarshalJSON defines custom encoding scheme +// MarshalJSON marshals the decimal func (d Dec) MarshalJSON() ([]byte, error) { if d.Int == nil { return nilJSON, nil } - bz, err := d.Int.MarshalText() if err != nil { return nil, err } - return json.Marshal(string(bz)) + var bzWDec []byte + // TODO: Remove trailing zeros + // case 1, pure decimal + if len(bz) <= 10 { + bzWDec = make([]byte, 12) + // 0. prefix + bzWDec[0] = byte('0') + bzWDec[1] = byte('.') + // set relevant digits to 0 + for i := 0; i < 10-len(bz); i++ { + bzWDec[i+2] = byte('0') + } + // set last few digits + copy(bzWDec[2+(10-len(bz)):], bz) + } else { + bzWDec = make([]byte, len(bz)+1) + copy(bzWDec, bz[:len(bz)-10]) + bzWDec[len(bz)-10] = byte('.') + copy(bzWDec[len(bz)-9:], bz[len(bz)-10:]) + } + return json.Marshal(string(bzWDec)) } // UnmarshalJSON defines custom decoding scheme @@ -431,7 +450,13 @@ func (d *Dec) UnmarshalJSON(bz []byte) error { if err != nil { return err } - return d.Int.UnmarshalText([]byte(text)) + // TODO: Reuse dec allocation + newDec, err := NewDecFromStr(text) + if err != nil { + return err + } + d.Int = newDec.Int + return nil } //___________________________________________________________________________________ diff --git a/types/decimal_test.go b/types/decimal_test.go index a6ec0740e8..73a00f60ab 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -4,6 +4,8 @@ import ( "math/big" "testing" + "github.com/stretchr/testify/assert" + "github.com/cosmos/cosmos-sdk/codec" "github.com/stretchr/testify/require" ) @@ -248,6 +250,44 @@ func TestToLeftPadded(t *testing.T) { var cdc = codec.New() +func TestDecMarshalJSON(t *testing.T) { + decimal := func(i int64) Dec { + d := NewDec(0) + d.Int = new(big.Int).SetInt64(i) + return d + } + tests := []struct { + name string + d Dec + want string + wantErr bool // if wantErr = false, will also attempt unmarshaling + }{ + {"zero", decimal(0), "\"0.0000000000\"", false}, + {"one", decimal(1), "\"0.0000000001\"", false}, + {"ten", decimal(10), "\"0.0000000010\"", false}, + {"12340", decimal(12340), "\"0.0000012340\"", false}, + {"zeroInt", NewDec(0), "\"0.0000000000\"", false}, + {"oneInt", NewDec(1), "\"1.0000000000\"", false}, + {"tenInt", NewDec(10), "\"10.0000000000\"", false}, + {"12340Int", NewDec(12340), "\"12340.0000000000\"", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.d.MarshalJSON() + if (err != nil) != tt.wantErr { + t.Errorf("Dec.MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + assert.Equal(t, tt.want, string(got), "incorrect marshalled value") + unmarshalledDec := NewDec(0) + unmarshalledDec.UnmarshalJSON(got) + assert.Equal(t, tt.d, unmarshalledDec, "incorrect unmarshalled value") + } + }) + } +} + func TestZeroDeserializationJSON(t *testing.T) { d := Dec{new(big.Int)} err := cdc.UnmarshalJSON([]byte(`"0"`), &d) From 8d59b51dfe94664641746cb6734a0f6fcd528310 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Tue, 16 Oct 2018 21:49:29 -0700 Subject: [PATCH 02/13] fix the weird non-alphanumeric key issue --- x/distribution/keeper/key.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/distribution/keeper/key.go b/x/distribution/keeper/key.go index 2e59890810..d139f02b87 100644 --- a/x/distribution/keeper/key.go +++ b/x/distribution/keeper/key.go @@ -13,9 +13,9 @@ var ( ProposerKey = []byte{0x04} // key for storing the proposer operator address // params store - ParamStoreKeyCommunityTax = []byte("community-tax") - ParamStoreKeyBaseProposerReward = []byte("base-proposer-reward") - ParamStoreKeyBonusProposerReward = []byte("bonus-proposer-reward") + ParamStoreKeyCommunityTax = []byte("CommunityTax") + ParamStoreKeyBaseProposerReward = []byte("BaseProposerReward") + ParamStoreKeyBonusProposerReward = []byte("BonusProposerReward") ) const ( From 15371dc36405dbb384c7978a709b3da7afaa0c5f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sat, 20 Oct 2018 20:31:20 +0200 Subject: [PATCH 03/13] Validator redelegation endpoint and querier --- x/stake/client/rest/query.go | 38 ++++++++++------------------------- x/stake/client/rest/utils.go | 30 +++++++++++++++++++++++++++ x/stake/querier/queryable.go | 39 +++++++++++++++++++++++++++--------- 3 files changed, 71 insertions(+), 36 deletions(-) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 0398119d82..fbe48d1681 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/utils" "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/gorilla/mux" @@ -67,6 +66,12 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co validatorHandlerFn(cliCtx, cdc), ).Methods("GET") + // Get all outgoing redelegations from a validator + r.HandleFunc( + "/stake/validators/{validatorAddr}/redelegations", + validatorRedelegationsHandlerFn(cliCtx, cdc), + ).Methods("GET") + // Get the current state of the staking pool r.HandleFunc( "/stake/pool", @@ -191,33 +196,12 @@ func validatorsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Handl // HTTP request handler to query the validator information from a given validator address func validatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - bech32validatorAddr := vars["validatorAddr"] + return queryValidator(cliCtx, cdc, "custom/stake/validator") +} - validatorAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr) - if err != nil { - utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - params := stake.QueryValidatorParams{ - ValidatorAddr: validatorAddr, - } - - bz, err := cdc.MarshalJSON(params) - if err != nil { - utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - res, err := cliCtx.QueryWithData("custom/stake/validator", bz) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) - } +// HTTP request handler to query all redelegations from a source validator +func validatorRedelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { + return queryValidator(cliCtx, cdc, "custom/stake/validatorRedelegations") } // HTTP request handler to query the pool information diff --git a/x/stake/client/rest/utils.go b/x/stake/client/rest/utils.go index 477432032a..bb986c3147 100644 --- a/x/stake/client/rest/utils.go +++ b/x/stake/client/rest/utils.go @@ -111,3 +111,33 @@ func queryDelegator(cliCtx context.CLIContext, cdc *codec.Codec, endpoint string utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) } } + +func queryValidator(cliCtx context.CLIContext, cdc *codec.Codec, endpoint string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + bech32validatorAddr := vars["validatorAddr"] + + validatorAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + params := stake.QueryValidatorParams{ + ValidatorAddr: validatorAddr, + } + + bz, err := cdc.MarshalJSON(params) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + res, err := cliCtx.QueryWithData(endpoint, bz) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) + } +} diff --git a/x/stake/querier/queryable.go b/x/stake/querier/queryable.go index 7cf01d0d3f..2d54de976d 100644 --- a/x/stake/querier/queryable.go +++ b/x/stake/querier/queryable.go @@ -10,15 +10,16 @@ import ( // 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" + QueryValidators = "validators" + QueryValidator = "validator" + QueryValidatorRedelegations = "validatorRedelegations" + QueryDelegator = "delegator" + QueryDelegation = "delegation" + QueryUnbondingDelegation = "unbondingDelegation" + QueryDelegatorValidators = "delegatorValidators" + QueryDelegatorValidator = "delegatorValidator" + QueryPool = "pool" + QueryParameters = "parameters" ) // creates a querier for staking REST endpoints @@ -29,6 +30,8 @@ func NewQuerier(k keep.Keeper, cdc *codec.Codec) sdk.Querier { return queryValidators(ctx, cdc, k) case QueryValidator: return queryValidator(ctx, cdc, req, k) + case QueryValidatorRedelegations: + return queryValidatorRedelegations(ctx, cdc, req, k) case QueryDelegator: return queryDelegator(ctx, cdc, req, k) case QueryDelegation: @@ -58,6 +61,7 @@ type QueryDelegatorParams struct { // defines the params for the following queries: // - 'custom/stake/validator' +// - 'custom/stake/validatorRedelegations' type QueryValidatorParams struct { ValidatorAddr sdk.ValAddress } @@ -102,6 +106,23 @@ func queryValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k return res, nil } +func queryValidatorRedelegations(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("") + } + + redelegations := k.GetRedelegationsFromValidator(ctx, params.ValidatorAddr) + + res, errRes = codec.MarshalJSONIndent(cdc, redelegations) + if errRes != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", 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) From 9cdd2d07efdeee74951d44dcdeafc76022d7722a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sat, 20 Oct 2018 20:38:07 +0200 Subject: [PATCH 04/13] PENDING and minor querier test --- PENDING.md | 1 + x/stake/querier/queryable_test.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/PENDING.md b/PENDING.md index 3a92041c33..fa5ff24976 100644 --- a/PENDING.md +++ b/PENDING.md @@ -107,6 +107,7 @@ FEATURES * [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint. * [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}` * [gaia-lite] [\#2478](https://github.com/cosmos/cosmos-sdk/issues/2478) Add query gov proposal's deposits endpoint + * [gaia-lite] [\#2477](https://github.com/cosmos/cosmos-sdk/issues/2477) Add query validator's outgoing redelegations endpoint * Gaia CLI (`gaiacli`) * [cli] Cmds to query staking pool and params diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go index 1d76da90d7..c4b1fc21da 100644 --- a/x/stake/querier/queryable_test.go +++ b/x/stake/querier/queryable_test.go @@ -81,6 +81,9 @@ func TestNewQuerier(t *testing.T) { _, err = querier(ctx, []string{"validator"}, query) require.Nil(t, err) + + _, err = querier(ctx, []string{"validatorRedelegations"}, query) + require.Nil(t, err) } func TestQueryParametersPool(t *testing.T) { From 5e1720b6cb3b8b13f6a2f1d82f8dff7186d3d0d9 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sat, 20 Oct 2018 21:10:19 +0200 Subject: [PATCH 05/13] Added LCD tests --- client/lcd/lcd_test.go | 73 ++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index d4d038016e..0adbc5fa1e 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -11,7 +11,6 @@ import ( "time" "github.com/spf13/viper" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" p2p "github.com/tendermint/tendermint/p2p" @@ -77,7 +76,7 @@ func TestKeys(t *testing.T) { // test if created account is the correct account expectedInfo, _ := GetKeyBase(t).CreateKey(newName, seed, newPassword) expectedAccount := sdk.AccAddress(expectedInfo.GetPubKey().Address().Bytes()) - assert.Equal(t, expectedAccount.String(), addr2Bech32) + require.Equal(t, expectedAccount.String(), addr2Bech32) // existing keys res, body = Request(t, port, "GET", "/keys", nil) @@ -511,7 +510,7 @@ func TestValidatorQuery(t *testing.T) { require.Equal(t, 1, len(operAddrs)) validator := getValidator(t, port, operAddrs[0]) - assert.Equal(t, validator.OperatorAddr, operAddrs[0], "The returned validator does not hold the correct data") + require.Equal(t, validator.OperatorAddr, operAddrs[0], "The returned validator does not hold the correct data") } func TestBonding(t *testing.T) { @@ -557,11 +556,10 @@ func TestBonding(t *testing.T) { bondedValidator := getDelegatorValidator(t, port, addr, operAddrs[0]) require.Equal(t, operAddrs[0], bondedValidator.OperatorAddr) - ////////////////////// // testing unbonding // create unbond TX - resultTx = doBeginUnbonding(t, port, seed, name, password, addr, operAddrs[0], 60) + resultTx = doBeginUnbonding(t, port, seed, name, password, addr, operAddrs[0], 30) tests.WaitForHeight(resultTx.Height+1, port) require.Equal(t, uint32(0), resultTx.CheckTx.Code) @@ -573,33 +571,47 @@ func TestBonding(t *testing.T) { require.Equal(t, int64(40), coins.AmountOf("steak").Int64()) unbonding := getUndelegation(t, port, addr, operAddrs[0]) - require.Equal(t, "60", unbonding.Balance.Amount.String()) + require.Equal(t, "30", unbonding.Balance.Amount.String()) + + // test redelegation + resultTx = doBeginRedelegation(t, port, seed, name, password, addr, operAddrs[0], operAddrs[1], 30) + tests.WaitForHeight(resultTx.Height+1, port) + + require.Equal(t, uint32(0), resultTx.CheckTx.Code) + require.Equal(t, uint32(0), resultTx.DeliverTx.Code) summary = getDelegationSummary(t, port, addr) - require.Len(t, summary.Delegations, 0, "Delegation summary holds all delegations") + require.Len(t, summary.Delegations, 1, "Delegation summary holds all delegations") require.Len(t, summary.UnbondingDelegations, 1, "Delegation summary holds all unbonding-delegations") - require.Equal(t, "60", summary.UnbondingDelegations[0].Balance.Amount.String()) + require.Len(t, summary.Redelegations, 1, "Delegation summary holds all redelegations") + + require.Equal(t, "30.0000000000", summary.Delegations[0].GetShares().String()) + require.Equal(t, "30", summary.UnbondingDelegations[0].Balance.Amount.String()) + require.Equal(t, "30", summary.Redelegations[0].Balance.Amount.String()) + + validatorReds := getValidatorRedelegations(t, port, operAddrs[0]) + require.Len(t, validatorReds, 1) + require.Equal(t, "30", validatorReds[0].Balance.Amount.String()) bondedValidators = getDelegatorValidators(t, port, addr) - require.Len(t, bondedValidators, 0, "There's no delegation as the user withdraw all funds") + require.Len(t, bondedValidators, 1, "There's a delegation as the user only withdraw half of the funds") // TODO Undonding status not currently implemented // require.Equal(t, sdk.Unbonding, bondedValidators[0].Status) - // TODO add redelegation, need more complex capabilities such to mock context and - // TODO check summary for redelegation - // assert.Len(t, summary.Redelegations, 1, "Delegation summary holds all redelegations") - // query txs txs := getBondingTxs(t, port, addr, "") - assert.Len(t, txs, 2, "All Txs found") + require.Len(t, txs, 3, "All Txs found") txs = getBondingTxs(t, port, addr, "bond") - assert.Len(t, txs, 1, "All bonding txs found") + require.Len(t, txs, 1, "All bonding txs found") txs = getBondingTxs(t, port, addr, "unbond") - assert.Len(t, txs, 1, "All unbonding txs found") + require.Len(t, txs, 1, "All unbonding txs found") + + txs = getBondingTxs(t, port, addr, "redelegate") + require.Len(t, txs, 1, "All redelegation txs found") } func TestSubmitProposal(t *testing.T) { @@ -974,11 +986,11 @@ func getUndelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, va 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 - err := cdc.UnmarshalJSON([]byte(body), &unbondings) + var unbond stake.UnbondingDelegation + err := cdc.UnmarshalJSON([]byte(body), &unbond) require.Nil(t, err) - return unbondings + return unbond } func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) stake.DelegationSummary { @@ -1052,9 +1064,7 @@ func doDelegate(t *testing.T, port, seed, name, password string, } ], "begin_unbondings": [], - "complete_unbondings": [], "begin_redelegates": [], - "complete_redelegates": [], "base_req": { "name": "%s", "password": "%s", @@ -1091,9 +1101,7 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, "shares": "%d" } ], - "complete_unbondings": [], "begin_redelegates": [], - "complete_redelegates": [], "base_req": { "name": "%s", "password": "%s", @@ -1114,7 +1122,7 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, } func doBeginRedelegation(t *testing.T, port, seed, name, password string, - delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (resultTx ctypes.ResultBroadcastTxCommit) { + delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) { acc := getAccount(t, port, delAddr) accnum := acc.GetAccountNumber() @@ -1125,16 +1133,14 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, jsonStr := []byte(fmt.Sprintf(`{ "delegations": [], "begin_unbondings": [], - "complete_unbondings": [], "begin_redelegates": [ { "delegator_addr": "%s", "validator_src_addr": "%s", "validator_dst_addr": "%s", - "shares": "30" + "shares": "%d" } ], - "complete_redelegates": [], "base_req": { "name": "%s", "password": "%s", @@ -1142,7 +1148,7 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, "account_number":"%d", "sequence":"%d" } - }`, delAddr, valSrcAddr, valDstAddr, name, password, chainID, accnum, sequence)) + }`, delAddr, valSrcAddr, valDstAddr, amount, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -1176,6 +1182,17 @@ func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake return validator } +func getValidatorRedelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.Redelegation { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/redelegations", validatorAddr.String()), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var reds []stake.Redelegation + err := cdc.UnmarshalJSON([]byte(body), &reds) + require.Nil(t, err) + + return reds +} + // ============= Governance Module ================ func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal { From 8999a4d719bf6e45aebf7e926b5d252147b65110 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sat, 20 Oct 2018 21:30:07 +0200 Subject: [PATCH 06/13] Add validator unbonds --- client/lcd/lcd_test.go | 15 +++++++++++ x/stake/client/rest/query.go | 11 +++++++++ x/stake/querier/queryable.go | 41 +++++++++++++++++++++++-------- x/stake/querier/queryable_test.go | 3 +++ 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 0adbc5fa1e..a173ac0e27 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -590,6 +590,10 @@ func TestBonding(t *testing.T) { require.Equal(t, "30", summary.UnbondingDelegations[0].Balance.Amount.String()) require.Equal(t, "30", summary.Redelegations[0].Balance.Amount.String()) + validatorUbds := getValidatorUnbondingDelegations(t, port, operAddrs[0]) + require.Len(t, validatorUbds, 1) + require.Equal(t, "30", validatorUbds[0].Balance.Amount.String()) + validatorReds := getValidatorRedelegations(t, port, operAddrs[0]) require.Len(t, validatorReds, 1) require.Equal(t, "30", validatorReds[0].Balance.Amount.String()) @@ -1182,6 +1186,17 @@ func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake return validator } +func getValidatorUnbondingDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.UnbondingDelegation { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/unbonding_delegations", validatorAddr.String()), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var ubds []stake.UnbondingDelegation + err := cdc.UnmarshalJSON([]byte(body), &ubds) + require.Nil(t, err) + + return ubds +} + func getValidatorRedelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.Redelegation { res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/redelegations", validatorAddr.String()), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index fbe48d1681..14de0b8e81 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -66,6 +66,12 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co validatorHandlerFn(cliCtx, cdc), ).Methods("GET") + // Get all unbonding delegations from a validator + r.HandleFunc( + "/stake/validators/{validatorAddr}/unbonding_delegations", + validatorUnbondingDelegationsHandlerFn(cliCtx, cdc), + ).Methods("GET") + // Get all outgoing redelegations from a validator r.HandleFunc( "/stake/validators/{validatorAddr}/redelegations", @@ -199,6 +205,11 @@ func validatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Handle return queryValidator(cliCtx, cdc, "custom/stake/validator") } +// HTTP request handler to query all unbonding delegations from a validator +func validatorUnbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { + return queryValidator(cliCtx, cdc, "custom/stake/validatorUnbondingDelegations") +} + // HTTP request handler to query all redelegations from a source validator func validatorRedelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { return queryValidator(cliCtx, cdc, "custom/stake/validatorRedelegations") diff --git a/x/stake/querier/queryable.go b/x/stake/querier/queryable.go index 2d54de976d..ace001fce8 100644 --- a/x/stake/querier/queryable.go +++ b/x/stake/querier/queryable.go @@ -10,16 +10,17 @@ import ( // query endpoints supported by the staking Querier const ( - QueryValidators = "validators" - QueryValidator = "validator" - QueryValidatorRedelegations = "validatorRedelegations" - QueryDelegator = "delegator" - QueryDelegation = "delegation" - QueryUnbondingDelegation = "unbondingDelegation" - QueryDelegatorValidators = "delegatorValidators" - QueryDelegatorValidator = "delegatorValidator" - QueryPool = "pool" - QueryParameters = "parameters" + QueryValidators = "validators" + QueryValidator = "validator" + QueryValidatorUnbondingDelegations = "validatorUnbondingDelegations" + QueryValidatorRedelegations = "validatorRedelegations" + QueryDelegator = "delegator" + QueryDelegation = "delegation" + QueryUnbondingDelegation = "unbondingDelegation" + QueryDelegatorValidators = "delegatorValidators" + QueryDelegatorValidator = "delegatorValidator" + QueryPool = "pool" + QueryParameters = "parameters" ) // creates a querier for staking REST endpoints @@ -30,6 +31,8 @@ func NewQuerier(k keep.Keeper, cdc *codec.Codec) sdk.Querier { return queryValidators(ctx, cdc, k) case QueryValidator: return queryValidator(ctx, cdc, req, k) + case QueryValidatorUnbondingDelegations: + return queryValidatorUnbondingDelegations(ctx, cdc, req, k) case QueryValidatorRedelegations: return queryValidatorRedelegations(ctx, cdc, req, k) case QueryDelegator: @@ -61,6 +64,7 @@ type QueryDelegatorParams struct { // defines the params for the following queries: // - 'custom/stake/validator' +// - 'custom/stake/validatorUnbondingDelegations' // - 'custom/stake/validatorRedelegations' type QueryValidatorParams struct { ValidatorAddr sdk.ValAddress @@ -106,6 +110,23 @@ func queryValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k return res, nil } +func queryValidatorUnbondingDelegations(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("") + } + + unbonds := k.GetUnbondingDelegationsFromValidator(ctx, params.ValidatorAddr) + + res, errRes = codec.MarshalJSONIndent(cdc, unbonds) + if errRes != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) + } + return res, nil +} + func queryValidatorRedelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryValidatorParams diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go index c4b1fc21da..2a86084175 100644 --- a/x/stake/querier/queryable_test.go +++ b/x/stake/querier/queryable_test.go @@ -82,6 +82,9 @@ func TestNewQuerier(t *testing.T) { _, err = querier(ctx, []string{"validator"}, query) require.Nil(t, err) + _, err = querier(ctx, []string{"validatorUnbondingDelegations"}, query) + require.Nil(t, err) + _, err = querier(ctx, []string{"validatorRedelegations"}, query) require.Nil(t, err) } From 864d7b61a6d3f28ded87cd5c9796d64ddd1ea7ac Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sat, 20 Oct 2018 21:36:58 +0200 Subject: [PATCH 07/13] Update PENDING --- PENDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PENDING.md b/PENDING.md index fa5ff24976..7a4ae355e4 100644 --- a/PENDING.md +++ b/PENDING.md @@ -107,7 +107,7 @@ FEATURES * [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint. * [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}` * [gaia-lite] [\#2478](https://github.com/cosmos/cosmos-sdk/issues/2478) Add query gov proposal's deposits endpoint - * [gaia-lite] [\#2477](https://github.com/cosmos/cosmos-sdk/issues/2477) Add query validator's outgoing redelegations endpoint + * [gaia-lite] [\#2477](https://github.com/cosmos/cosmos-sdk/issues/2477) Add query validator's outgoing redelegations and unbonding delegations endpoints * Gaia CLI (`gaiacli`) * [cli] Cmds to query staking pool and params From c2d68928e7f7f9032f68282d118656d9507cd8d0 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Sat, 20 Oct 2018 13:32:43 -0700 Subject: [PATCH 08/13] Switch to new Decimal.String() implementation --- types/decimal.go | 74 ++++++++++++++++--------------------------- types/decimal_test.go | 18 ----------- 2 files changed, 27 insertions(+), 65 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index a3cd7cc0e3..b621acd516 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -248,29 +248,32 @@ func (d Dec) QuoInt(i Int) Dec { } func (d Dec) String() string { - str := d.ToLeftPaddedWithDecimals(Precision) - placement := len(str) - Precision - if placement < 0 { - panic("too few decimal digits") + bz, err := d.Int.MarshalText() + if err != nil { + return "" } - return str[:placement] + "." + str[placement:] -} - -// TODO panic if negative or if totalDigits < len(initStr)??? -// evaluate as an integer and return left padded string -func (d Dec) ToLeftPaddedWithDecimals(totalDigits int8) string { - intStr := d.Int.String() - fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` - return fmt.Sprintf(fcode, intStr) -} - -// TODO panic if negative or if totalDigits < len(initStr)??? -// evaluate as an integer and return left padded string -func (d Dec) ToLeftPadded(totalDigits int8) string { - chopped := chopPrecisionAndRoundNonMutative(d.Int) - intStr := chopped.String() - fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s` - return fmt.Sprintf(fcode, intStr) + var bzWDec []byte + // TODO: Remove trailing zeros + // case 1, purely decimal + if len(bz) <= 10 { + bzWDec = make([]byte, 12) + // 0. prefix + bzWDec[0] = byte('0') + bzWDec[1] = byte('.') + // set relevant digits to 0 + for i := 0; i < 10-len(bz); i++ { + bzWDec[i+2] = byte('0') + } + // set last few digits + copy(bzWDec[2+(10-len(bz)):], bz) + } else { + // len(bz) + 1 to account for the decimal point that is being added + bzWDec = make([]byte, len(bz)+1) + copy(bzWDec, bz[:len(bz)-10]) + bzWDec[len(bz)-10] = byte('.') + copy(bzWDec[len(bz)-9:], bz[len(bz)-10:]) + } + return string(bzWDec) } // ____ @@ -412,31 +415,8 @@ func (d Dec) MarshalJSON() ([]byte, error) { if d.Int == nil { return nilJSON, nil } - bz, err := d.Int.MarshalText() - if err != nil { - return nil, err - } - var bzWDec []byte - // TODO: Remove trailing zeros - // case 1, pure decimal - if len(bz) <= 10 { - bzWDec = make([]byte, 12) - // 0. prefix - bzWDec[0] = byte('0') - bzWDec[1] = byte('.') - // set relevant digits to 0 - for i := 0; i < 10-len(bz); i++ { - bzWDec[i+2] = byte('0') - } - // set last few digits - copy(bzWDec[2+(10-len(bz)):], bz) - } else { - bzWDec = make([]byte, len(bz)+1) - copy(bzWDec, bz[:len(bz)-10]) - bzWDec[len(bz)-10] = byte('.') - copy(bzWDec[len(bz)-9:], bz[len(bz)-10:]) - } - return json.Marshal(string(bzWDec)) + + return json.Marshal(d.String()) } // UnmarshalJSON defines custom decoding scheme diff --git a/types/decimal_test.go b/types/decimal_test.go index 73a00f60ab..07329c7dc7 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -230,24 +230,6 @@ func TestTruncate(t *testing.T) { } } -func TestToLeftPadded(t *testing.T) { - tests := []struct { - dec Dec - digits int8 - exp string - }{ - {mustNewDecFromStr(t, "33.3"), 8, "00000033"}, - {mustNewDecFromStr(t, "50"), 8, "00000050"}, - {mustNewDecFromStr(t, "333"), 8, "00000333"}, - {mustNewDecFromStr(t, "333"), 12, "000000000333"}, - {mustNewDecFromStr(t, "0.3333"), 8, "00000000"}, - } - for tcIndex, tc := range tests { - res := tc.dec.ToLeftPadded(tc.digits) - require.Equal(t, tc.exp, res, "incorrect left padding, tc %d", tcIndex) - } -} - var cdc = codec.New() func TestDecMarshalJSON(t *testing.T) { From 1a463eb056e6aaa566c94a4f16de7094891abd55 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Sat, 20 Oct 2018 18:02:17 -0700 Subject: [PATCH 09/13] make more clear --- types/decimal.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index b621acd516..c981f6dca6 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -253,25 +253,26 @@ func (d Dec) String() string { return "" } var bzWDec []byte + inputSize := len(bz) // TODO: Remove trailing zeros // case 1, purely decimal - if len(bz) <= 10 { + if inputSize <= 10 { bzWDec = make([]byte, 12) // 0. prefix bzWDec[0] = byte('0') bzWDec[1] = byte('.') // set relevant digits to 0 - for i := 0; i < 10-len(bz); i++ { + for i := 0; i < 10-inputSize; i++ { bzWDec[i+2] = byte('0') } // set last few digits - copy(bzWDec[2+(10-len(bz)):], bz) + copy(bzWDec[2+(10-inputSize):], bz) } else { - // len(bz) + 1 to account for the decimal point that is being added - bzWDec = make([]byte, len(bz)+1) - copy(bzWDec, bz[:len(bz)-10]) - bzWDec[len(bz)-10] = byte('.') - copy(bzWDec[len(bz)-9:], bz[len(bz)-10:]) + // inputSize + 1 to account for the decimal point that is being added + bzWDec = make([]byte, inputSize+1) + copy(bzWDec, bz[:inputSize-10]) + bzWDec[inputSize-10] = byte('.') + copy(bzWDec[inputSize-9:], bz[inputSize-10:]) } return string(bzWDec) } From 6014089fa1cd874fec10858edd1c83cb102b1f71 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sat, 20 Oct 2018 23:22:48 -0700 Subject: [PATCH 10/13] Rename AccountMapper to AccountKeeper Closes: #2540 --- cmd/gaia/app/app.go | 16 +++---- cmd/gaia/app/sim_test.go | 14 +++--- cmd/gaia/cmd/gaiadebug/hack.go | 12 ++--- docs/sdk/core/app3.md | 46 +++++++++---------- docs/sdk/core/examples/app3.go | 6 +-- docs/sdk/core/examples/app4.go | 14 +++--- docs/sdk/overview.md | 2 +- .../simple-governance/bridging-it-all.md | 6 +-- examples/basecoin/app/app.go | 14 +++--- examples/basecoin/app/app_test.go | 4 +- examples/basecoin/types/account.go | 2 +- examples/democoin/app/app.go | 14 +++--- examples/democoin/app/app_test.go | 4 +- examples/democoin/x/cool/app_test.go | 4 +- examples/democoin/x/cool/keeper.go | 2 +- examples/democoin/x/cool/keeper_test.go | 2 +- examples/democoin/x/pow/app_test.go | 4 +- examples/democoin/x/pow/handler_test.go | 2 +- examples/democoin/x/pow/keeper_test.go | 2 +- .../democoin/x/simplestake/keeper_test.go | 8 ++-- x/auth/ante.go | 6 +-- x/auth/ante_test.go | 20 ++++---- x/auth/context.go | 2 +- x/auth/mapper.go | 42 ++++++++--------- x/auth/mapper_test.go | 6 +-- x/bank/app_test.go | 2 +- x/bank/bench_test.go | 2 +- x/bank/keeper.go | 26 +++++------ x/bank/keeper_test.go | 28 +++++------ x/bank/simulation/invariants.go | 4 +- x/bank/simulation/msgs.go | 8 ++-- x/bank/simulation/sim_test.go | 2 +- x/distribution/keeper/test_common.go | 10 ++-- x/gov/keeper.go | 4 +- x/gov/simulation/sim_test.go | 2 +- x/gov/test_common.go | 2 +- x/ibc/app_test.go | 4 +- x/ibc/ibc_test.go | 4 +- x/mock/app.go | 16 +++---- x/mock/app_test.go | 2 +- x/mock/test_utils.go | 2 +- x/slashing/app_test.go | 2 +- x/slashing/test_common.go | 4 +- x/stake/app_test.go | 2 +- x/stake/keeper/test_common.go | 8 ++-- x/stake/simulation/invariants.go | 4 +- x/stake/simulation/msgs.go | 12 ++--- x/stake/simulation/sim_test.go | 4 +- 48 files changed, 204 insertions(+), 204 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 8fba41f600..f8d2bb410d 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -56,7 +56,7 @@ type GaiaApp struct { tkeyParams *sdk.TransientStoreKey // Manage getting and setting accounts - accountMapper auth.AccountMapper + accountKeeper auth.AccountKeeper feeCollectionKeeper auth.FeeCollectionKeeper bankKeeper bank.Keeper stakeKeeper stake.Keeper @@ -91,15 +91,15 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio tkeyParams: sdk.NewTransientStoreKey("transient_params"), } - // define the accountMapper - app.accountMapper = auth.NewAccountMapper( + // define the accountKeeper + app.accountKeeper = auth.NewAccountKeeper( app.cdc, app.keyAccount, // target store auth.ProtoBaseAccount, // prototype ) // add handlers - app.bankKeeper = bank.NewBaseKeeper(app.accountMapper) + app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper) app.feeCollectionKeeper = auth.NewFeeCollectionKeeper( app.cdc, app.keyFeeCollection, @@ -159,7 +159,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams) app.SetInitChainer(app.initChainer) app.SetBeginBlocker(app.BeginBlocker) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper)) app.MountStoresTransient(app.tkeyParams, app.tkeyStake, app.tkeyDistr) app.SetEndBlocker(app.EndBlocker) @@ -231,8 +231,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci // load the accounts for _, gacc := range genesisState.Accounts { acc := gacc.ToAccount() - acc.AccountNumber = app.accountMapper.GetNextAccountNumber(ctx) - app.accountMapper.SetAccount(ctx, acc) + acc.AccountNumber = app.accountKeeper.GetNextAccountNumber(ctx) + app.accountKeeper.SetAccount(ctx, acc) } // load the initial stake information @@ -299,7 +299,7 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val accounts = append(accounts, account) return false } - app.accountMapper.IterateAccounts(ctx, appendAccount) + app.accountKeeper.IterateAccounts(ctx, appendAccount) genState := NewGenesisState( accounts, stake.WriteGenesis(ctx, app.stakeKeeper), diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index e24919e102..19a1c4fe5c 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -106,23 +106,23 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage { func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation { return []simulation.WeightedOperation{ - {100, banksim.SingleInputSendMsg(app.accountMapper, app.bankKeeper)}, + {100, banksim.SingleInputSendMsg(app.accountKeeper, app.bankKeeper)}, {5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper)}, {100, govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper)}, - {100, stakesim.SimulateMsgCreateValidator(app.accountMapper, app.stakeKeeper)}, + {100, stakesim.SimulateMsgCreateValidator(app.accountKeeper, app.stakeKeeper)}, {5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)}, - {100, stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper)}, - {100, stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper)}, - {100, stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper)}, + {100, stakesim.SimulateMsgDelegate(app.accountKeeper, app.stakeKeeper)}, + {100, stakesim.SimulateMsgBeginUnbonding(app.accountKeeper, app.stakeKeeper)}, + {100, stakesim.SimulateMsgBeginRedelegate(app.accountKeeper, app.stakeKeeper)}, {100, slashingsim.SimulateMsgUnjail(app.slashingKeeper)}, } } func invariants(app *GaiaApp) []simulation.Invariant { return []simulation.Invariant{ - banksim.NonnegativeBalanceInvariant(app.accountMapper), + banksim.NonnegativeBalanceInvariant(app.accountKeeper), govsim.AllInvariants(), - stakesim.AllInvariants(app.bankKeeper, app.stakeKeeper, app.accountMapper), + stakesim.AllInvariants(app.bankKeeper, app.stakeKeeper, app.accountKeeper), slashingsim.AllInvariants(), } } diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index db22da0b52..734a83df30 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -138,7 +138,7 @@ type GaiaApp struct { tkeyParams *sdk.TransientStoreKey // Manage getting and setting accounts - accountMapper auth.AccountMapper + accountKeeper auth.AccountKeeper feeCollectionKeeper auth.FeeCollectionKeeper bankKeeper bank.Keeper stakeKeeper stake.Keeper @@ -165,15 +165,15 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp tkeyParams: sdk.NewTransientStoreKey("transient_params"), } - // define the accountMapper - app.accountMapper = auth.NewAccountMapper( + // define the accountKeeper + app.accountKeeper = auth.NewAccountKeeper( app.cdc, app.keyAccount, // target store auth.ProtoBaseAccount, // prototype ) // add handlers - app.bankKeeper = bank.NewBaseKeeper(app.accountMapper) + app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper) app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams) app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace), app.RegisterCodespace(stake.DefaultCodespace)) app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), app.RegisterCodespace(slashing.DefaultCodespace)) @@ -187,7 +187,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp app.SetInitChainer(app.initChainer) app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper)) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake, app.keySlashing, app.keyParams) app.MountStore(app.tkeyParams, sdk.StoreTypeTransient) err := app.LoadLatestVersion(app.keyMain) @@ -246,7 +246,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci // load the accounts for _, gacc := range genesisState.Accounts { acc := gacc.ToAccount() - app.accountMapper.SetAccount(ctx, acc) + app.accountKeeper.SetAccount(ctx, acc) } // load the initial stake information diff --git a/docs/sdk/core/app3.md b/docs/sdk/core/app3.md index 595a3694fa..2462e3e66a 100644 --- a/docs/sdk/core/app3.md +++ b/docs/sdk/core/app3.md @@ -86,7 +86,7 @@ type BaseAccount struct { It simply contains a field for each of the methods. -### AccountMapper +### AccountKeeper In previous apps using our `appAccount`, we handled marshaling/unmarshaling the account from the store ourselves, by performing @@ -95,36 +95,36 @@ to work with in our applications. In the SDK, we use the term `Mapper` to refer to an abstaction over a KVStore that handles marshalling and unmarshalling a particular data type to and from the underlying store. -The `x/auth` module provides an `AccountMapper` that allows us to get and +The `x/auth` module provides an `AccountKeeper` that allows us to get and set `Account` types to the store. Note the benefit of using the `Account` interface here - developers can implement their own account type that extends the `BaseAccount` to store additional data without requiring another lookup from the store. -Creating an AccountMapper is easy - we just need to specify a codec, a +Creating an AccountKeeper is easy - we just need to specify a codec, a capability key, and a prototype of the object being encoded ```go -accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount) +accountKeeper := auth.NewAccountKeeper(cdc, keyAccount, auth.ProtoBaseAccount) ``` Then we can get, modify, and set accounts. For instance, we could double the amount of coins in an account: ```go -acc := accountMapper.GetAccount(ctx, addr) +acc := accountKeeper.GetAccount(ctx, addr) acc.SetCoins(acc.Coins.Plus(acc.Coins)) -accountMapper.SetAccount(ctx, addr) +accountKeeper.SetAccount(ctx, addr) ``` -Note that the `AccountMapper` takes a `Context` as the first argument, and will +Note that the `AccountKeeper` takes a `Context` as the first argument, and will load the KVStore from there using the capability key it was granted on creation. Also note that you must explicitly call `SetAccount` after mutating an account for the change to persist! -See the [AccountMapper API -docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth#AccountMapper) for more information. +See the [AccountKeeper API +docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth#AccountKeeper) for more information. ## StdTx @@ -224,10 +224,10 @@ all the relevant information. As we saw in `App2`, we can use an `AnteHandler` to authenticate transactions before we handle any of their internal messages. While previously we implemented our own simple `AnteHandler`, the `x/auth` module provides a much more advanced -one that uses `AccountMapper` and works with `StdTx`: +one that uses `AccountKeeper` and works with `StdTx`: ```go -app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) +app.SetAnteHandler(auth.NewAnteHandler(accountKeeper, feeKeeper)) ``` The AnteHandler provided by `x/auth` enforces the following rules: @@ -263,7 +263,7 @@ The fee is paid by the first address returned by `msg.GetSigners()` for the firs ## CoinKeeper -Now that we've seen the `auth.AccountMapper` and how its used to build a +Now that we've seen the `auth.AccountKeeper` and how its used to build a complete AnteHandler, it's time to look at how to build higher-level abstractions for taking action on accounts. @@ -274,26 +274,26 @@ which expose only limitted functionality on the underlying types stored by the ` For instance, the `x/bank` module defines the canonical versions of `MsgSend` and `MsgIssue` for the SDK, as well as a `Handler` for processing them. However, -rather than passing a `KVStore` or even an `AccountMapper` directly to the handler, +rather than passing a `KVStore` or even an `AccountKeeper` directly to the handler, we introduce a `bank.Keeper`, which can only be used to transfer coins in and out of accounts. This allows us to determine up front that the only effect the bank module's `Handler` can have on the store is to change the amount of coins in an account - it can't increment sequence numbers, change PubKeys, or otherwise. -A `bank.Keeper` is easily instantiated from an `AccountMapper`: +A `bank.Keeper` is easily instantiated from an `AccountKeeper`: ```go -bankKeeper = bank.NewBaseKeeper(accountMapper) +bankKeeper = bank.NewBaseKeeper(accountKeeper) ``` We can then use it within a handler, instead of working directly with the -`AccountMapper`. For instance, to add coins to an account: +`AccountKeeper`. For instance, to add coins to an account: ```go -// Finds account with addr in AccountMapper. +// Finds account with addr in AccountKeeper. // Adds coins to account's coin array. -// Sets updated account in AccountMapper +// Sets updated account in AccountKeeper app.bankKeeper.AddCoins(ctx, addr, coins) ``` @@ -311,12 +311,12 @@ accounts. We use this `Keeper` paradigm extensively in the SDK as the way to define what kind of functionality each module gets access to. In particular, we try to follow the *principle of least authority*. -Rather than providing full blown access to the `KVStore` or the `AccountMapper`, +Rather than providing full blown access to the `KVStore` or the `AccountKeeper`, we restrict access to a small number of functions that do very specific things. ## App3 -With the `auth.AccountMapper` and `bank.Keeper` in hand, +With the `auth.AccountKeeper` and `bank.Keeper` in hand, we're now ready to build `App3`. The `x/auth` and `x/bank` modules do all the heavy lifting: @@ -334,11 +334,11 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { keyFees := sdk.NewKVStoreKey("fee") // TODO // Set various mappers/keepers to interact easily with underlying stores - accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountMapper) + accountKeeper := auth.NewAccountKeeper(cdc, keyAccount, auth.ProtoBaseAccount) + bankKeeper := bank.NewBaseKeeper(accountKeeper) feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) - app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) + app.SetAnteHandler(auth.NewAnteHandler(accountKeeper, feeKeeper)) // Register message routes. // Note the handler gets access to diff --git a/docs/sdk/core/examples/app3.go b/docs/sdk/core/examples/app3.go index 9a101c2816..453970c1af 100644 --- a/docs/sdk/core/examples/app3.go +++ b/docs/sdk/core/examples/app3.go @@ -30,11 +30,11 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { keyFees := sdk.NewKVStoreKey("fee") // TODO // Set various mappers/keepers to interact easily with underlying stores - accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountMapper) + accountKeeper := auth.NewAccountKeeper(cdc, keyAccount, auth.ProtoBaseAccount) + bankKeeper := bank.NewBaseKeeper(accountKeeper) feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) - app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) + app.SetAnteHandler(auth.NewAnteHandler(accountKeeper, feeKeeper)) // Register message routes. // Note the handler gets access to diff --git a/docs/sdk/core/examples/app4.go b/docs/sdk/core/examples/app4.go index e4fa515ee2..6d45c40315 100644 --- a/docs/sdk/core/examples/app4.go +++ b/docs/sdk/core/examples/app4.go @@ -28,17 +28,17 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { keyAccount := sdk.NewKVStoreKey("acc") // Set various mappers/keepers to interact easily with underlying stores - accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountMapper) + accountKeeper := auth.NewAccountKeeper(cdc, keyAccount, auth.ProtoBaseAccount) + bankKeeper := bank.NewBaseKeeper(accountKeeper) // TODO keyFees := sdk.NewKVStoreKey("fee") feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) - app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) + app.SetAnteHandler(auth.NewAnteHandler(accountKeeper, feeKeeper)) // Set InitChainer - app.SetInitChainer(NewInitChainer(cdc, accountMapper)) + app.SetInitChainer(NewInitChainer(cdc, accountKeeper)) // Register message routes. // Note the handler gets access to the account store. @@ -76,7 +76,7 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount, err error) { // InitChainer will set initial balances for accounts as well as initial coin metadata // MsgIssue can no longer be used to create new coin -func NewInitChainer(cdc *codec.Codec, accountMapper auth.AccountMapper) sdk.InitChainer { +func NewInitChainer(cdc *codec.Codec, accountKeeper auth.AccountKeeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { stateJSON := req.AppStateBytes @@ -91,8 +91,8 @@ func NewInitChainer(cdc *codec.Codec, accountMapper auth.AccountMapper) sdk.Init if err != nil { panic(err) } - acc.AccountNumber = accountMapper.GetNextAccountNumber(ctx) - accountMapper.SetAccount(ctx, acc) + acc.AccountNumber = accountKeeper.GetNextAccountNumber(ctx) + accountKeeper.SetAccount(ctx, acc) } return abci.ResponseInitChain{} diff --git a/docs/sdk/overview.md b/docs/sdk/overview.md index 905982f621..70e826c60a 100644 --- a/docs/sdk/overview.md +++ b/docs/sdk/overview.md @@ -127,7 +127,7 @@ func (app *BasecoinApp) initRouterHandlers() { // All handlers must be added here. // The order matters. - app.router.AddRoute("bank", bank.NewHandler(app.accountMapper)) + app.router.AddRoute("bank", bank.NewHandler(app.accountKeeper)) app.router.AddRoute("sketchy", sketchy.NewHandler()) } ``` diff --git a/docs/sdk/sdk-by-examples/simple-governance/bridging-it-all.md b/docs/sdk/sdk-by-examples/simple-governance/bridging-it-all.md index aed6de85ef..546eb7d875 100644 --- a/docs/sdk/sdk-by-examples/simple-governance/bridging-it-all.md +++ b/docs/sdk/sdk-by-examples/simple-governance/bridging-it-all.md @@ -45,7 +45,7 @@ type SimpleGovApp struct { simpleGovKeeper simpleGov.Keeper // Manage getting and setting accounts - accountMapper auth.AccountMapper + accountKeeper auth.AccountKeeper } ``` @@ -206,7 +206,7 @@ var cdc = MakeCodec() - Instantiate the keepers. Note that keepers generally need access to other module's keepers. In this case, make sure you only pass an instance of the keeper for the functionality that is needed. If a keeper only needs to read in another module's store, a read-only keeper should be passed to it. ```go -app.bankKeeper = bank.NewBaseKeeper(app.accountMapper) +app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper) app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper,app.RegisterCodespace(simplestake.DefaultCodespace)) app.simpleGovKeeper = simpleGov.NewKeeper(app.capKeySimpleGovStore, app.bankKeeper, app.stakeKeeper, app.RegisterCodespace(simpleGov.DefaultCodespace)) ``` @@ -225,7 +225,7 @@ app.Router(). ```go // Initialize BaseApp. app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeySimpleGovStore, app.capKeyStakingStore) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper)) err := app.LoadLatestVersion(app.capKeyMainStore) if err != nil { cmn.Exit(err.Error()) diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index 3d9ac81736..286afd003e 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -42,7 +42,7 @@ type BasecoinApp struct { keyIBC *sdk.KVStoreKey // manage getting and setting accounts - accountMapper auth.AccountMapper + accountKeeper auth.AccountKeeper feeCollectionKeeper auth.FeeCollectionKeeper bankKeeper bank.Keeper ibcMapper ibc.Mapper @@ -67,14 +67,14 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.Ba } // define and attach the mappers and keepers - app.accountMapper = auth.NewAccountMapper( + app.accountKeeper = auth.NewAccountKeeper( cdc, app.keyAccount, // target store func() auth.Account { return &types.AppAccount{} }, ) - app.bankKeeper = bank.NewBaseKeeper(app.accountMapper) + app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper) app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) // register message routes @@ -86,7 +86,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.Ba app.SetInitChainer(app.initChainer) app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper)) // mount the multistore and load the latest state app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC) @@ -153,8 +153,8 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) panic(err) } - acc.AccountNumber = app.accountMapper.GetNextAccountNumber(ctx) - app.accountMapper.SetAccount(ctx, acc) + acc.AccountNumber = app.accountKeeper.GetNextAccountNumber(ctx) + app.accountKeeper.SetAccount(ctx, acc) } return abci.ResponseInitChain{} @@ -177,7 +177,7 @@ func (app *BasecoinApp) ExportAppStateAndValidators() (appState json.RawMessage, return false } - app.accountMapper.IterateAccounts(ctx, appendAccountsFn) + app.accountKeeper.IterateAccounts(ctx, appendAccountsFn) genState := types.GenesisState{Accounts: accounts} appState, err = codec.MarshalJSONIndent(app.cdc, genState) diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index da544f4803..c49d5d4768 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -61,7 +61,7 @@ func TestGenesis(t *testing.T) { // create a context for the BaseApp ctx := baseApp.BaseApp.NewContext(true, abci.Header{}) - res := baseApp.accountMapper.GetAccount(ctx, baseAcct.Address) + res := baseApp.accountKeeper.GetAccount(ctx, baseAcct.Address) require.Equal(t, appAcct, res) // reload app and ensure the account is still there @@ -76,6 +76,6 @@ func TestGenesis(t *testing.T) { }) ctx = baseApp.BaseApp.NewContext(true, abci.Header{}) - res = baseApp.accountMapper.GetAccount(ctx, baseAcct.Address) + res = baseApp.accountKeeper.GetAccount(ctx, baseAcct.Address) require.Equal(t, appAcct, res) } diff --git a/examples/basecoin/types/account.go b/examples/basecoin/types/account.go index 04d3e371ef..41b4377180 100644 --- a/examples/basecoin/types/account.go +++ b/examples/basecoin/types/account.go @@ -10,7 +10,7 @@ var _ auth.Account = (*AppAccount)(nil) // AppAccount is a custom extension for this application. It is an example of // extending auth.BaseAccount with custom fields. It is compatible with the -// stock auth.AccountMapper, since auth.AccountMapper uses the flexible go-amino +// stock auth.AccountKeeper, since auth.AccountKeeper uses the flexible go-amino // library. type AppAccount struct { auth.BaseAccount diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 97dcf4e358..12f5d8d294 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -55,7 +55,7 @@ type DemocoinApp struct { stakeKeeper simplestake.Keeper // Manage getting and setting accounts - accountMapper auth.AccountMapper + accountKeeper auth.AccountKeeper } func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { @@ -74,15 +74,15 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { capKeyStakingStore: sdk.NewKVStoreKey("stake"), } - // Define the accountMapper. - app.accountMapper = auth.NewAccountMapper( + // Define the accountKeeper. + app.accountKeeper = auth.NewAccountKeeper( cdc, app.capKeyAccountStore, // target store types.ProtoAppAccount, // prototype ) // Add handlers. - app.bankKeeper = bank.NewBaseKeeper(app.accountMapper) + app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper) app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.bankKeeper, app.RegisterCodespace(cool.DefaultCodespace)) app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.bankKeeper, app.RegisterCodespace(pow.DefaultCodespace)) app.ibcMapper = ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace)) @@ -98,7 +98,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { // Initialize BaseApp. app.SetInitChainer(app.initChainerFn(app.coolKeeper, app.powKeeper)) app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper)) err := app.LoadLatestVersion(app.capKeyMainStore) if err != nil { cmn.Exit(err.Error()) @@ -148,7 +148,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "") } - app.accountMapper.SetAccount(ctx, acc) + app.accountKeeper.SetAccount(ctx, acc) } // Application specific genesis handling @@ -182,7 +182,7 @@ func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage, accounts = append(accounts, account) return false } - app.accountMapper.IterateAccounts(ctx, appendAccount) + app.accountKeeper.IterateAccounts(ctx, appendAccount) genState := types.GenesisState{ Accounts: accounts, diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index fc00651b8f..5b3be00e12 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -60,13 +60,13 @@ func TestGenesis(t *testing.T) { require.Nil(t, err) // A checkTx context ctx := bapp.BaseApp.NewContext(true, abci.Header{}) - res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address) + res1 := bapp.accountKeeper.GetAccount(ctx, baseAcc.Address) require.Equal(t, acc, res1) // reload app and ensure the account is still there bapp = NewDemocoinApp(logger, db) bapp.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}")}) ctx = bapp.BaseApp.NewContext(true, abci.Header{}) - res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address) + res1 = bapp.accountKeeper.GetAccount(ctx, baseAcc.Address) require.Equal(t, acc, res1) } diff --git a/examples/democoin/x/cool/app_test.go b/examples/democoin/x/cool/app_test.go index 35a656cebc..01cb73ef17 100644 --- a/examples/democoin/x/cool/app_test.go +++ b/examples/democoin/x/cool/app_test.go @@ -49,7 +49,7 @@ func getMockApp(t *testing.T) *mock.App { RegisterCodec(mapp.Cdc) keyCool := sdk.NewKVStoreKey("cool") - bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper) + bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper) keeper := NewKeeper(keyCool, bankKeeper, mapp.RegisterCodespace(DefaultCodespace)) mapp.Router().AddRoute("cool", NewHandler(keeper)) @@ -84,7 +84,7 @@ func TestMsgQuiz(t *testing.T) { // A checkTx context (true) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) + res1 := mapp.AccountKeeper.GetAccount(ctxCheck, addr1) require.Equal(t, acc1, res1) // Set the trend, submit a really cool quiz and check for reward diff --git a/examples/democoin/x/cool/keeper.go b/examples/democoin/x/cool/keeper.go index fef93b954d..f805ca880b 100644 --- a/examples/democoin/x/cool/keeper.go +++ b/examples/democoin/x/cool/keeper.go @@ -29,7 +29,7 @@ func (k Keeper) GetTrend(ctx sdk.Context) string { return string(bz) } -// Implements sdk.AccountMapper. +// Implements sdk.AccountKeeper. func (k Keeper) setTrend(ctx sdk.Context, newTrend string) { store := ctx.KVStore(k.storeKey) store.Set(trendKey, []byte(newTrend)) diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index e3af7790e4..1eb40dfb29 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -29,7 +29,7 @@ func TestCoolKeeper(t *testing.T) { cdc := codec.New() auth.RegisterBaseAccount(cdc) - am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount) + am := auth.NewAccountKeeper(cdc, capKey, auth.ProtoBaseAccount) ctx := sdk.NewContext(ms, abci.Header{}, false, nil) ck := bank.NewBaseKeeper(am) keeper := NewKeeper(capKey, ck, DefaultCodespace) diff --git a/examples/democoin/x/pow/app_test.go b/examples/democoin/x/pow/app_test.go index 6e6f07f770..5009b7ec54 100644 --- a/examples/democoin/x/pow/app_test.go +++ b/examples/democoin/x/pow/app_test.go @@ -25,7 +25,7 @@ func getMockApp(t *testing.T) *mock.App { RegisterCodec(mapp.Cdc) keyPOW := sdk.NewKVStoreKey("pow") - bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper) + bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper) config := Config{"pow", 1} keeper := NewKeeper(keyPOW, config, bankKeeper, mapp.RegisterCodespace(DefaultCodespace)) mapp.Router().AddRoute("pow", keeper.Handler) @@ -69,7 +69,7 @@ func TestMsgMine(t *testing.T) { // A checkTx context (true) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) + res1 := mapp.AccountKeeper.GetAccount(ctxCheck, addr1) require.Equal(t, acc1, res1) // Mine and check for reward diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index 8166ddfc53..ce398b7c28 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -19,7 +19,7 @@ func TestPowHandler(t *testing.T) { cdc := codec.New() auth.RegisterBaseAccount(cdc) - am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount) + am := auth.NewAccountKeeper(cdc, capKey, auth.ProtoBaseAccount) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) config := NewConfig("pow", int64(1)) ck := bank.NewBaseKeeper(am) diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index dbd974c4d0..86ccbc8c01 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -32,7 +32,7 @@ func TestPowKeeperGetSet(t *testing.T) { cdc := codec.New() auth.RegisterBaseAccount(cdc) - am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount) + am := auth.NewAccountKeeper(cdc, capKey, auth.ProtoBaseAccount) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) config := NewConfig("pow", int64(1)) ck := bank.NewBaseKeeper(am) diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index 68f28bd91b..c3876cf4ad 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -35,8 +35,8 @@ func TestKeeperGetSet(t *testing.T) { cdc := codec.New() auth.RegisterBaseAccount(cdc) - accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) - stakeKeeper := NewKeeper(capKey, bank.NewBaseKeeper(accountMapper), DefaultCodespace) + accountKeeper := auth.NewAccountKeeper(cdc, authKey, auth.ProtoBaseAccount) + stakeKeeper := NewKeeper(capKey, bank.NewBaseKeeper(accountKeeper), DefaultCodespace) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) addr := sdk.AccAddress([]byte("some-address")) @@ -65,8 +65,8 @@ func TestBonding(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountMapper) + accountKeeper := auth.NewAccountKeeper(cdc, authKey, auth.ProtoBaseAccount) + bankKeeper := bank.NewBaseKeeper(accountKeeper) stakeKeeper := NewKeeper(capKey, bankKeeper, DefaultCodespace) addr := sdk.AccAddress([]byte("some-address")) privKey := ed25519.GenPrivKey() diff --git a/x/auth/ante.go b/x/auth/ante.go index 3fd183a0ca..9d5bc50597 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -22,7 +22,7 @@ const ( // NewAnteHandler returns an AnteHandler that checks // and increments sequence numbers, checks signatures & account numbers, // and deducts fees from the first signer. -func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { +func NewAnteHandler(am AccountKeeper, fck FeeCollectionKeeper) sdk.AnteHandler { return func( ctx sdk.Context, tx sdk.Tx, simulate bool, ) (newCtx sdk.Context, res sdk.Result, abort bool) { @@ -137,7 +137,7 @@ func validateBasic(tx StdTx) (err sdk.Error) { return nil } -func getSignerAccs(ctx sdk.Context, am AccountMapper, addrs []sdk.AccAddress) (accs []Account, res sdk.Result) { +func getSignerAccs(ctx sdk.Context, am AccountKeeper, addrs []sdk.AccAddress) (accs []Account, res sdk.Result) { accs = make([]Account, len(addrs)) for i := 0; i < len(accs); i++ { accs[i] = am.GetAccount(ctx, addrs[i]) @@ -257,7 +257,7 @@ func adjustFeesByGas(fees sdk.Coins, gas int64) sdk.Coins { } // Deduct the fee from the account. -// We could use the CoinKeeper (in addition to the AccountMapper, +// We could use the CoinKeeper (in addition to the AccountKeeper, // because the CoinKeeper doesn't give us accounts), but it seems easier to do this. func deductFees(acc Account, fee StdFee) (Account, sdk.Result) { coins := acc.GetCoins() diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index bacb3013f9..d29b0bf50d 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -112,7 +112,7 @@ func TestAnteHandlerSigErrors(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -165,7 +165,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -225,7 +225,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -285,7 +285,7 @@ func TestAnteHandlerSequences(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -364,7 +364,7 @@ func TestAnteHandlerFees(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -406,7 +406,7 @@ func TestAnteHandlerMemoGas(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -450,7 +450,7 @@ func TestAnteHandlerMultiSigner(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -502,7 +502,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -584,7 +584,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -638,7 +638,7 @@ func TestProcessPubKey(t *testing.T) { ms, capKey, _ := setupMultiStore() cdc := codec.New() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) // keys _, addr1 := privAndAddr() diff --git a/x/auth/context.go b/x/auth/context.go index 40fb177858..28d159c972 100644 --- a/x/auth/context.go +++ b/x/auth/context.go @@ -8,7 +8,7 @@ import ( Usage: -var accounts types.AccountMapper +var accounts types.AccountKeeper // Fetch all signer accounts. addrs := tx.GetSigners() diff --git a/x/auth/mapper.go b/x/auth/mapper.go index 20d6c2d143..dd127c7312 100644 --- a/x/auth/mapper.go +++ b/x/auth/mapper.go @@ -8,9 +8,9 @@ import ( var globalAccountNumberKey = []byte("globalAccountNumber") -// This AccountMapper encodes/decodes accounts using the +// This AccountKeeper encodes/decodes accounts using the // go-amino (binary) encoding/decoding library. -type AccountMapper struct { +type AccountKeeper struct { // The (unexposed) key used to access the store from the Context. key sdk.StoreKey @@ -22,19 +22,19 @@ type AccountMapper struct { cdc *codec.Codec } -// NewAccountMapper returns a new sdk.AccountMapper that +// NewAccountKeeper returns a new sdk.AccountKeeper that // uses go-amino to (binary) encode and decode concrete sdk.Accounts. // nolint -func NewAccountMapper(cdc *codec.Codec, key sdk.StoreKey, proto func() Account) AccountMapper { - return AccountMapper{ +func NewAccountKeeper(cdc *codec.Codec, key sdk.StoreKey, proto func() Account) AccountKeeper { + return AccountKeeper{ key: key, proto: proto, cdc: cdc, } } -// Implaements sdk.AccountMapper. -func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) Account { +// Implaements sdk.AccountKeeper. +func (am AccountKeeper) NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) Account { acc := am.proto() err := acc.SetAddress(addr) if err != nil { @@ -50,7 +50,7 @@ func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddre } // New Account -func (am AccountMapper) NewAccount(ctx sdk.Context, acc Account) Account { +func (am AccountKeeper) NewAccount(ctx sdk.Context, acc Account) Account { err := acc.SetAccountNumber(am.GetNextAccountNumber(ctx)) if err != nil { // TODO: Handle with #870 @@ -64,8 +64,8 @@ func AddressStoreKey(addr sdk.AccAddress) []byte { return append([]byte("account:"), addr.Bytes()...) } -// Implements sdk.AccountMapper. -func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.AccAddress) Account { +// Implements sdk.AccountKeeper. +func (am AccountKeeper) GetAccount(ctx sdk.Context, addr sdk.AccAddress) Account { store := ctx.KVStore(am.key) bz := store.Get(AddressStoreKey(addr)) if bz == nil { @@ -75,8 +75,8 @@ func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.AccAddress) Account return acc } -// Implements sdk.AccountMapper. -func (am AccountMapper) SetAccount(ctx sdk.Context, acc Account) { +// Implements sdk.AccountKeeper. +func (am AccountKeeper) SetAccount(ctx sdk.Context, acc Account) { addr := acc.GetAddress() store := ctx.KVStore(am.key) bz := am.encodeAccount(acc) @@ -84,14 +84,14 @@ func (am AccountMapper) SetAccount(ctx sdk.Context, acc Account) { } // RemoveAccount removes an account for the account mapper store. -func (am AccountMapper) RemoveAccount(ctx sdk.Context, acc Account) { +func (am AccountKeeper) RemoveAccount(ctx sdk.Context, acc Account) { addr := acc.GetAddress() store := ctx.KVStore(am.key) store.Delete(AddressStoreKey(addr)) } -// Implements sdk.AccountMapper. -func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(Account) (stop bool)) { +// Implements sdk.AccountKeeper. +func (am AccountKeeper) IterateAccounts(ctx sdk.Context, process func(Account) (stop bool)) { store := ctx.KVStore(am.key) iter := sdk.KVStorePrefixIterator(store, []byte("account:")) defer iter.Close() @@ -109,7 +109,7 @@ func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(Account) ( } // Returns the PubKey of the account at address -func (am AccountMapper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto.PubKey, sdk.Error) { +func (am AccountKeeper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto.PubKey, sdk.Error) { acc := am.GetAccount(ctx, addr) if acc == nil { return nil, sdk.ErrUnknownAddress(addr.String()) @@ -118,7 +118,7 @@ func (am AccountMapper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto. } // Returns the Sequence of the account at address -func (am AccountMapper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (int64, sdk.Error) { +func (am AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (int64, sdk.Error) { acc := am.GetAccount(ctx, addr) if acc == nil { return 0, sdk.ErrUnknownAddress(addr.String()) @@ -126,7 +126,7 @@ func (am AccountMapper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (int64 return acc.GetSequence(), nil } -func (am AccountMapper) setSequence(ctx sdk.Context, addr sdk.AccAddress, newSequence int64) sdk.Error { +func (am AccountKeeper) setSequence(ctx sdk.Context, addr sdk.AccAddress, newSequence int64) sdk.Error { acc := am.GetAccount(ctx, addr) if acc == nil { return sdk.ErrUnknownAddress(addr.String()) @@ -141,7 +141,7 @@ func (am AccountMapper) setSequence(ctx sdk.Context, addr sdk.AccAddress, newSeq } // Returns and increments the global account number counter -func (am AccountMapper) GetNextAccountNumber(ctx sdk.Context) int64 { +func (am AccountKeeper) GetNextAccountNumber(ctx sdk.Context) int64 { var accNumber int64 store := ctx.KVStore(am.key) bz := store.Get(globalAccountNumberKey) @@ -163,7 +163,7 @@ func (am AccountMapper) GetNextAccountNumber(ctx sdk.Context) int64 { //---------------------------------------- // misc. -func (am AccountMapper) encodeAccount(acc Account) []byte { +func (am AccountKeeper) encodeAccount(acc Account) []byte { bz, err := am.cdc.MarshalBinaryBare(acc) if err != nil { panic(err) @@ -171,7 +171,7 @@ func (am AccountMapper) encodeAccount(acc Account) []byte { return bz } -func (am AccountMapper) decodeAccount(bz []byte) (acc Account) { +func (am AccountKeeper) decodeAccount(bz []byte) (acc Account) { err := am.cdc.UnmarshalBinaryBare(bz, &acc) if err != nil { panic(err) diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index e3b737ea3c..326f83dcca 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -32,7 +32,7 @@ func TestAccountMapperGetSet(t *testing.T) { // make context and mapper ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) addr := sdk.AccAddress([]byte("some-address")) @@ -68,7 +68,7 @@ func TestAccountMapperRemoveAccount(t *testing.T) { // make context and mapper ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) @@ -106,7 +106,7 @@ func BenchmarkAccountMapperGetAccountFound(b *testing.B) { // make context and mapper ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount) // assumes b.N < 2**24 for i := 0; i < b.N; i++ { diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 7c320a9bd0..906573eae2 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -102,7 +102,7 @@ func TestMsgSendWithAccounts(t *testing.T) { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) + res1 := mapp.AccountKeeper.GetAccount(ctxCheck, addr1) require.NotNil(t, res1) require.Equal(t, acc, res1.(*auth.BaseAccount)) diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index a29a25b999..bff99da996 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -16,7 +16,7 @@ func getBenchmarkMockApp() (*mock.App, error) { mapp := mock.NewApp() RegisterCodec(mapp.Cdc) - bankKeeper := NewBaseKeeper(mapp.AccountMapper) + bankKeeper := NewBaseKeeper(mapp.AccountKeeper) mapp.Router().AddRoute("bank", NewHandler(bankKeeper)) err := mapp.CompleteSetup() diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 2da4eedc8b..ac7a484d5e 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -29,11 +29,11 @@ var _ Keeper = (*BaseKeeper)(nil) // BaseKeeper manages transfers between accounts. It implements the Keeper // interface. type BaseKeeper struct { - am auth.AccountMapper + am auth.AccountKeeper } // NewBaseKeeper returns a new BaseKeeper -func NewBaseKeeper(am auth.AccountMapper) BaseKeeper { +func NewBaseKeeper(am auth.AccountKeeper) BaseKeeper { return BaseKeeper{am: am} } @@ -96,11 +96,11 @@ var _ SendKeeper = (*BaseSendKeeper)(nil) // SendKeeper only allows transfers between accounts without the possibility of // creating coins. It implements the SendKeeper interface. type BaseSendKeeper struct { - am auth.AccountMapper + am auth.AccountKeeper } // NewBaseSendKeeper returns a new BaseSendKeeper. -func NewBaseSendKeeper(am auth.AccountMapper) BaseSendKeeper { +func NewBaseSendKeeper(am auth.AccountKeeper) BaseSendKeeper { return BaseSendKeeper{am: am} } @@ -143,11 +143,11 @@ var _ ViewKeeper = (*BaseViewKeeper)(nil) // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { - am auth.AccountMapper + am auth.AccountKeeper } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper(am auth.AccountMapper) BaseViewKeeper { +func NewBaseViewKeeper(am auth.AccountKeeper) BaseViewKeeper { return BaseViewKeeper{am: am} } @@ -163,7 +163,7 @@ func (keeper BaseViewKeeper) HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt //______________________________________________________________________________________________ -func getCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress) sdk.Coins { +func getCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress) sdk.Coins { ctx.GasMeter().ConsumeGas(costGetCoins, "getCoins") acc := am.GetAccount(ctx, addr) if acc == nil { @@ -172,7 +172,7 @@ func getCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress) sdk.C return acc.GetCoins() } -func setCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress, amt sdk.Coins) sdk.Error { +func setCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) sdk.Error { ctx.GasMeter().ConsumeGas(costSetCoins, "setCoins") acc := am.GetAccount(ctx, addr) if acc == nil { @@ -188,13 +188,13 @@ func setCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress, amt s } // HasCoins returns whether or not an account has at least amt coins. -func hasCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress, amt sdk.Coins) bool { +func hasCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) bool { ctx.GasMeter().ConsumeGas(costHasCoins, "hasCoins") return getCoins(ctx, am, addr).IsGTE(amt) } // SubtractCoins subtracts amt from the coins at the addr. -func subtractCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { +func subtractCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { ctx.GasMeter().ConsumeGas(costSubtractCoins, "subtractCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Minus(amt) @@ -207,7 +207,7 @@ func subtractCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress, } // AddCoins adds amt to the coins at the addr. -func addCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { +func addCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { ctx.GasMeter().ConsumeGas(costAddCoins, "addCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Plus(amt) @@ -221,7 +221,7 @@ func addCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.AccAddress, amt s // SendCoins moves coins from one account to another // NOTE: Make sure to revert state changes from tx on error -func sendCoins(ctx sdk.Context, am auth.AccountMapper, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.Tags, sdk.Error) { +func sendCoins(ctx sdk.Context, am auth.AccountKeeper, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.Tags, sdk.Error) { _, subTags, err := subtractCoins(ctx, am, fromAddr, amt) if err != nil { return nil, err @@ -237,7 +237,7 @@ func sendCoins(ctx sdk.Context, am auth.AccountMapper, fromAddr sdk.AccAddress, // InputOutputCoins handles a list of inputs and outputs // NOTE: Make sure to revert state changes from tx on error -func inputOutputCoins(ctx sdk.Context, am auth.AccountMapper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) { +func inputOutputCoins(ctx sdk.Context, am auth.AccountKeeper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) { allTags := sdk.EmptyTags() for _, in := range inputs { diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index c48410c154..26c1446d27 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -33,16 +33,16 @@ func TestKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) - bankKeeper := NewBaseKeeper(accountMapper) + accountKeeper := auth.NewAccountKeeper(cdc, authKey, auth.ProtoBaseAccount) + bankKeeper := NewBaseKeeper(accountKeeper) addr := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) addr3 := sdk.AccAddress([]byte("addr3")) - acc := accountMapper.NewAccountWithAddress(ctx, addr) + acc := accountKeeper.NewAccountWithAddress(ctx, addr) // Test GetCoins/SetCoins - accountMapper.SetAccount(ctx, acc) + accountKeeper.SetAccount(ctx, acc) require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) bankKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}) @@ -118,17 +118,17 @@ func TestSendKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) - bankKeeper := NewBaseKeeper(accountMapper) - sendKeeper := NewBaseSendKeeper(accountMapper) + accountKeeper := auth.NewAccountKeeper(cdc, authKey, auth.ProtoBaseAccount) + bankKeeper := NewBaseKeeper(accountKeeper) + sendKeeper := NewBaseSendKeeper(accountKeeper) addr := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) addr3 := sdk.AccAddress([]byte("addr3")) - acc := accountMapper.NewAccountWithAddress(ctx, addr) + acc := accountKeeper.NewAccountWithAddress(ctx, addr) // Test GetCoins/SetCoins - accountMapper.SetAccount(ctx, acc) + accountKeeper.SetAccount(ctx, acc) require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) bankKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}) @@ -187,15 +187,15 @@ func TestViewKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) - bankKeeper := NewBaseKeeper(accountMapper) - viewKeeper := NewBaseViewKeeper(accountMapper) + accountKeeper := auth.NewAccountKeeper(cdc, authKey, auth.ProtoBaseAccount) + bankKeeper := NewBaseKeeper(accountKeeper) + viewKeeper := NewBaseViewKeeper(accountKeeper) addr := sdk.AccAddress([]byte("addr1")) - acc := accountMapper.NewAccountWithAddress(ctx, addr) + acc := accountKeeper.NewAccountWithAddress(ctx, addr) // Test GetCoins/SetCoins - accountMapper.SetAccount(ctx, acc) + accountKeeper.SetAccount(ctx, acc) require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) bankKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}) diff --git a/x/bank/simulation/invariants.go b/x/bank/simulation/invariants.go index 20aa9570bf..f0cd5ba63c 100644 --- a/x/bank/simulation/invariants.go +++ b/x/bank/simulation/invariants.go @@ -13,7 +13,7 @@ import ( ) // NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances -func NonnegativeBalanceInvariant(mapper auth.AccountMapper) simulation.Invariant { +func NonnegativeBalanceInvariant(mapper auth.AccountKeeper) simulation.Invariant { return func(app *baseapp.BaseApp) error { ctx := app.NewContext(false, abci.Header{}) accts := mock.GetAllAccounts(mapper, ctx) @@ -31,7 +31,7 @@ func NonnegativeBalanceInvariant(mapper auth.AccountMapper) simulation.Invariant // TotalCoinsInvariant checks that the sum of the coins across all accounts // is what is expected -func TotalCoinsInvariant(mapper auth.AccountMapper, totalSupplyFn func() sdk.Coins) simulation.Invariant { +func TotalCoinsInvariant(mapper auth.AccountKeeper, totalSupplyFn func() sdk.Coins) simulation.Invariant { return func(app *baseapp.BaseApp) error { ctx := app.NewContext(false, abci.Header{}) totalCoins := sdk.Coins{} diff --git a/x/bank/simulation/msgs.go b/x/bank/simulation/msgs.go index 0a253235e1..f33c5e0c99 100644 --- a/x/bank/simulation/msgs.go +++ b/x/bank/simulation/msgs.go @@ -17,7 +17,7 @@ import ( // SingleInputSendTx tests and runs a single msg send w/ auth, with one input and one output, where both // accounts already exist. -func SingleInputSendTx(mapper auth.AccountMapper) simulation.Operation { +func SingleInputSendTx(mapper auth.AccountKeeper) simulation.Operation { return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { fromAcc, action, msg, abort := createSingleInputSendMsg(r, ctx, accs, mapper) if abort { @@ -35,7 +35,7 @@ func SingleInputSendTx(mapper auth.AccountMapper) simulation.Operation { // SingleInputSendMsg tests and runs a single msg send, with one input and one output, where both // accounts already exist. -func SingleInputSendMsg(mapper auth.AccountMapper, bk bank.Keeper) simulation.Operation { +func SingleInputSendMsg(mapper auth.AccountKeeper, bk bank.Keeper) simulation.Operation { handler := bank.NewHandler(bk) return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { fromAcc, action, msg, abort := createSingleInputSendMsg(r, ctx, accs, mapper) @@ -52,7 +52,7 @@ func SingleInputSendMsg(mapper auth.AccountMapper, bk bank.Keeper) simulation.Op } } -func createSingleInputSendMsg(r *rand.Rand, ctx sdk.Context, accs []simulation.Account, mapper auth.AccountMapper) (fromAcc simulation.Account, action string, msg bank.MsgSend, abort bool) { +func createSingleInputSendMsg(r *rand.Rand, ctx sdk.Context, accs []simulation.Account, mapper auth.AccountKeeper) (fromAcc simulation.Account, action string, msg bank.MsgSend, abort bool) { fromAcc = simulation.RandomAcc(r, accs) toAcc := simulation.RandomAcc(r, accs) // Disallow sending money to yourself @@ -92,7 +92,7 @@ func createSingleInputSendMsg(r *rand.Rand, ctx sdk.Context, accs []simulation.A // Sends and verifies the transition of a msg send. This fails if there are repeated inputs or outputs // pass in handler as nil to handle txs, otherwise handle msgs -func sendAndVerifyMsgSend(app *baseapp.BaseApp, mapper auth.AccountMapper, msg bank.MsgSend, ctx sdk.Context, privkeys []crypto.PrivKey, handler sdk.Handler) error { +func sendAndVerifyMsgSend(app *baseapp.BaseApp, mapper auth.AccountKeeper, msg bank.MsgSend, ctx sdk.Context, privkeys []crypto.PrivKey, handler sdk.Handler) error { initialInputAddrCoins := make([]sdk.Coins, len(msg.Inputs)) initialOutputAddrCoins := make([]sdk.Coins, len(msg.Outputs)) AccountNumbers := make([]int64, len(msg.Inputs)) diff --git a/x/bank/simulation/sim_test.go b/x/bank/simulation/sim_test.go index ce3877a620..5141562281 100644 --- a/x/bank/simulation/sim_test.go +++ b/x/bank/simulation/sim_test.go @@ -15,7 +15,7 @@ func TestBankWithRandomMessages(t *testing.T) { mapp := mock.NewApp() bank.RegisterCodec(mapp.Cdc) - mapper := mapp.AccountMapper + mapper := mapp.AccountKeeper bankKeeper := bank.NewBaseKeeper(mapper) mapp.Router().AddRoute("bank", bank.NewHandler(bankKeeper)) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 59b615ec8a..95303b16ba 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -72,7 +72,7 @@ func MakeTestCodec() *codec.Codec { // test input with default values func CreateTestInputDefault(t *testing.T, isCheckTx bool, initCoins int64) ( - sdk.Context, auth.AccountMapper, Keeper, stake.Keeper, DummyFeeCollectionKeeper) { + sdk.Context, auth.AccountKeeper, Keeper, stake.Keeper, DummyFeeCollectionKeeper) { communityTax := sdk.NewDecWithPrec(2, 2) return CreateTestInputAdvanced(t, isCheckTx, initCoins, communityTax) @@ -81,7 +81,7 @@ func CreateTestInputDefault(t *testing.T, isCheckTx bool, initCoins int64) ( // hogpodge of all sorts of input required for testing func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initCoins int64, communityTax sdk.Dec) ( - sdk.Context, auth.AccountMapper, Keeper, stake.Keeper, DummyFeeCollectionKeeper) { + sdk.Context, auth.AccountKeeper, Keeper, stake.Keeper, DummyFeeCollectionKeeper) { keyDistr := sdk.NewKVStoreKey("distr") keyStake := sdk.NewKVStoreKey("stake") @@ -109,8 +109,8 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initCoins int64, pk := params.NewKeeper(cdc, keyParams, tkeyParams) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount) - ck := bank.NewBaseKeeper(accountMapper) + accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, auth.ProtoBaseAccount) + ck := bank.NewBaseKeeper(accountKeeper) sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, pk.Subspace(stake.DefaultParamspace), stake.DefaultCodespace) sk.SetPool(ctx, stake.InitialPool()) sk.SetParams(ctx, stake.DefaultParams()) @@ -139,7 +139,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initCoins int64, keeper.SetBaseProposerReward(ctx, sdk.NewDecWithPrec(1, 2)) keeper.SetBonusProposerReward(ctx, sdk.NewDecWithPrec(4, 2)) - return ctx, accountMapper, keeper, sk, fck + return ctx, accountKeeper, keeper, sk, fck } //__________________________________________________________________________________ diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 4b7ec26b5c..d061f12062 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -111,14 +111,14 @@ func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID int64) Proposal { return proposal } -// Implements sdk.AccountMapper. +// Implements sdk.AccountKeeper. func (keeper Keeper) SetProposal(ctx sdk.Context, proposal Proposal) { store := ctx.KVStore(keeper.storeKey) bz := keeper.cdc.MustMarshalBinary(proposal) store.Set(KeyProposal(proposal.GetProposalID()), bz) } -// Implements sdk.AccountMapper. +// Implements sdk.AccountKeeper. func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposal Proposal) { store := ctx.KVStore(keeper.storeKey) store.Delete(KeyProposal(proposal.GetProposalID())) diff --git a/x/gov/simulation/sim_test.go b/x/gov/simulation/sim_test.go index a7d4e40d05..a222c19a52 100644 --- a/x/gov/simulation/sim_test.go +++ b/x/gov/simulation/sim_test.go @@ -22,7 +22,7 @@ func TestGovWithRandomMessages(t *testing.T) { bank.RegisterCodec(mapp.Cdc) gov.RegisterCodec(mapp.Cdc) - mapper := mapp.AccountMapper + mapper := mapp.AccountKeeper bankKeeper := bank.NewBaseKeeper(mapper) stakeKey := sdk.NewKVStoreKey("stake") diff --git a/x/gov/test_common.go b/x/gov/test_common.go index b33f580841..82ae30358b 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -33,7 +33,7 @@ func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper, keyGov := sdk.NewKVStoreKey("gov") pk := params.NewKeeper(mapp.Cdc, keyGlobalParams, tkeyGlobalParams) - ck := bank.NewBaseKeeper(mapp.AccountMapper) + ck := bank.NewBaseKeeper(mapp.AccountKeeper) sk := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, ck, pk.Subspace(stake.DefaultParamspace), mapp.RegisterCodespace(stake.DefaultCodespace)) keeper := NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, DefaultCodespace) diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go index 6806d9779e..9b360c7c24 100644 --- a/x/ibc/app_test.go +++ b/x/ibc/app_test.go @@ -21,7 +21,7 @@ func getMockApp(t *testing.T) *mock.App { RegisterCodec(mapp.Cdc) keyIBC := sdk.NewKVStoreKey("ibc") ibcMapper := NewMapper(mapp.Cdc, keyIBC, mapp.RegisterCodespace(DefaultCodespace)) - bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper) + bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper) mapp.Router().AddRoute("ibc", NewHandler(ibcMapper, bankKeeper)) require.NoError(t, mapp.CompleteSetup(keyIBC)) @@ -49,7 +49,7 @@ func TestIBCMsgs(t *testing.T) { // A checkTx context (true) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) + res1 := mapp.AccountKeeper.GetAccount(ctxCheck, addr1) require.Equal(t, acc, res1) packet := IBCPacket{ diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index c8e7492be7..6cd89fded4 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -17,7 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" ) -// AccountMapper(/Keeper) and IBCMapper should use different StoreKey later +// AccountKeeper(/Keeper) and IBCMapper should use different StoreKey later func defaultContext(key sdk.StoreKey) sdk.Context { db := dbm.NewMemDB() @@ -64,7 +64,7 @@ func TestIBC(t *testing.T) { key := sdk.NewKVStoreKey("ibc") ctx := defaultContext(key) - am := auth.NewAccountMapper(cdc, key, auth.ProtoBaseAccount) + am := auth.NewAccountKeeper(cdc, key, auth.ProtoBaseAccount) ck := bank.NewBaseKeeper(am) src := newAddress() diff --git a/x/mock/app.go b/x/mock/app.go index 1fe411fbc5..627434a513 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -29,7 +29,7 @@ type App struct { KeyAccount *sdk.KVStoreKey // TODO: Abstract this out from not needing to be auth specifically - AccountMapper auth.AccountMapper + AccountKeeper auth.AccountKeeper FeeCollectionKeeper auth.FeeCollectionKeeper GenesisAccounts []auth.Account @@ -57,8 +57,8 @@ func NewApp() *App { TotalCoinsSupply: sdk.Coins{}, } - // Define the accountMapper - app.AccountMapper = auth.NewAccountMapper( + // Define the accountKeeper + app.AccountKeeper = auth.NewAccountKeeper( app.Cdc, app.KeyAccount, auth.ProtoBaseAccount, @@ -67,7 +67,7 @@ func NewApp() *App { // 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)) + app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, app.FeeCollectionKeeper)) // Not sealing for custom extension @@ -101,9 +101,9 @@ func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error { 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 := app.AccountKeeper.NewAccountWithAddress(ctx, genacc.GetAddress()) acc.SetCoins(genacc.GetCoins()) - app.AccountMapper.SetAccount(ctx, acc) + app.AccountKeeper.SetAccount(ctx, acc) } return abci.ResponseInitChain{} @@ -247,8 +247,8 @@ func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []s app.GenesisAccounts = accts } -// GetAllAccounts returns all accounts in the accountMapper. -func GetAllAccounts(mapper auth.AccountMapper, ctx sdk.Context) []auth.Account { +// GetAllAccounts returns all accounts in the accountKeeper. +func GetAllAccounts(mapper auth.AccountKeeper, ctx sdk.Context) []auth.Account { accounts := []auth.Account{} appendAccount := func(acc auth.Account) (stop bool) { accounts = append(accounts, acc) diff --git a/x/mock/app_test.go b/x/mock/app_test.go index d48a6ba14d..6835d50b13 100644 --- a/x/mock/app_test.go +++ b/x/mock/app_test.go @@ -56,7 +56,7 @@ func TestCheckAndDeliverGenTx(t *testing.T) { msg := testMsg{signers: []sdk.AccAddress{addrs[0]}, positiveNum: 1} - acct := mApp.AccountMapper.GetAccount(ctxCheck, addrs[0]) + acct := mApp.AccountKeeper.GetAccount(ctxCheck, addrs[0]) require.Equal(t, accs[0], acct.(*auth.BaseAccount)) SignCheckDeliver( diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go index caaca6c9a5..4e60478fa4 100644 --- a/x/mock/test_utils.go +++ b/x/mock/test_utils.go @@ -41,7 +41,7 @@ func RandFromBigInterval(r *rand.Rand, intervals []BigInterval) sdk.Int { // CheckBalance checks the balance of an account. func CheckBalance(t *testing.T, app *App, addr sdk.AccAddress, exp sdk.Coins) { ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) - res := app.AccountMapper.GetAccount(ctxCheck, addr) + res := app.AccountKeeper.GetAccount(ctxCheck, addr) require.Equal(t, exp, res.GetCoins()) } diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index c0ed10747c..6529609ba0 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -31,7 +31,7 @@ func getMockApp(t *testing.T) (*mock.App, stake.Keeper, Keeper) { keyParams := sdk.NewKVStoreKey("params") tkeyParams := sdk.NewTransientStoreKey("transient_params") - bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper) + bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper) paramsKeeper := params.NewKeeper(mapp.Cdc, keyParams, tkeyParams) stakeKeeper := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, bankKeeper, paramsKeeper.Subspace(stake.DefaultParamspace), mapp.RegisterCodespace(stake.DefaultCodespace)) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index a648bfe850..55a6fda18f 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -68,9 +68,9 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s require.Nil(t, err) ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout)) cdc := createTestCodec() - accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount) + accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, auth.ProtoBaseAccount) - ck := bank.NewBaseKeeper(accountMapper) + ck := bank.NewBaseKeeper(accountKeeper) paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, paramsKeeper.Subspace(stake.DefaultParamspace), stake.DefaultCodespace) genesis := stake.DefaultGenesisState() diff --git a/x/stake/app_test.go b/x/stake/app_test.go index faafb6664f..9a38d2d170 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -24,7 +24,7 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) { keyParams := sdk.NewKVStoreKey("params") tkeyParams := sdk.NewTransientStoreKey("transient_params") - bankKeeper := bank.NewBaseKeeper(mApp.AccountMapper) + bankKeeper := bank.NewBaseKeeper(mApp.AccountKeeper) pk := params.NewKeeper(mApp.Cdc, keyParams, tkeyParams) keeper := NewKeeper(mApp.Cdc, keyStake, tkeyStake, bankKeeper, pk.Subspace(DefaultParamspace), mApp.RegisterCodespace(DefaultCodespace)) diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index d0ac4a2825..2303d3c750 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -74,7 +74,7 @@ func MakeTestCodec() *codec.Codec { } // hogpodge of all sorts of input required for testing -func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, auth.AccountMapper, Keeper) { +func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, auth.AccountKeeper, Keeper) { keyStake := sdk.NewKVStoreKey("stake") tkeyStake := sdk.NewTransientStoreKey("transient_stake") @@ -94,13 +94,13 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) cdc := MakeTestCodec() - accountMapper := auth.NewAccountMapper( + accountKeeper := auth.NewAccountKeeper( cdc, // amino codec keyAcc, // target store auth.ProtoBaseAccount, // prototype ) - ck := bank.NewBaseKeeper(accountMapper) + ck := bank.NewBaseKeeper(accountKeeper) pk := params.NewKeeper(cdc, keyParams, tkeyParams) keeper := NewKeeper(cdc, keyStake, tkeyStake, ck, pk.Subspace(DefaultParamspace), types.DefaultCodespace) @@ -119,7 +119,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context keeper.SetPool(ctx, pool) } - return ctx, accountMapper, keeper + return ctx, accountKeeper, keeper } func NewPubKey(pk string) (res crypto.PubKey) { diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index 2866f6292f..661e46cc49 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -14,7 +14,7 @@ import ( // AllInvariants runs all invariants of the stake module. // Currently: total supply, positive power -func AllInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant { +func AllInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountKeeper) simulation.Invariant { return func(app *baseapp.BaseApp) error { err := SupplyInvariants(ck, k, am)(app) if err != nil { @@ -31,7 +31,7 @@ func AllInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simula // SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations // nolint: unparam -func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant { +func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountKeeper) simulation.Invariant { return func(app *baseapp.BaseApp) error { ctx := app.NewContext(false, abci.Header{}) pool := k.GetPool(ctx) diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index f2224c865b..8684126e30 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -14,7 +14,7 @@ import ( ) // SimulateMsgCreateValidator -func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation { +func SimulateMsgCreateValidator(m auth.AccountKeeper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) ( @@ -111,7 +111,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { } // SimulateMsgDelegate -func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation { +func SimulateMsgDelegate(m auth.AccountKeeper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) ( @@ -149,7 +149,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat } // SimulateMsgBeginUnbonding -func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation { +func SimulateMsgBeginUnbonding(m auth.AccountKeeper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) ( @@ -187,7 +187,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. } // SimulateMsgBeginRedelegate -func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation { +func SimulateMsgBeginRedelegate(m auth.AccountKeeper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) ( @@ -238,10 +238,10 @@ func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup { params := k.GetParams(ctx) denom := params.BondDenom loose := sdk.ZeroInt() - mapp.AccountMapper.IterateAccounts(ctx, func(acc auth.Account) bool { + mapp.AccountKeeper.IterateAccounts(ctx, func(acc auth.Account) bool { balance := simulation.RandomAmount(r, sdk.NewInt(1000000)) acc.SetCoins(acc.GetCoins().Plus(sdk.Coins{sdk.NewCoin(denom, balance)})) - mapp.AccountMapper.SetAccount(ctx, acc) + mapp.AccountKeeper.SetAccount(ctx, acc) loose = loose.Add(balance) return false }) diff --git a/x/stake/simulation/sim_test.go b/x/stake/simulation/sim_test.go index 6aa7801139..648c092849 100644 --- a/x/stake/simulation/sim_test.go +++ b/x/stake/simulation/sim_test.go @@ -20,7 +20,7 @@ func TestStakeWithRandomMessages(t *testing.T) { mapp := mock.NewApp() bank.RegisterCodec(mapp.Cdc) - mapper := mapp.AccountMapper + mapper := mapp.AccountKeeper bankKeeper := bank.NewBaseKeeper(mapper) stakeKey := sdk.NewKVStoreKey("stake") stakeTKey := sdk.NewTransientStoreKey("transient_stake") @@ -58,7 +58,7 @@ func TestStakeWithRandomMessages(t *testing.T) { }, []simulation.RandSetup{ Setup(mapp, stakeKeeper), }, []simulation.Invariant{ - AllInvariants(bankKeeper, stakeKeeper, mapp.AccountMapper), + AllInvariants(bankKeeper, stakeKeeper, mapp.AccountKeeper), }, 10, 100, false, ) From 17cf2ac62d185ba076d43e14f0452bee4a61d321 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sat, 20 Oct 2018 23:25:29 -0700 Subject: [PATCH 11/13] Refresh PENDING.md --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index eda622202c..926f755815 100644 --- a/PENDING.md +++ b/PENDING.md @@ -85,6 +85,7 @@ BREAKING CHANGES * [x/stake] \#2508 Utilize Tendermint power for validator power key * [x/stake] \#2531 Remove all inflation logic * [x/mint] \#2531 Add minting module and inflation logic + * [x/auth] [\#2540](https://github.com/cosmos/cosmos-sdk/issues/2540) Rename `AccountMapper` to `AccountKeeper`. * Tendermint * Update tendermint version from v0.23.0 to v0.25.0, notable changes From a4c7faaa403896f94323f4638fbac194e143a47c Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sat, 20 Oct 2018 23:52:45 -0700 Subject: [PATCH 12/13] Mark --to and --amount flags required for gaiacli tx send Closes: #2547 --- PENDING.md | 1 + x/bank/client/cli/sendtx.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/PENDING.md b/PENDING.md index eda622202c..d7bcf555c0 100644 --- a/PENDING.md +++ b/PENDING.md @@ -202,6 +202,7 @@ BUG FIXES * Gaia CLI (`gaiacli`) * [cli] [\#1997](https://github.com/cosmos/cosmos-sdk/issues/1997) Handle panics gracefully when `gaiacli stake {delegation,unbond}` fail to unmarshal delegation. * [cli] [\#2265](https://github.com/cosmos/cosmos-sdk/issues/2265) Fix JSON formatting of the `gaiacli send` command. + * [cli] [\#2547](https://github.com/cosmos/cosmos-sdk/issues/2547) Mark --to and --amount as required flags for `gaiacli tx send`. * Gaia * [x/stake] Return correct Tendermint validator update set on `EndBlocker` by not diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index 8200563b0e..c72ed6fcb9 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -75,6 +75,8 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command { cmd.Flags().String(flagTo, "", "Address to send coins") cmd.Flags().String(flagAmount, "", "Amount of coins to send") + cmd.MarkFlagRequired(flagTo) + cmd.MarkFlagRequired(flagAmount) return cmd } From 48b877512194f6b171ffc055ee2c67ce1af8a6da Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Mon, 22 Oct 2018 17:56:31 -0700 Subject: [PATCH 13/13] F1 fee distribution draft 00 This was written up in latex, because github markdown doesn't support latex. --- .gitignore | 5 + .../f1-fee-distribution/f1_fee_distr.pdf | Bin 0 -> 160589 bytes .../f1-fee-distribution/f1_fee_distr.tex | 135 ++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 docs/spec-proposals/f1-fee-distribution/f1_fee_distr.pdf create mode 100644 docs/spec-proposals/f1-fee-distribution/f1_fee_distr.tex diff --git a/.gitignore b/.gitignore index dec322b7ba..cbc5e5e22c 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,8 @@ vagrant # Graphviz dependency-graph.png + +# Latex +*.aux +*.out +*.synctex.gz diff --git a/docs/spec-proposals/f1-fee-distribution/f1_fee_distr.pdf b/docs/spec-proposals/f1-fee-distribution/f1_fee_distr.pdf new file mode 100644 index 0000000000000000000000000000000000000000..12e7d5906e58b2efa6f94679c342d341854d2f6f GIT binary patch literal 160589 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®ryLZ+Am4HXXm3kv{(f^rp^LK&zv z=aL}-%0C4IzlQ{P4<7jt9u^<~;DaD}r4u5N#L0(n4HE#!>;_;V0lF0IFZFkR6dbU= z(O%g4wu0QRKLxpuh={QNa|Ivg5LBSIq6f-{bZrUZEOcuI8v^tcx58Lnxxy!8C%Mtq z$r%pdhlhvPtuKP6Lo%V7nSj0b@7M%%E})f9=0X8_SE1*JzJ~Zw!lVPl=HG)meH5z= zYj$`6D9Q(D27qe{CDNY9vxR^_0p+)Yn^#%^;C2lp`o*yNX4nV&Ucm;yr`zir`Z@Wb zLV$VL!nC%DadrkG?$(FU@`r_i1Lam--FJC$J^}MbjMod*Z-+*@fp-NT+SjLQ9=Mwx z05IXe1;EhR*E{J@FVdH-rR}Drf3HId=o`%Mst)$2Ai%{ffKWpZ)cg21C@*j2yw&6H zC%Xz5@XY`I4Qj0q5k6B#L|`k+4-7KB0b5!5o(8EYeBU;Wb_s<56u?h3NCZ&M1aN6# z1OAPwyEg^-sWtH?6U|2qbAIgUV1mq~0XI!J`S*N@Hbmv?|9SZEvz zbNjFIw_Q#*_agHC5HShV{sB4=;QRY&i?(L zW$fPPpBSub@IcQmBY)EB3@Q&mruZ`k!SB{G!l#+}NrL^j-<7h?z&S&_(E8xtj&OPu z<1{kVLTHEP*3ZEte#bx^X3!9VyiGCm^;!wg{sC~nuT&TwwH5gD$Uz|4u^lQ358L0i zBBVh~@HZB{FQEYdMhK7>VtyP(OfUei_qjwcKaZah2EefhfzARgfU|=y05(bF{+b6A zG@!p@pKxD7Is^d3FLnfwzp5WG1Hk;}UU-}w0)X%jxbT?62RsD~K<97h-}ve#Y=~go zl^tt=)Cc;n4;z0$uDn%X2WD}LaQIJFe4E*dqca}2o@fc#MlVLG}K}J=v*U@h(0w=HmtrAnggW2ry zz~tj1CQ}QEdmWS&-$TNlv!?hm10RHM;ZQb>M%o;uwy|7w-qf$f=su+A;t2ROfQZ>2 zr4(@&U=kq=d{AUaSJqajvC|+?wX58^b`|)|L@KRn2xcYc`S;azdEFeTQB#N`XNb=& z5ABC)c*;;z_n*Rt5flv$jFEn{aqhCDRDw8&YB2cGV4|mMK1r}KmLTnn>&i5!`qdd| zd)cU$vU|?sQn2m?Q;oxO=5K@u1AA|BCY`tHO!x`t)n@#Go(++ z*(0z)9GHi~G`dJ-XwwQx@h?+ZWViEY$)?6)N8U15yyimIF8*_{1Y8Le2cAF8Q)H#y z?s*(?C;tn9NTgi%84ER3!_Z_Tm^XYRwmmLTb#Zz3HF1*cqU%5lm$%8pMyuUO>zW<-Aj4)S+-5+xdvl`QS8WXT+F*f|ylBdh8t6m_YFCRjwAi!Yix5J)nbKE4t7m0M{+>|_cJSVmF_jeAo zOh%dp(v^r9j5k3|QIsDllIphLN$K8{N5<|dQrqe8}1|mBl;oFhS6pqtR{mS@grvOoV*7)nj z2#>&lynC6?sScq~p}Q7Elskwu@j*@eF9+JqXctZ{PGq$gECYI9+_*tN!qj)|Ty+yi>) zqwK7Cq3V2>wQJ>C}0o80ODYM>r#M3gUyd(4RtB~L+ms7E0SdPP^N zpAkRNrqOuZP~(G9PO@e6wE^cR0ei{8K7?~Hoz4IRMr-fc0nqbcbU7XW2%9C*2B^8u z(e(}W!kniJAfJCGKbA_L2~m~4$gc%$NudjuK6UTcm^3-zZdQpblq>e6~4_ecO$Vc0*4VTIXl71fk9kbxt*cn(Kzb~tiXMfDZreby$nMG

C7R4eI5x2(Q@?~o$ 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

g$S4a8MQKehuoH@`AaY?82F9-=76aJy0cN%% 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%0AZb%{LW*Zsh4`JVVJ0J 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

ppo=HyXDBmkvO{a2&Jr4vg2<|gwkHs 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�jV-%FZ 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 literal 0 HcmV?d00001 diff --git a/docs/spec-proposals/f1-fee-distribution/f1_fee_distr.tex b/docs/spec-proposals/f1-fee-distribution/f1_fee_distr.tex new file mode 100644 index 0000000000..969e77ec94 --- /dev/null +++ b/docs/spec-proposals/f1-fee-distribution/f1_fee_distr.tex @@ -0,0 +1,135 @@ +\documentclass[]{article} +\usepackage{hyperref} + +%opening +\title{F1 Fee Distribution Draft-00} +\author{Dev Ojha} + +\begin{document} + +\maketitle + +\begin{abstract} + In a proof of stake blockchain, validators need to split the rewards gained from transaction fees each block. Furthermore, these fees must be fairly distributed to each of a validator's constituent delegators. They accrue this reward throughout the entire time they are delegated, and they have a special operation to withdraw accrued rewards. + + The F1 fee distribution scheme works for any algorithm to split funds between validators each block, with minimal iteration, and the only approximations being due to finite decimal precision. Per block there is a single iteration over the validator set, which enables only rewarding validators who signed a given block. No iteration is required to delegate, and withdrawing only requires iterating over all of that validators slashes since delegation it began. State usage is minimal as well, one state update per validator per block, and one state record per delegator. +\end{abstract} + +\section{F1 Fee Distribution} + +In a proof of stake model, each validator has an associated stake, with delegators each contributing some amount to a validator's stake. +The validator is rewarded transaction fees every block for the service they are providing the network. +In the F1 distribution, each validator is permitted to take a commission from the fees they receive, and the remaining fees should be evenly distributed across the validator's delegators, such that every delegator the percentage of the validator's stake that came from the delegator is the proportion of that validator's remaining tx fees which they are getting. +Iterating over all delegators for every validator each block is too expensive for a blockchain environment. +Instead there is an explicit withdraw fees action which a delegator can take, which will give the delegator the same total amount of fees as though they were receiving it every block. + +Suppose a delegator delegates $x$ stake to a validator at block $h$. +Let the amount of stake the validator has at block $i$ be $s_i$ and the amount of fees they receive at this height be $f_i$. +Then if a delegator contributing $x$ stake decides to withdraw at block $n$, the rewards they receive is +$$\sum_{i = h}^{n} \frac{x}{s_i}f_i = x \sum_{i = h}^{n} \frac{f_i}{s_i}$$ + +However $s_i$ will not change every block. +It only changes if the validator gets slashed, or if someone new has bonded or unbonded. +Handling slashes is relegated to \autoref{ssec:slashing}. +Define a period as the set of blocks between two changes in a given validator's total stake. +A new period begins every time that validator's total stake changes. +The above iteration will be converted to iteration over periods. +Let the total amount of stake for the validator in period $p$ be $n_p$. +Let $T_p$ be the total fees this validator accrued within this period. +Let $h$ be the start of period $p_{init}$, and height $n$ be the end of $p_{final}$. +It follows that +$$x \sum_{i = h}^{n} \frac{f_i}{s_i} = x \sum_{p = p_{init}}^{p_{final}} \frac{T_p}{n_p}$$ + +Let $p_0$ represent the period from when the validator first bonded until the first change to the validators stake. +The central idea to the F1 model is that at the end of the $k$th period, the following is stored at a state location indexable by $k$: $\sum_{i=0}^{k}\frac{T_i}{n_i}$. +When a delegator wants to delegate or withdraw their reward, they first create a new entry in state to end the current period. Let the index of the current period be $f$. +Then this entry is created using the previous entry as follows: $$\sum_{i=0}^{f}\frac{T_i}{n_i} = \sum_{i=0}^{f-1}\frac{T_i}{n_i} + \frac{T_f}{n_f} = entry_{f-1} + \frac{T_f}{n_f}$$ +Where $T_f$ is the fees the validator has accrued in period $f$, and $n_f$ is the validators total amount of stake in period $f$. + +The withdrawer's delegation object has the index $k$ for the period which they started accruing fees for. +Thus the reward they should receive when withdrawing is: + +$$x\left(entry_f - entry_k\right) = x\left(\left(\sum_{i=0}^{f}\frac{T_i}{n_i}\right) - \left(\sum_{i=0}^{k}\frac{T_i}{n_i}\right)\right) = x \sum_{i = k}^{f} \frac{T_i}{n_i}$$ + +The first summation is the state entry for $f$, and the second sum is the state entry at $k$. +It is clear from the equations that this payout mechanism maintains correctness, and required no iterations. + +$T_f$ is a separate variable in state for the amount of fees this validator has accrued since the last update to its power. +This variable is incremented at every block by however much fees this validator received that block. +On the update to the validators power, this variable is used to create the entry in state at $f$. + +This fee distribution proposal is agnostic to how all of the blocks fees are divied up between validators. +This creates many nice properties, for example only rewarding validators who signed that block. + +\section{Additional add-ons} +\subsection{Commission Rates} +Commission rates are the idea that a validator can take a fixed $x\%$ cut of all of their received fees, before redistributing evenly to the constituent delegators. +This can easily be done as follows: + +In block $h$ a validator receives $f_h$ fees. +Instead of incrementing that validators ``total accrued fees this period variable" by $f_h$, it is instead incremented by $(1 - commission\_rate) * f_p$. +Then $commission\_rate * f_p$ is deposited directly to the validator. +This scheme allow for updates to a validator's commission rate every block if desired. + +\subsection{Slashing} +\label{ssec:slashing} +Slashing is distinct from withdrawals, since not only does it lower the validators total amount of stake, but it also lowers each of its delegator's stake by a fixed percentage. +Since noone is charged gas for slashes, a slash cannot iterate over all delegators. +Thus we can no longer just multiply by $x$ over the difference in stake. +The solution here is to instead store each period created by a slash in the validators state. +Then when withdrawing, you must iterate over all slashes between when you started and ended. +Suppose you delegated at period $0$, a y\% slash occured at period $2$, and your withdrawal is period $4$. +Then you receive funds from $0$ to $2$ as normal. +The equations for funds you receive for $2$ to $4$ now uses $(1 - y)x$ for your stake instead of just $x$ stake. +When there are multiple slashes, you just account for the accumulated slash factor. + +In practice this will not really be an efficiency hit, as we can expect most validators to have no slashes. +Validators that get slashed a lot will naturally lose their delegators. +A malicious validator that gets itself slashed many times would increase the gas to withdraw linearly, but the economic loss of funds due to the slashes should far out-weigh the extra overhead the withdrawer must pay for due to the gas. + +\subsection{Inflation} +Inflation is the idea that we want every staked coin to grow in value as time progresses. Each block, every staked token should each be rewarded $x$ staking tokens as inflation, where $x$ is calculated from function which takes state and the block information as input. This also allows for many seemless upgrade's to $x$'s algorithm. This can be added efficiently into the fee distribution model as follows: + +Make each block have an inflation number, by which every staked token should produce $x$ additional staking tokens. In state there is a variable for the sum of all such inflation numbers. Then each period will store this total inflation sum in addition to $\sum_{i=0}^{end}\frac{T_i}{n_i}$. When withdrawing perform a subtraction on the inflation sums at the end and at the start to see how many new staking tokens to produce per staked token. + +This works great in the model where the inflation rate should be dynamic each block, but apply the same to each validator. Inflation creation can trivially be epoched as long as inflation isn't required within the epoch, through changes to the $x$ function. + +Note that this process is extremely efficient. + +The above can be trivially amended if we want inflation to proceed differently for different validators each block. (e.g. depending on who was offline) It can also be made to be easily adapted in a live chain. It is unclear if either of these two are more desirable settings. + +\subsection{Delegation updates} +Updating your delegation amount is equivalent to withdrawing earned rewards and a fully independent new delegation occuring in the same block. + +\subsection{Jailing / being kicked out of the validator set} +This basically requires no change. In each block you only iterate over the currently bonded validators. So you simply don't update the "total accrued fees this period" variable for jailed / non-bonded validators. Withdrawing requires \textit{no} special casing here! + +\section{State pruning} +You will notice that in the main scheme there was no note for pruning entries from state. +We can in fact prune quite effectively. +Suppose for the sake of exposition that there is at most one delegation / withdrawal to a particular validator in any given block. +Then each delegation is responsible for one addition to state. +Only the next period, and this delegator's withdrawal could depend on this entry. Thus once this delegator withdraws, this state entry can be pruned. +For the entry created by the delegator's withdrawal, that is only required by the creation of the next period. Thus once the next period is created, that withdrawal's period can be deleted. + +This can be easily adapted to the case where there are multiple delegations / withdrawals per block. Keep a counter per state entry for how many delegations need to be cleared. (So 1 for each delegation in that block which created that period, 0 for each withdrawal) When creating a new period, check that the previous period (which had to be read anyway) doesn't have a count of 0. If it does have a count of 0, delete it. When withdrawing, decrement the period which created this delegation's counter by 1. If that counter is now 0, delete that period. + +The slash entries for a validator can only be pruned when all of that validator's delegators have their bonding period starting after the slash. This seems ineffective to keep track of, thus it is not worth it. Each slash should instead remain in state until the validator unbonds and all delegators have their fees withdrawn. + +\section{Implementers Considerations} + +This is an extremely simple scheme with many nice benefits. +\begin{itemize} + \item The overhead per block is a simple iteration over the bonded validator set, which occurs anyway. (Thus it can be implemented ``for-free" with an optimized code-base) + \item Withdrawing earned fees only requires iterating over slashes since when you bonded. (Which is a negligible iteration) + \item There are no approximations in any of the calculations. (modulo minor errata resulting from fixed precision decimals used in divisions) + \item Supports arbitrary inflation models. (Thus could even vary upon block signers) + \item Supports arbitrary fee distribution amongst the validator set. (Thus can account for things like only online validators get fees, which has important incentivization impacts) + \item The above two can change on a live chain with no issues. + \item Validator commission rates can be changed every block + \item The simplicity of this scheme lends itself well to implementation +\end{itemize} + +Thus this scheme has efficiency improvements, simplicity improvements, and expressiveness improvements over the currently proposed schemes. With a correct fee distribution amongst the validator set, this solves the existing problem where one could withhold their signature for risk-free gain. + +\end{document}