diff --git a/.pending/features/sdk/4570-Move-bank-balan b/.pending/features/sdk/4570-Move-bank-balan new file mode 100644 index 000000000000..55eb4b3d456b --- /dev/null +++ b/.pending/features/sdk/4570-Move-bank-balan @@ -0,0 +1 @@ +#4570 Move /bank/balances/{address} REST handler to x/bank/client/rest. The exposed interface is unchanged. diff --git a/x/auth/alias.go b/x/auth/alias.go index 2cfba026aae5..afd3b94b0252 100644 --- a/x/auth/alias.go +++ b/x/auth/alias.go @@ -42,7 +42,6 @@ var ( NewParams = types.NewParams ParamKeyTable = types.ParamKeyTable DefaultParams = types.DefaultParams - NewQueryAccountParams = types.NewQueryAccountParams NewStdTx = types.NewStdTx CountSubKeys = types.CountSubKeys NewStdFee = types.NewStdFee @@ -75,7 +74,6 @@ type ( FeeCollectionKeeper = types.FeeCollectionKeeper GenesisState = types.GenesisState Params = types.Params - QueryAccountParams = types.QueryAccountParams StdSignMsg = types.StdSignMsg StdTx = types.StdTx StdFee = types.StdFee diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 0c54ddd508ec..3d8cf3cf194f 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -64,50 +64,6 @@ func QueryAccountRequestHandlerFn( } } -// query accountREST Handler -func QueryBalancesRequestHandlerFn( - storeName string, decoder types.AccountDecoder, cliCtx context.CLIContext, -) http.HandlerFunc { - - return func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - vars := mux.Vars(r) - bech32addr := vars["address"] - - addr, err := sdk.AccAddressFromBech32(bech32addr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) - if !ok { - return - } - - res, _, err := cliCtx.QueryStore(types.AddressStoreKey(addr), storeName) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - // the query will return empty if there is no data for this account - if len(res) == 0 { - rest.PostProcessResponse(w, cliCtx, sdk.Coins{}) - return - } - - // decode the value - account, err := decoder(res) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - rest.PostProcessResponse(w, cliCtx, account.GetCoins()) - } -} - // QueryTxsByTagsRequestHandlerFn implements a REST handler that searches for // transactions by tags. func QueryTxsByTagsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { diff --git a/x/auth/client/rest/rest.go b/x/auth/client/rest/rest.go index 707750fa3b19..4195a06f2589 100644 --- a/x/auth/client/rest/rest.go +++ b/x/auth/client/rest/rest.go @@ -12,12 +12,6 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, storeName string) "/auth/accounts/{address}", QueryAccountRequestHandlerFn(storeName, context.GetAccountDecoder(cliCtx.Codec), cliCtx), ).Methods("GET") - - // TODO: Change path or mount under x/bank if possible - r.HandleFunc( - "/bank/balances/{address}", - QueryBalancesRequestHandlerFn(storeName, context.GetAccountDecoder(cliCtx.Codec), cliCtx), - ).Methods("GET") } // RegisterTxRoutes registers all transaction routes on the provided router. diff --git a/x/auth/querier_test.go b/x/auth/querier_test.go index 16c7bb582166..a73b12a402b5 100644 --- a/x/auth/querier_test.go +++ b/x/auth/querier_test.go @@ -4,9 +4,11 @@ import ( "fmt" "testing" - "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/x/auth/types" ) func Test_queryAccount(t *testing.T) { @@ -20,13 +22,13 @@ func Test_queryAccount(t *testing.T) { require.NotNil(t, err) require.Nil(t, res) - req.Data = input.cdc.MustMarshalJSON(NewQueryAccountParams([]byte(""))) + req.Data = input.cdc.MustMarshalJSON(types.NewQueryAccountParams([]byte(""))) res, err = queryAccount(input.ctx, req, input.ak) require.NotNil(t, err) require.Nil(t, res) _, _, addr := types.KeyTestPubAddr() - req.Data = input.cdc.MustMarshalJSON(NewQueryAccountParams(addr)) + req.Data = input.cdc.MustMarshalJSON(types.NewQueryAccountParams(addr)) res, err = queryAccount(input.ctx, req, input.ak) require.NotNil(t, err) require.Nil(t, res) diff --git a/x/auth/types/querier.go b/x/auth/types/querier.go index e0b45fc7a80a..84a80b1411a4 100644 --- a/x/auth/types/querier.go +++ b/x/auth/types/querier.go @@ -9,13 +9,12 @@ const ( QueryAccount = "account" ) -// defines the params for query: "custom/acc/account" +// QueryAccountParams defines the params for querying accounts. type QueryAccountParams struct { Address sdk.AccAddress } +// NewQueryAccountParams creates a new instance of QueryAccountParams. func NewQueryAccountParams(addr sdk.AccAddress) QueryAccountParams { - return QueryAccountParams{ - Address: addr, - } + return QueryAccountParams{Address: addr} } diff --git a/x/bank/alias.go b/x/bank/alias.go index 0a8c2a3f2ef3..b4885a675837 100644 --- a/x/bank/alias.go +++ b/x/bank/alias.go @@ -15,6 +15,7 @@ const ( CodeInvalidInputsOutputs = types.CodeInvalidInputsOutputs ModuleName = types.ModuleName RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute DefaultParamspace = types.DefaultParamspace ) diff --git a/x/bank/client/rest/query.go b/x/bank/client/rest/query.go new file mode 100644 index 000000000000..84c660fae5a9 --- /dev/null +++ b/x/bank/client/rest/query.go @@ -0,0 +1,54 @@ +package rest + +import ( + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/x/bank/internal/types" +) + +// query accountREST Handler +func QueryBalancesRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + vars := mux.Vars(r) + bech32addr := vars["address"] + + addr, err := sdk.AccAddressFromBech32(bech32addr) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + params := types.NewQueryBalanceParams(addr) + bz, err := cliCtx.Codec.MarshalJSON(params) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + res, _, err := cliCtx.QueryWithData("custom/bank/balances", bz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + // the query will return empty if there is no data for this account + if len(res) == 0 { + rest.PostProcessResponse(w, cliCtx, sdk.Coins{}) + return + } + + rest.PostProcessResponse(w, cliCtx, res) + } +} diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index 9bc9bc3450c0..9522167abf6d 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -6,7 +6,6 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" @@ -17,6 +16,7 @@ import ( // RegisterRoutes - Central function to define routes that get registered by the main application func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/bank/accounts/{address}/transfers", SendRequestHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/bank/balances/{address}", QueryBalancesRequestHandlerFn(cliCtx)).Methods("GET") } // SendReq defines the properties of a send request's body. @@ -25,12 +25,6 @@ type SendReq struct { Amount sdk.Coins `json:"amount"` } -var moduleCdc = codec.New() - -func init() { - types.RegisterCodec(moduleCdc) -} - // SendRequestHandlerFn - http request handler to send coins to a address. func SendRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index b87b100c1378..2487ccf9764a 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -21,6 +21,7 @@ import ( type testInput struct { cdc *codec.Codec ctx sdk.Context + k Keeper ak auth.AccountKeeper pk params.Keeper } @@ -51,14 +52,15 @@ func setupTestInput() testInput { ak.SetParams(ctx, auth.DefaultParams()) - return testInput{cdc: cdc, ctx: ctx, ak: ak, pk: pk} + bankKeeper := NewBaseKeeper(ak, pk.Subspace(types.DefaultParamspace), types.DefaultCodespace) + bankKeeper.SetSendEnabled(ctx, true) + + return testInput{cdc: cdc, ctx: ctx, k: bankKeeper, ak: ak, pk: pk} } func TestKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx - bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(types.DefaultParamspace), types.DefaultCodespace) - bankKeeper.SetSendEnabled(ctx, true) addr := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) @@ -67,57 +69,57 @@ func TestKeeper(t *testing.T) { // Test GetCoins/SetCoins input.ak.SetAccount(ctx, acc) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) - bankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) + input.k.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) // Test HasCoins - require.True(t, bankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, bankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - require.False(t, bankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, bankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) + require.True(t, input.k.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) + require.True(t, input.k.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) + require.False(t, input.k.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) + require.False(t, input.k.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) // Test AddCoins - bankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15))) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 25)))) + input.k.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 25)))) - bankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 15))) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 15), sdk.NewInt64Coin("foocoin", 25)))) + input.k.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 15))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 15), sdk.NewInt64Coin("foocoin", 25)))) // Test SubtractCoins - bankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) - bankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5))) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 15)))) + input.k.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) + input.k.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 15)))) - bankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 11))) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 15)))) + input.k.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 11))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 15)))) - bankKeeper.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10))) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) - require.False(t, bankKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 1)))) + input.k.SubtractCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) + require.False(t, input.k.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 1)))) // Test SendCoins - bankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5))) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, bankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) + input.k.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) + require.True(t, input.k.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - err2 := bankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) + err2 := input.k.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) require.Implements(t, (*sdk.Error)(nil), err2) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) - require.True(t, bankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) + require.True(t, input.k.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - bankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 30))) - bankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 5))) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 5)))) - require.True(t, bankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 10)))) + input.k.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 30))) + input.k.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 5))) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 5)))) + require.True(t, input.k.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 10)))) // Test InputOutputCoins input1 := types.NewInput(addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 2))) output1 := types.NewOutput(addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 2))) - bankKeeper.InputOutputCoins(ctx, []types.Input{input1}, []types.Output{output1}) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 7)))) - require.True(t, bankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 8)))) + input.k.InputOutputCoins(ctx, []types.Input{input1}, []types.Output{output1}) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 7)))) + require.True(t, input.k.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 8)))) inputs := []types.Input{ types.NewInput(addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 3))), @@ -128,19 +130,18 @@ func TestKeeper(t *testing.T) { types.NewOutput(addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 1))), types.NewOutput(addr3, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 2), sdk.NewInt64Coin("foocoin", 5))), } - bankKeeper.InputOutputCoins(ctx, inputs, outputs) - require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 21), sdk.NewInt64Coin("foocoin", 4)))) - require.True(t, bankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 7), sdk.NewInt64Coin("foocoin", 6)))) - require.True(t, bankKeeper.GetCoins(ctx, addr3).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 2), sdk.NewInt64Coin("foocoin", 5)))) + input.k.InputOutputCoins(ctx, inputs, outputs) + require.True(t, input.k.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 21), sdk.NewInt64Coin("foocoin", 4)))) + require.True(t, input.k.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 7), sdk.NewInt64Coin("foocoin", 6)))) + require.True(t, input.k.GetCoins(ctx, addr3).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 2), sdk.NewInt64Coin("foocoin", 5)))) } func TestSendKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx - paramSpace := input.pk.Subspace(types.DefaultParamspace) - bankKeeper := NewBaseKeeper(input.ak, paramSpace, types.DefaultCodespace) + paramSpace := input.pk.Subspace("newspace") sendKeeper := NewBaseSendKeeper(input.ak, paramSpace, types.DefaultCodespace) - bankKeeper.SetSendEnabled(ctx, true) + input.k.SetSendEnabled(ctx, true) addr := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) @@ -150,7 +151,7 @@ func TestSendKeeper(t *testing.T) { input.ak.SetAccount(ctx, acc) require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) - bankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) + input.k.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) // Test HasCoins @@ -159,7 +160,7 @@ func TestSendKeeper(t *testing.T) { require.False(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15)))) require.False(t, sendKeeper.HasCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 5)))) - bankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15))) + input.k.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 15))) // Test SendCoins sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5))) @@ -171,7 +172,7 @@ func TestSendKeeper(t *testing.T) { require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - bankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 30))) + input.k.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 30))) sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 5))) require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 20), sdk.NewInt64Coin("foocoin", 5)))) require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("barcoin", 10), sdk.NewInt64Coin("foocoin", 10)))) @@ -186,9 +187,7 @@ func TestSendKeeper(t *testing.T) { func TestViewKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx - paramSpace := input.pk.Subspace(types.DefaultParamspace) - bankKeeper := NewBaseKeeper(input.ak, paramSpace, types.DefaultCodespace) - bankKeeper.SetSendEnabled(ctx, true) + //paramSpace := input.pk.Subspace(types.DefaultParamspace) viewKeeper := NewBaseViewKeeper(input.ak, types.DefaultCodespace) addr := sdk.AccAddress([]byte("addr1")) @@ -198,7 +197,7 @@ func TestViewKeeper(t *testing.T) { input.ak.SetAccount(ctx, acc) require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins())) - bankKeeper.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) + input.k.SetCoins(ctx, addr, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10))) require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) // Test HasCoins @@ -216,8 +215,6 @@ func TestVestingAccountSend(t *testing.T) { origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(types.DefaultParamspace), types.DefaultCodespace) - bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) @@ -227,7 +224,7 @@ func TestVestingAccountSend(t *testing.T) { input.ak.SetAccount(ctx, vacc) // require that no coins be sendable at the beginning of the vesting schedule - err := bankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) + err := input.k.SendCoins(ctx, addr1, addr2, sendCoins) require.Error(t, err) // receive some coins @@ -236,7 +233,7 @@ func TestVestingAccountSend(t *testing.T) { // require that all vested coins are spendable plus any received ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) - err = bankKeeper.SendCoins(ctx, addr1, addr2, sendCoins) + err = input.k.SendCoins(ctx, addr1, addr2, sendCoins) vacc = input.ak.GetAccount(ctx, addr1).(*auth.ContinuousVestingAccount) require.NoError(t, err) require.Equal(t, origCoins, vacc.GetCoins()) @@ -250,8 +247,6 @@ func TestVestingAccountReceive(t *testing.T) { origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(types.DefaultParamspace), types.DefaultCodespace) - bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) @@ -262,10 +257,10 @@ func TestVestingAccountReceive(t *testing.T) { acc := input.ak.NewAccountWithAddress(ctx, addr2) input.ak.SetAccount(ctx, vacc) input.ak.SetAccount(ctx, acc) - bankKeeper.SetCoins(ctx, addr2, origCoins) + input.k.SetCoins(ctx, addr2, origCoins) // send some coins to the vesting account - bankKeeper.SendCoins(ctx, addr2, addr1, sendCoins) + input.k.SendCoins(ctx, addr2, addr1, sendCoins) // require the coins are spendable vacc = input.ak.GetAccount(ctx, addr1).(*auth.ContinuousVestingAccount) @@ -284,8 +279,6 @@ func TestDelegateCoins(t *testing.T) { origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(types.DefaultParamspace), types.DefaultCodespace) - bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) @@ -296,18 +289,18 @@ func TestDelegateCoins(t *testing.T) { acc := input.ak.NewAccountWithAddress(ctx, addr2) input.ak.SetAccount(ctx, vacc) input.ak.SetAccount(ctx, acc) - bankKeeper.SetCoins(ctx, addr2, origCoins) + input.k.SetCoins(ctx, addr2, origCoins) ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) // require the ability for a non-vesting account to delegate - _, err := bankKeeper.DelegateCoins(ctx, addr2, delCoins) + _, err := input.k.DelegateCoins(ctx, addr2, delCoins) acc = input.ak.GetAccount(ctx, addr2) require.NoError(t, err) require.Equal(t, delCoins, acc.GetCoins()) // require the ability for a vesting account to delegate - _, err = bankKeeper.DelegateCoins(ctx, addr1, delCoins) + _, err = input.k.DelegateCoins(ctx, addr1, delCoins) vacc = input.ak.GetAccount(ctx, addr1).(*auth.ContinuousVestingAccount) require.NoError(t, err) require.Equal(t, delCoins, vacc.GetCoins()) @@ -321,8 +314,6 @@ func TestUndelegateCoins(t *testing.T) { origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(types.DefaultParamspace), types.DefaultCodespace) - bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) addr2 := sdk.AccAddress([]byte("addr2")) @@ -333,27 +324,27 @@ func TestUndelegateCoins(t *testing.T) { acc := input.ak.NewAccountWithAddress(ctx, addr2) input.ak.SetAccount(ctx, vacc) input.ak.SetAccount(ctx, acc) - bankKeeper.SetCoins(ctx, addr2, origCoins) + input.k.SetCoins(ctx, addr2, origCoins) ctx = ctx.WithBlockTime(now.Add(12 * time.Hour)) // require the ability for a non-vesting account to delegate - _, err := bankKeeper.DelegateCoins(ctx, addr2, delCoins) + _, err := input.k.DelegateCoins(ctx, addr2, delCoins) require.NoError(t, err) // require the ability for a non-vesting account to undelegate - _, err = bankKeeper.UndelegateCoins(ctx, addr2, delCoins) + _, err = input.k.UndelegateCoins(ctx, addr2, delCoins) require.NoError(t, err) acc = input.ak.GetAccount(ctx, addr2) require.Equal(t, origCoins, acc.GetCoins()) // require the ability for a vesting account to delegate - _, err = bankKeeper.DelegateCoins(ctx, addr1, delCoins) + _, err = input.k.DelegateCoins(ctx, addr1, delCoins) require.NoError(t, err) // require the ability for a vesting account to undelegate - _, err = bankKeeper.UndelegateCoins(ctx, addr1, delCoins) + _, err = input.k.UndelegateCoins(ctx, addr1, delCoins) require.NoError(t, err) vacc = input.ak.GetAccount(ctx, addr1).(*auth.ContinuousVestingAccount) diff --git a/x/bank/internal/keeper/querier.go b/x/bank/internal/keeper/querier.go new file mode 100644 index 000000000000..b02d7dee26ec --- /dev/null +++ b/x/bank/internal/keeper/querier.go @@ -0,0 +1,45 @@ +package keeper + +import ( + "fmt" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/internal/types" +) + +const ( + QueryBalance = "balances" +) + +// NewQuerier returns a new sdk.Keeper instance. +func NewQuerier(k Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + switch path[0] { + case QueryBalance: + return queryBalance(ctx, req, k) + + default: + return nil, sdk.ErrUnknownRequest("unknown bank query endpoint") + } + } +} + +// queryBalance fetch an account's balance for the supplied height. +// Height and account address are passed as first and second path components respectively. +func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + var params types.QueryBalanceParams + + if err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + } + + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, k.GetCoins(ctx, params.Address)) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + } + + return bz, nil +} diff --git a/x/bank/internal/keeper/querier_test.go b/x/bank/internal/keeper/querier_test.go new file mode 100644 index 000000000000..0d1d1cdee52b --- /dev/null +++ b/x/bank/internal/keeper/querier_test.go @@ -0,0 +1,59 @@ +package keeper + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/bank/internal/types" +) + +func TestBalances(t *testing.T) { + input := setupTestInput() + req := abci.RequestQuery{ + Path: fmt.Sprintf("custom/bank/%s", QueryBalance), + Data: []byte{}, + } + + querier := NewQuerier(input.k) + + res, err := querier(input.ctx, []string{"balances"}, req) + require.NotNil(t, err) + require.Nil(t, res) + + _, _, addr := authtypes.KeyTestPubAddr() + req.Data = input.cdc.MustMarshalJSON(types.NewQueryBalanceParams(addr)) + res, err = querier(input.ctx, []string{"balances"}, req) + require.Nil(t, err) // the account does not exist, no error returned anyway + require.NotNil(t, res) + + var coins sdk.Coins + require.NoError(t, input.cdc.UnmarshalJSON(res, &coins)) + require.True(t, coins.IsZero()) + + acc := input.ak.NewAccountWithAddress(input.ctx, addr) + acc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("foo", 10))) + input.ak.SetAccount(input.ctx, acc) + res, err = querier(input.ctx, []string{"balances"}, req) + require.Nil(t, err) + require.NotNil(t, res) + require.NoError(t, input.cdc.UnmarshalJSON(res, &coins)) + require.True(t, coins.AmountOf("foo").Equal(sdk.NewInt(10))) +} + +func TestQuerierRouteNotFound(t *testing.T) { + input := setupTestInput() + req := abci.RequestQuery{ + Path: "custom/bank/notfound", + Data: []byte{}, + } + + querier := NewQuerier(input.k) + _, err := querier(input.ctx, []string{"notfound"}, req) + require.Error(t, err) +} diff --git a/x/bank/internal/types/key.go b/x/bank/internal/types/key.go index b894b78ed913..7e38aeb52487 100644 --- a/x/bank/internal/types/key.go +++ b/x/bank/internal/types/key.go @@ -2,5 +2,6 @@ package types const ( // module name - ModuleName = "bank" + ModuleName = "bank" + QuerierRoute = ModuleName ) diff --git a/x/bank/internal/types/querier.go b/x/bank/internal/types/querier.go new file mode 100644 index 000000000000..ef0a8576b879 --- /dev/null +++ b/x/bank/internal/types/querier.go @@ -0,0 +1,15 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// QueryBalanceParams defines the params for querying an account balance. +type QueryBalanceParams struct { + Address sdk.AccAddress +} + +// NewQueryBalanceParams creates a new instance of QueryBalanceParams. +func NewQueryBalanceParams(addr sdk.AccAddress) QueryBalanceParams { + return QueryBalanceParams{Address: addr} +} diff --git a/x/bank/module.go b/x/bank/module.go index eb0b85634800..b75ed286c6a8 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -26,8 +26,6 @@ var ( // app module basics object type AppModuleBasic struct{} -var _ module.AppModuleBasic = AppModuleBasic{} - // module name func (AppModuleBasic) Name() string { return ModuleName } @@ -94,10 +92,12 @@ func (AppModule) Route() string { return RouterKey } func (am AppModule) NewHandler() sdk.Handler { return NewHandler(am.keeper) } // module querier route name -func (AppModule) QuerierRoute() string { return "" } +func (AppModule) QuerierRoute() string { return RouterKey } // module querier -func (AppModule) NewQuerierHandler() sdk.Querier { return nil } +func (am AppModule) NewQuerierHandler() sdk.Querier { + return keeper.NewQuerier(am.keeper) +} // module init-genesis func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {