Merge PR #4788: Query genesis transactions

This commit is contained in:
colin axner 2019-08-01 11:56:50 -07:00 committed by Alexander Bezobchuk
parent fd92504f84
commit 2e3c52bae1
27 changed files with 158 additions and 58 deletions

View File

@ -0,0 +1 @@
# 3867 Allow querying for genesis transaction when height query param is set to zero.

View File

@ -142,7 +142,7 @@ func NewSimApp(
// add keepers // add keepers
app.accountKeeper = auth.NewAccountKeeper(app.cdc, keys[auth.StoreKey], authSubspace, auth.ProtoBaseAccount) app.accountKeeper = auth.NewAccountKeeper(app.cdc, keys[auth.StoreKey], authSubspace, auth.ProtoBaseAccount)
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace, app.ModuleAccountAddrs()) app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace, app.ModuleAccountAddrs())
app.supplyKeeper = supply.NewKeeper(app.cdc, keys[supply.StoreKey], app.accountKeeper, app.bankKeeper, supply.DefaultCodespace, maccPerms) app.supplyKeeper = supply.NewKeeper(app.cdc, keys[supply.StoreKey], app.accountKeeper, app.bankKeeper, maccPerms)
stakingKeeper := staking.NewKeeper(app.cdc, keys[staking.StoreKey], tkeys[staking.TStoreKey], stakingKeeper := staking.NewKeeper(app.cdc, keys[staking.StoreKey], tkeys[staking.TStoreKey],
app.supplyKeeper, stakingSubspace, staking.DefaultCodespace) app.supplyKeeper, stakingSubspace, staking.DefaultCodespace)
app.mintKeeper = mint.NewKeeper(app.cdc, keys[mint.StoreKey], mintSubspace, &stakingKeeper, app.supplyKeeper, auth.FeeCollectorName) app.mintKeeper = mint.NewKeeper(app.cdc, keys[mint.StoreKey], mintSubspace, &stakingKeeper, app.supplyKeeper, auth.FeeCollectorName)

View File

@ -3,6 +3,7 @@ package rest
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"strconv"
"strings" "strings"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -12,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
"github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/types"
genutilrest "github.com/cosmos/cosmos-sdk/x/genutil/client/rest"
) )
// query accountREST Handler // query accountREST Handler
@ -50,16 +52,11 @@ func QueryAccountRequestHandlerFn(storeName string, cliCtx context.CLIContext) h
} }
} }
// QueryTxsByEventsRequestHandlerFn implements a REST handler that searches for // QueryTxsHandlerFn implements a REST handler that searches for transactions.
// transactions by events. // Genesis transactions are returned if the height parameter is set to zero,
func QueryTxsByEventsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // otherwise the transactions are searched for by events.
func QueryTxsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var (
tags []string
txs []sdk.TxResponse
page, limit int
)
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, rest.WriteErrorResponse(w, http.StatusBadRequest,
@ -67,6 +64,21 @@ func QueryTxsByEventsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFun
return return
} }
// if the height query param is set to zero, query for genesis transactions
heightStr := r.FormValue("height")
if heightStr != "" {
if height, err := strconv.ParseInt(heightStr, 10, 64); err == nil && height == 0 {
genutilrest.QueryGenesisTxs(cliCtx, w)
return
}
}
var (
events []string
txs []sdk.TxResponse
page, limit int
)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok { if !ok {
return return
@ -77,13 +89,13 @@ func QueryTxsByEventsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFun
return return
} }
tags, page, limit, err = rest.ParseHTTPArgs(r) events, page, limit, err = rest.ParseHTTPArgs(r)
if err != nil { if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return return
} }
searchResult, err := utils.QueryTxsByEvents(cliCtx, tags, page, limit) searchResult, err := utils.QueryTxsByEvents(cliCtx, events, page, limit)
if err != nil { if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return return

View File

@ -16,7 +16,7 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, storeName string)
// RegisterTxRoutes registers all transaction routes on the provided router. // RegisterTxRoutes registers all transaction routes on the provided router.
func RegisterTxRoutes(cliCtx context.CLIContext, r *mux.Router) { func RegisterTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/txs", QueryTxsByEventsRequestHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/txs", QueryTxsRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/txs", BroadcastTxRequest(cliCtx)).Methods("POST") r.HandleFunc("/txs", BroadcastTxRequest(cliCtx)).Methods("POST")
r.HandleFunc("/txs/encode", EncodeTxRequestHandlerFn(cliCtx)).Methods("POST") r.HandleFunc("/txs/encode", EncodeTxRequestHandlerFn(cliCtx)).Methods("POST")
} }

View File

@ -138,7 +138,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64,
staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.NotBondedPoolName: {supply.Burner, supply.Staking},
staking.BondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking},
} }
supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, supply.DefaultCodespace, maccPerms) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms)
sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
sk.SetParams(ctx, staking.DefaultParams()) sk.SetParams(ctx, staking.DefaultParams())

View File

@ -0,0 +1,41 @@
package rest
import (
"net/http"
"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/genutil/types"
)
// QueryGenesisTxs writes the genesis transactions to the response if no error
// occurs.
func QueryGenesisTxs(cliCtx context.CLIContext, w http.ResponseWriter) {
resultGenesis, err := cliCtx.Client.Genesis()
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError,
sdk.AppendMsgToErr("could not retrieve genesis from client", err.Error()))
return
}
appState, err := types.GenesisStateFromGenDoc(cliCtx.Codec, *resultGenesis.Genesis)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError,
sdk.AppendMsgToErr("could not decode genesis doc", err.Error()))
return
}
genState := types.GetGenesisStateFromAppState(cliCtx.Codec, appState)
genTxs := make([]sdk.Tx, len(genState.GenTxs))
for i, tx := range genState.GenTxs {
err := cliCtx.Codec.UnmarshalJSON(tx, &genTxs[i])
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError,
sdk.AppendMsgToErr("could not decode genesis transaction", err.Error()))
return
}
}
rest.PostProcessResponse(w, cliCtx, genTxs)
}

View File

@ -74,7 +74,7 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a
staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.NotBondedPoolName: {supply.Burner, supply.Staking},
staking.BondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking},
} }
supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, supply.DefaultCodespace, maccPerms) supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, maccPerms)
sk := staking.NewKeeper(mApp.Cdc, keyStaking, tKeyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) sk := staking.NewKeeper(mApp.Cdc, keyStaking, tKeyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
keeper := NewKeeper(mApp.Cdc, keyGov, pk, pk.Subspace(DefaultParamspace), supplyKeeper, sk, DefaultCodespace, rtr) keeper := NewKeeper(mApp.Cdc, keyGov, pk, pk.Subspace(DefaultParamspace), supplyKeeper, sk, DefaultCodespace, rtr)

View File

@ -74,7 +74,7 @@ func newTestInput(t *testing.T) testInput {
staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.NotBondedPoolName: {supply.Burner, supply.Staking},
staking.BondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking},
} }
supplyKeeper := supply.NewKeeper(types.ModuleCdc, keySupply, accountKeeper, bankKeeper, supply.DefaultCodespace, maccPerms) supplyKeeper := supply.NewKeeper(types.ModuleCdc, keySupply, accountKeeper, bankKeeper, maccPerms)
supplyKeeper.SetSupply(ctx, supply.NewSupply(sdk.Coins{})) supplyKeeper.SetSupply(ctx, supply.NewSupply(sdk.Coins{}))
stakingKeeper := staking.NewKeeper( stakingKeeper := staking.NewKeeper(

View File

@ -53,7 +53,7 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) {
staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.NotBondedPoolName: {supply.Burner, supply.Staking},
staking.BondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking},
} }
supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, bankKeeper, supply.DefaultCodespace, maccPerms) supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, bankKeeper, maccPerms)
stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace) keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace)
mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper)) mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper))

View File

@ -99,7 +99,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee
staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.NotBondedPoolName: {supply.Burner, supply.Staking},
staking.BondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking},
} }
supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, supply.DefaultCodespace, maccPerms) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, maccPerms)
totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs))))) totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs)))))
supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply))

View File

@ -41,7 +41,7 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) {
types.NotBondedPoolName: {supply.Burner, supply.Staking}, types.NotBondedPoolName: {supply.Burner, supply.Staking},
types.BondedPoolName: {supply.Burner, supply.Staking}, types.BondedPoolName: {supply.Burner, supply.Staking},
} }
supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bankKeeper, supply.DefaultCodespace, maccPerms) supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bankKeeper, maccPerms)
keeper := NewKeeper(mApp.Cdc, keyStaking, tkeyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace) keeper := NewKeeper(mApp.Cdc, keyStaking, tkeyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace)
mApp.Router().AddRoute(RouterKey, NewHandler(keeper)) mApp.Router().AddRoute(RouterKey, NewHandler(keeper))

View File

@ -62,7 +62,7 @@ func (k Keeper) TotalBondedTokens(ctx sdk.Context) sdk.Int {
// StakingTokenSupply staking tokens from the total supply // StakingTokenSupply staking tokens from the total supply
func (k Keeper) StakingTokenSupply(ctx sdk.Context) sdk.Int { func (k Keeper) StakingTokenSupply(ctx sdk.Context) sdk.Int {
return k.supplyKeeper.GetSupply(ctx).Total.AmountOf(k.BondDenom(ctx)) return k.supplyKeeper.GetSupply(ctx).GetTotal().AmountOf(k.BondDenom(ctx))
} }
// BondedRatio the fraction of the staking tokens which are currently bonded // BondedRatio the fraction of the staking tokens which are currently bonded

View File

@ -24,7 +24,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/supply"
"github.com/cosmos/cosmos-sdk/x/supply/exported"
) )
// dummy addresses used for testing // dummy addresses used for testing
@ -70,8 +69,7 @@ func MakeTestCodec() *codec.Codec {
// Register AppAccount // Register AppAccount
cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterInterface((*auth.Account)(nil), nil)
cdc.RegisterConcrete(&auth.BaseAccount{}, "test/staking/BaseAccount", nil) cdc.RegisterConcrete(&auth.BaseAccount{}, "test/staking/BaseAccount", nil)
cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) supply.RegisterCodec(cdc)
cdc.RegisterConcrete(&supply.ModuleAccount{}, "test/staking/ModuleAccount", nil)
codec.RegisterCrypto(cdc) codec.RegisterCrypto(cdc)
return cdc return cdc
@ -139,7 +137,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context
types.NotBondedPoolName: {supply.Burner, supply.Staking}, types.NotBondedPoolName: {supply.Burner, supply.Staking},
types.BondedPoolName: {supply.Burner, supply.Staking}, types.BondedPoolName: {supply.Burner, supply.Staking},
} }
supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, supply.DefaultCodespace, maccPerms) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, maccPerms)
initTokens := sdk.TokensFromConsensusPower(initPower) initTokens := sdk.TokensFromConsensusPower(initPower)
initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens)) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))

View File

@ -4,7 +4,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported" stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported"
"github.com/cosmos/cosmos-sdk/x/supply"
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
) )
@ -21,7 +20,7 @@ type AccountKeeper interface {
// SupplyKeeper defines the expected supply Keeper (noalias) // SupplyKeeper defines the expected supply Keeper (noalias)
type SupplyKeeper interface { type SupplyKeeper interface {
GetSupply(ctx sdk.Context) supply.Supply GetSupply(ctx sdk.Context) supplyexported.SupplyI
GetModuleAddress(name string) sdk.AccAddress GetModuleAddress(name string) sdk.AccAddress
GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI

View File

@ -1,11 +1,29 @@
package exported package exported
import "github.com/cosmos/cosmos-sdk/x/auth/exported" import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/exported"
)
// ModuleAccountI defines an account interface for modules that hold tokens in an escrow // ModuleAccountI defines an account interface for modules that hold tokens in an escrow
type ModuleAccountI interface { type ModuleAccountI interface {
exported.Account exported.Account
GetName() string GetName() string
GetPermissions() []string GetPermissions() []string
HasPermission(string) bool HasPermission(string) bool
} }
// SupplyI defines an inflationary supply interface for modules that handle
// token supply.
type SupplyI interface {
GetTotal() sdk.Coins
SetTotal(total sdk.Coins) SupplyI
Inflate(amount sdk.Coins) SupplyI
Deflate(amount sdk.Coins) SupplyI
String() string
ValidateBasic() error
}

View File

@ -11,7 +11,7 @@ import (
// CONTRACT: all types of accounts must have been already initialized/created // CONTRACT: all types of accounts must have been already initialized/created
func InitGenesis(ctx sdk.Context, keeper Keeper, ak types.AccountKeeper, data GenesisState) { func InitGenesis(ctx sdk.Context, keeper Keeper, ak types.AccountKeeper, data GenesisState) {
// manually set the total supply based on accounts if not provided // manually set the total supply based on accounts if not provided
if data.Supply.Total.Empty() { if data.Supply.GetTotal().Empty() {
var totalSupply sdk.Coins var totalSupply sdk.Coins
ak.IterateAccounts(ctx, ak.IterateAccounts(ctx,
func(acc authexported.Account) (stop bool) { func(acc authexported.Account) (stop bool) {
@ -19,8 +19,10 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, ak types.AccountKeeper, data Ge
return false return false
}, },
) )
data.Supply.Total = totalSupply
data.Supply = data.Supply.SetTotal(totalSupply)
} }
keeper.SetSupply(ctx, data.Supply) keeper.SetSupply(ctx, data.Supply)
} }

View File

@ -105,7 +105,8 @@ func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk
// update total supply // update total supply
supply := k.GetSupply(ctx) supply := k.GetSupply(ctx)
supply.Inflate(amt) supply = supply.Inflate(amt)
k.SetSupply(ctx, supply) k.SetSupply(ctx, supply)
logger := k.Logger(ctx) logger := k.Logger(ctx)
@ -135,7 +136,7 @@ func (k Keeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk
// update total supply // update total supply
supply := k.GetSupply(ctx) supply := k.GetSupply(ctx)
supply.Deflate(amt) supply = supply.Deflate(amt)
k.SetSupply(ctx, supply) k.SetSupply(ctx, supply)
logger := k.Logger(ctx) logger := k.Logger(ctx)

View File

@ -94,7 +94,7 @@ func TestMintCoins(t *testing.T) {
err := keeper.MintCoins(ctx, types.Minter, initCoins) err := keeper.MintCoins(ctx, types.Minter, initCoins)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, initCoins, getCoinsByName(ctx, keeper, types.Minter)) require.Equal(t, initCoins, getCoinsByName(ctx, keeper, types.Minter))
require.Equal(t, initialSupply.Total.Add(initCoins), keeper.GetSupply(ctx).Total) require.Equal(t, initialSupply.GetTotal().Add(initCoins), keeper.GetSupply(ctx).GetTotal())
// test same functionality on module account with multiple permissions // test same functionality on module account with multiple permissions
initialSupply = keeper.GetSupply(ctx) initialSupply = keeper.GetSupply(ctx)
@ -102,7 +102,7 @@ func TestMintCoins(t *testing.T) {
err = keeper.MintCoins(ctx, multiPermAcc.GetName(), initCoins) err = keeper.MintCoins(ctx, multiPermAcc.GetName(), initCoins)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, initCoins, getCoinsByName(ctx, keeper, multiPermAcc.GetName())) require.Equal(t, initCoins, getCoinsByName(ctx, keeper, multiPermAcc.GetName()))
require.Equal(t, initialSupply.Total.Add(initCoins), keeper.GetSupply(ctx).Total) require.Equal(t, initialSupply.GetTotal().Add(initCoins), keeper.GetSupply(ctx).GetTotal())
require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }) require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) })
} }
@ -115,22 +115,22 @@ func TestBurnCoins(t *testing.T) {
keeper.SetModuleAccount(ctx, burnerAcc) keeper.SetModuleAccount(ctx, burnerAcc)
initialSupply := keeper.GetSupply(ctx) initialSupply := keeper.GetSupply(ctx)
initialSupply.Inflate(initCoins) initialSupply = initialSupply.Inflate(initCoins)
keeper.SetSupply(ctx, initialSupply) keeper.SetSupply(ctx, initialSupply)
require.Error(t, keeper.BurnCoins(ctx, "", initCoins), "no module account") require.Error(t, keeper.BurnCoins(ctx, "", initCoins), "no module account")
require.Panics(t, func() { keeper.BurnCoins(ctx, types.Minter, initCoins) }, "invalid permission") require.Panics(t, func() { keeper.BurnCoins(ctx, types.Minter, initCoins) }, "invalid permission")
require.Panics(t, func() { keeper.BurnCoins(ctx, randomPerm, initialSupply.Total) }, "random permission") require.Panics(t, func() { keeper.BurnCoins(ctx, randomPerm, initialSupply.GetTotal()) }, "random permission")
require.Panics(t, func() { keeper.BurnCoins(ctx, types.Burner, initialSupply.Total) }, "insufficient coins") require.Panics(t, func() { keeper.BurnCoins(ctx, types.Burner, initialSupply.GetTotal()) }, "insufficient coins")
err := keeper.BurnCoins(ctx, types.Burner, initCoins) err := keeper.BurnCoins(ctx, types.Burner, initCoins)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, types.Burner)) require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, types.Burner))
require.Equal(t, initialSupply.Total.Sub(initCoins), keeper.GetSupply(ctx).Total) require.Equal(t, initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal())
// test same functionality on module account with multiple permissions // test same functionality on module account with multiple permissions
initialSupply = keeper.GetSupply(ctx) initialSupply = keeper.GetSupply(ctx)
initialSupply.Inflate(initCoins) initialSupply = initialSupply.Inflate(initCoins)
keeper.SetSupply(ctx, initialSupply) keeper.SetSupply(ctx, initialSupply)
require.NoError(t, multiPermAcc.SetCoins(initCoins)) require.NoError(t, multiPermAcc.SetCoins(initCoins))
@ -139,5 +139,5 @@ func TestBurnCoins(t *testing.T) {
err = keeper.BurnCoins(ctx, multiPermAcc.GetName(), initCoins) err = keeper.BurnCoins(ctx, multiPermAcc.GetName(), initCoins)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, multiPermAcc.GetName())) require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, multiPermAcc.GetName()))
require.Equal(t, initialSupply.Total.Sub(initCoins), keeper.GetSupply(ctx).Total) require.Equal(t, initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal())
} }

View File

@ -88,7 +88,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64, nAccs int64)
multiPerm: {types.Minter, types.Burner, types.Staking}, multiPerm: {types.Minter, types.Burner, types.Staking},
randomPerm: {"random"}, randomPerm: {"random"},
} }
keeper := NewKeeper(cdc, keySupply, ak, bk, DefaultCodespace, maccPerms) keeper := NewKeeper(cdc, keySupply, ak, bk, maccPerms)
totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, valTokens.MulRaw(nAccs))) totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, valTokens.MulRaw(nAccs)))
keeper.SetSupply(ctx, types.NewSupply(totalSupply)) keeper.SetSupply(ctx, types.NewSupply(totalSupply))

View File

@ -31,12 +31,12 @@ func TotalSupply(k Keeper) sdk.Invariant {
return false return false
}) })
broken := !expectedTotal.IsEqual(supply.Total) broken := !expectedTotal.IsEqual(supply.GetTotal())
return sdk.FormatInvariant(types.ModuleName, "total supply", return sdk.FormatInvariant(types.ModuleName, "total supply",
fmt.Sprintf( fmt.Sprintf(
"\tsum of accounts coins: %v\n"+ "\tsum of accounts coins: %v\n"+
"\tsupply.Total: %v\n", "\tsupply.Total: %v\n",
expectedTotal, supply.Total), broken) expectedTotal, supply.GetTotal()), broken)
} }
} }

View File

@ -21,9 +21,7 @@ type Keeper struct {
} }
// NewKeeper creates a new Keeper instance // NewKeeper creates a new Keeper instance
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ak types.AccountKeeper, bk types.BankKeeper, func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ak types.AccountKeeper, bk types.BankKeeper, maccPerms map[string][]string) Keeper {
codespace sdk.CodespaceType, maccPerms map[string][]string) Keeper {
// set the addresses // set the addresses
permAddrs := make(map[string]types.PermissionsForAddress) permAddrs := make(map[string]types.PermissionsForAddress)
for name, perms := range maccPerms { for name, perms := range maccPerms {
@ -45,7 +43,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
} }
// GetSupply retrieves the Supply from store // GetSupply retrieves the Supply from store
func (k Keeper) GetSupply(ctx sdk.Context) (supply types.Supply) { func (k Keeper) GetSupply(ctx sdk.Context) (supply exported.SupplyI) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
b := store.Get(SupplyKey) b := store.Get(SupplyKey)
if b == nil { if b == nil {
@ -56,7 +54,7 @@ func (k Keeper) GetSupply(ctx sdk.Context) (supply types.Supply) {
} }
// SetSupply sets the Supply to store // SetSupply sets the Supply to store
func (k Keeper) SetSupply(ctx sdk.Context, supply types.Supply) { func (k Keeper) SetSupply(ctx sdk.Context, supply exported.SupplyI) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshalBinaryLengthPrefixed(supply) b := k.cdc.MustMarshalBinaryLengthPrefixed(supply)
store.Set(SupplyKey, b) store.Set(SupplyKey, b)

View File

@ -16,7 +16,7 @@ func TestSupply(t *testing.T) {
ctx, _, keeper := createTestInput(t, false, initialPower, nAccs) ctx, _, keeper := createTestInput(t, false, initialPower, nAccs)
total := keeper.GetSupply(ctx).Total total := keeper.GetSupply(ctx).GetTotal()
expectedTotal := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens.MulRaw(nAccs))) expectedTotal := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens.MulRaw(nAccs)))
require.Equal(t, expectedTotal, total) require.Equal(t, expectedTotal, total)

View File

@ -14,10 +14,13 @@ import (
func NewQuerier(k Keeper) sdk.Querier { func NewQuerier(k Keeper) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) {
switch path[0] { switch path[0] {
case types.QueryTotalSupply: case types.QueryTotalSupply:
return queryTotalSupply(ctx, req, k) return queryTotalSupply(ctx, req, k)
case types.QuerySupplyOf: case types.QuerySupplyOf:
return querySupplyOf(ctx, req, k) return querySupplyOf(ctx, req, k)
default: default:
return nil, sdk.ErrUnknownRequest("unknown supply query endpoint") return nil, sdk.ErrUnknownRequest("unknown supply query endpoint")
} }
@ -32,7 +35,7 @@ func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte,
return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err))
} }
totalSupply := k.GetSupply(ctx).Total totalSupply := k.GetSupply(ctx).GetTotal()
start, end := client.Paginate(len(totalSupply), params.Page, params.Limit, 100) start, end := client.Paginate(len(totalSupply), params.Page, params.Limit, 100)
if start < 0 || end < 0 { if start < 0 || end < 0 {
@ -57,7 +60,7 @@ func querySupplyOf(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sd
return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err))
} }
supply := k.GetSupply(ctx).Total.AmountOf(params.Denom) supply := k.GetSupply(ctx).GetTotal().AmountOf(params.Denom)
res, err := supply.MarshalJSON() res, err := supply.MarshalJSON()
if err != nil { if err != nil {

View File

@ -8,7 +8,9 @@ import (
// RegisterCodec registers the account types and interface // RegisterCodec registers the account types and interface
func RegisterCodec(cdc *codec.Codec) { func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil) cdc.RegisterInterface((*exported.ModuleAccountI)(nil), nil)
cdc.RegisterInterface((*exported.SupplyI)(nil), nil)
cdc.RegisterConcrete(&ModuleAccount{}, "cosmos-sdk/ModuleAccount", nil) cdc.RegisterConcrete(&ModuleAccount{}, "cosmos-sdk/ModuleAccount", nil)
cdc.RegisterConcrete(&Supply{}, "cosmos-sdk/Supply", nil)
} }
// ModuleCdc generic sealed codec to be used throughout module // ModuleCdc generic sealed codec to be used throughout module

View File

@ -1,12 +1,16 @@
package types package types
import (
"github.com/cosmos/cosmos-sdk/x/supply/exported"
)
// GenesisState is the supply state that must be provided at genesis. // GenesisState is the supply state that must be provided at genesis.
type GenesisState struct { type GenesisState struct {
Supply Supply `json:"supply" yaml:"supply"` Supply exported.SupplyI `json:"supply" yaml:"supply"`
} }
// NewGenesisState creates a new genesis state. // NewGenesisState creates a new genesis state.
func NewGenesisState(supply Supply) GenesisState { func NewGenesisState(supply exported.SupplyI) GenesisState {
return GenesisState{supply} return GenesisState{supply}
} }

View File

@ -3,30 +3,51 @@ package types
import ( import (
"fmt" "fmt"
yaml "gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/supply/exported"
) )
// Implements Delegation interface
var _ exported.SupplyI = Supply{}
// Supply represents a struct that passively keeps track of the total supply amounts in the network // Supply represents a struct that passively keeps track of the total supply amounts in the network
type Supply struct { type Supply struct {
Total sdk.Coins `json:"total" yaml:"total"` // total supply of tokens registered on the chain Total sdk.Coins `json:"total" yaml:"total"` // total supply of tokens registered on the chain
} }
// SetTotal sets the total supply.
func (supply Supply) SetTotal(total sdk.Coins) exported.SupplyI {
supply.Total = total
return supply
}
// GetTotal returns the supply total.
func (supply Supply) GetTotal() sdk.Coins {
return supply.Total
}
// NewSupply creates a new Supply instance // NewSupply creates a new Supply instance
func NewSupply(total sdk.Coins) Supply { return Supply{total} } func NewSupply(total sdk.Coins) exported.SupplyI {
return Supply{total}
}
// DefaultSupply creates an empty Supply // DefaultSupply creates an empty Supply
func DefaultSupply() Supply { return NewSupply(sdk.NewCoins()) } func DefaultSupply() exported.SupplyI {
return NewSupply(sdk.NewCoins())
}
// Inflate adds coins to the total supply // Inflate adds coins to the total supply
func (supply *Supply) Inflate(amount sdk.Coins) { func (supply Supply) Inflate(amount sdk.Coins) exported.SupplyI {
supply.Total = supply.Total.Add(amount) supply.Total = supply.Total.Add(amount)
return supply
} }
// Deflate subtracts coins from the total supply // Deflate subtracts coins from the total supply
func (supply *Supply) Deflate(amount sdk.Coins) { func (supply Supply) Deflate(amount sdk.Coins) exported.SupplyI {
supply.Total = supply.Total.Sub(amount) supply.Total = supply.Total.Sub(amount)
return supply
} }
// String returns a human readable string representation of a supplier. // String returns a human readable string representation of a supplier.

View File

@ -14,7 +14,7 @@ import (
func TestSupplyMarshalYAML(t *testing.T) { func TestSupplyMarshalYAML(t *testing.T) {
supply := DefaultSupply() supply := DefaultSupply()
coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())) coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()))
supply.Inflate(coins) supply = supply.Inflate(coins)
bz, err := yaml.Marshal(supply) bz, err := yaml.Marshal(supply)
require.NoError(t, err) require.NoError(t, err)