From cf8a1c9f5929c5cee9783f0d21cb39d69030e92d Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 10 Apr 2019 19:53:10 +0200 Subject: [PATCH 01/46] supply and token holder --- x/supply/errors.go | 31 ++++++++++++++ x/supply/keeper.go | 90 ++++++++++++++++++++++++++++++++++++++++ x/supply/keys.go | 24 +++++++++++ x/supply/token_holder.go | 52 +++++++++++++++++++++++ 4 files changed, 197 insertions(+) create mode 100644 x/supply/errors.go create mode 100644 x/supply/keeper.go create mode 100644 x/supply/keys.go create mode 100644 x/supply/token_holder.go diff --git a/x/supply/errors.go b/x/supply/errors.go new file mode 100644 index 000000000000..764e59c46468 --- /dev/null +++ b/x/supply/errors.go @@ -0,0 +1,31 @@ +// nolint +package supply + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type CodeType = sdk.CodeType + +// define the supply errors codes +const ( + DefaultCodespace sdk.CodespaceType = ModuleName + CodeInsufficientSupply CodeType = 101 + CodeInsufficientHoldings CodeType = 102 +) + +func ErrInsufficientSupply(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError( + codespace, + CodeInsufficientSupply, + "requested tokens greater than current total supply", + ) +} + +func ErrInsufficientHoldings(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError( + codespace, + CodeInsufficientHoldings, + "insufficient token holdings", + ) +} diff --git a/x/supply/keeper.go b/x/supply/keeper.go new file mode 100644 index 000000000000..ba4208ce941a --- /dev/null +++ b/x/supply/keeper.go @@ -0,0 +1,90 @@ +package supply + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params" +) + +// Keeper of the supply store +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + paramSpace params.Subspace +} + +// NewKeeper defines the supply store keeper +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, +) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + } +} + +// GetTokenHolders returns all the token holders +func (k Keeper) GetTokenHolders(ctx sdk.Context) ( + tokenHolders []TokenHolder, err error) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) + defer iterator.Close() + + var tokenHolder TokenHolder + for ; iterator.Valid(); iterator.Next() { + err = k.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) + if err != nil { + return + } + tokenHolders = append(tokenHolders, tokenHolder) + } + return +} + +// GetTokenHolder returns a token holder instance +func (k Keeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( + tokenHolder TokenHolder) { + store := ctx.KVStore(k.storeKey) + b := store.Get(GetTokenHolderKey(moduleName)) + if b == nil { + panic(fmt.Sprintf("module %s is not in store", moduleName)) + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) + return +} + +// SetTokenHolder sets a holder to store +func (k Keeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { + store := ctx.KVStore(k.storeKey) + holderKey := GetTokenHolderKey(tokenHolder.module) + b := k.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) + store.Set(holderKey, b) +} + +// GetTotalSupply returns the total supply of the network +func (k Keeper) GetTotalSupply(ctx sdk.Context) (totalSupply sdk.Coins) { + holders, err := k.GetTokenHolders(ctx) + if err != nil { + panic(err) + } + + for _, holder := range holders { + totalSupply = totalSupply.Add(holder.GetHoldings()) + } + return +} + +// GetSupplyOf returns a coin's total supply +func (k Keeper) GetSupplyOf(ctx sdk.Context, denom string) (supply sdk.Int) { + holders, err := k.GetTokenHolders(ctx) + if err != nil { + panic(err) + } + + for _, holder := range holders { + supply = supply.Add(holder.GetHoldingsOf(denom)) + } + return +} diff --git a/x/supply/keys.go b/x/supply/keys.go new file mode 100644 index 000000000000..948b2bdb5f76 --- /dev/null +++ b/x/supply/keys.go @@ -0,0 +1,24 @@ +package supply + +const ( + // ModuleName is the name of the module + ModuleName = "supply" + + // DefaultParamspace for params keeper + DefaultParamspace = ModuleName + + // StoreKey is the default store key for mint + StoreKey = ModuleName + + // QuerierRoute is the querier route for the suply store. + QuerierRoute = StoreKey +) + +var ( + holderKeyPrefix = []byte{0x00} +) + +// GetTokenHolderKey returns the store key of the given module +func GetTokenHolderKey(moduleName string) []byte { + return append(holderKeyPrefix, []byte(moduleName)...) +} diff --git a/x/supply/token_holder.go b/x/supply/token_holder.go new file mode 100644 index 000000000000..62fe9b01838b --- /dev/null +++ b/x/supply/token_holder.go @@ -0,0 +1,52 @@ +package supply + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TokenHolder defines an instance of a module that holds tokens +type TokenHolder struct { + module string + tokenHoldings sdk.Coins +} + +// NewTokenHolder creates a new TokenHolder instance +func NewTokenHolder(moduleName string, initialHoldings sdk.Coins) TokenHolder { + return TokenHolder{ + module: moduleName, + tokenHoldings: initialHoldings, + } +} + +// GetHoldings returns the total tokens held by a module +func (tk TokenHolder) GetHoldings() sdk.Coins { + return tk.tokenHoldings +} + +// GetHoldingsOf returns the a total coin denom holdings retained by a module +func (tk TokenHolder) GetHoldingsOf(denom string) sdk.Int { + return tk.tokenHoldings.AmountOf(denom) +} + +// RequestTokens re +func (tk TokenHolder) RequestTokens(amount sdk.Coins) (err sdk.Error) { + // get available supply (not held by a module or account) + // check if supply > amount + // + return +} + +// RelinquishTokens hands over a portion of the module's holdings +func (tk TokenHolder) RelinquishTokens(amount sdk.Coins) (err sdk.Error) { + holdings := tk.GetHoldings() + if !holdings.IsAllGTE(amount) { + return ErrInsufficientHoldings(DefaultCodespace) + } + tk.setTokenHoldings(holdings.Sub(amount)) + return +} + +// set new token holdings +func (tk *TokenHolder) setTokenHoldings(amount sdk.Coins) { + tk.tokenHoldings = amount +} From f36e8a843441e4d877f75c7e741eefd053e0b202 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 11 Apr 2019 00:24:58 +0200 Subject: [PATCH 02/46] move logic to bank module --- x/bank/errors.go | 11 ++-- x/bank/genesis.go | 37 +++++++++-- x/bank/keeper.go | 126 ++++++++++++++++++++++++++++++++++--- x/{supply => bank}/keys.go | 7 +-- x/bank/token_holder.go | 51 +++++++++++++++ x/supply/errors.go | 31 --------- x/supply/keeper.go | 90 -------------------------- x/supply/token_holder.go | 52 --------------- 8 files changed, 209 insertions(+), 196 deletions(-) rename x/{supply => bank}/keys.go (79%) create mode 100644 x/bank/token_holder.go delete mode 100644 x/supply/errors.go delete mode 100644 x/supply/keeper.go delete mode 100644 x/supply/token_holder.go diff --git a/x/bank/errors.go b/x/bank/errors.go index e76debe30394..b74f64cc4bb2 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -4,17 +4,20 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// CodeType definition +type CodeType = sdk.CodeType + // Bank errors reserve 100 ~ 199. const ( - DefaultCodespace sdk.CodespaceType = "bank" + DefaultCodespace sdk.CodespaceType = ModuleName - CodeSendDisabled sdk.CodeType = 101 - CodeInvalidInputsOutputs sdk.CodeType = 102 + CodeSendDisabled CodeType = 101 + CodeInvalidInputsOutputs CodeType = 102 ) // ErrNoInputs is an error func ErrNoInputs(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInputsOutputs, "no inputs to send transacction") + return sdk.NewError(codespace, CodeInvalidInputsOutputs, "no inputs to send transaction") } // ErrNoOutputs is an error diff --git a/x/bank/genesis.go b/x/bank/genesis.go index 1bdf4e7ff92a..6dc22b8b6964 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -1,32 +1,57 @@ package bank import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) // GenesisState is the bank state that must be provided at genesis. type GenesisState struct { - SendEnabled bool `json:"send_enabled"` + SendEnabled bool `json:"send_enabled"` + CirculatingSupply sdk.Coins `json:"circulating_supply"` + ModulesHoldings []TokenHolder `json:"modules_holdings"` } // NewGenesisState creates a new genesis state. -func NewGenesisState(sendEnabled bool) GenesisState { - return GenesisState{SendEnabled: sendEnabled} +func NewGenesisState( + sendEnabled bool, circulatingSupply sdk.Coins, holdings []TokenHolder, +) GenesisState { + return GenesisState{ + SendEnabled: sendEnabled, + CirculatingSupply: circulatingSupply, + ModulesHoldings: holdings, + } } // DefaultGenesisState returns a default genesis state -func DefaultGenesisState() GenesisState { return NewGenesisState(true) } +func DefaultGenesisState() GenesisState { + return NewGenesisState(true, sdk.Coins{}, []TokenHolder{}) +} // InitGenesis sets distribution information for genesis. func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { keeper.SetSendEnabled(ctx, data.SendEnabled) + keeper.SetCirculatingSupply(ctx, data.CirculatingSupply) + for _, holder := range data.ModulesHoldings { + keeper.SetTokenHolder(ctx, holder.Module) + } } // ExportGenesis returns a GenesisState for a given context and keeper. func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { - return NewGenesisState(keeper.GetSendEnabled(ctx)) + return NewGenesisState( + keeper.GetSendEnabled(ctx), + keeper.GetCirculatingSupply(ctx), + keeper.GetTokenHolders(ctx), + ) } // ValidateGenesis performs basic validation of bank genesis data returning an // error for any failed validation criteria. -func ValidateGenesis(data GenesisState) error { return nil } +func ValidateGenesis(data GenesisState) error { + if !data.CirculatingSupply.IsValid() { + return fmt.Errorf("circulating supply coins are not valid") + } + return nil +} diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 05a5b3d6e31d..8fee882ba35a 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank/tags" @@ -26,22 +27,32 @@ type Keeper interface { UndelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Tags, sdk.Error) } +//----------------------------------------------------------------------------- +// BaseKeeper + // BaseKeeper manages transfers between accounts. It implements the Keeper interface. type BaseKeeper struct { BaseSendKeeper + cdc *codec.Codec + storeKey sdk.StoreKey ak auth.AccountKeeper paramSpace params.Subspace } // NewBaseKeeper returns a new BaseKeeper -func NewBaseKeeper(ak auth.AccountKeeper, +func NewBaseKeeper( + cdc *codec.Codec, + key sdk.StoreKey, + ak auth.AccountKeeper, paramSpace params.Subspace, codespace sdk.CodespaceType) BaseKeeper { ps := paramSpace.WithKeyTable(ParamKeyTable()) return BaseKeeper{ - BaseSendKeeper: NewBaseSendKeeper(ak, ps, codespace), + BaseSendKeeper: NewBaseSendKeeper(cdc, key, ak, ps, codespace), + cdc: cdc, + storeKey: key, ak: ak, paramSpace: ps, } @@ -88,6 +99,70 @@ func (keeper BaseKeeper) InputOutputCoins( return inputOutputCoins(ctx, keeper.ak, inputs, outputs) } +// GetTokenHolders returns all the token holders +func (keeper BaseKeeper) GetTokenHolders(ctx sdk.Context) ( + tokenHolders []TokenHolder, err error) { + store := ctx.KVStore(keeper.storeKey) + iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) + defer iterator.Close() + + var tokenHolder TokenHolder + for ; iterator.Valid(); iterator.Next() { + err = keeper.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) + if err != nil { + return + } + tokenHolders = append(tokenHolders, tokenHolder) + } + return +} + +// GetTokenHolder returns a token holder instance +func (keeper BaseKeeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( + tokenHolder TokenHolder) { + store := ctx.KVStore(keeper.storeKey) + b := store.Get(GetTokenHolderKey(moduleName)) + if b == nil { + panic(fmt.Sprintf("module %s is not in store", moduleName)) + } + keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) + return +} + +// SetTokenHolder sets a holder to store +func (keeper BaseKeeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { + store := ctx.KVStore(keeper.storeKey) + holderKey := GetTokenHolderKey(tokenHolder.Module) + b := keeper.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) + store.Set(holderKey, b) +} + +// GetTotalSupply returns the total supply of the network +func (keeper BaseKeeper) GetTotalSupply(ctx sdk.Context) (totalSupply sdk.Coins) { + holders, err := keeper.GetTokenHolders(ctx) + if err != nil { + panic(err) + } + + for _, holder := range holders { + totalSupply = totalSupply.Add(holder.Holdings) + } + return +} + +// GetSupplyOf returns a coin's total supply +func (keeper BaseKeeper) GetSupplyOf(ctx sdk.Context, denom string) (supply sdk.Int) { + holders, err := keeper.GetTokenHolders(ctx) + if err != nil { + panic(err) + } + + for _, holder := range holders { + supply = supply.Add(holder.HoldingsOf(denom)) + } + return +} + // DelegateCoins performs delegation by deducting amt coins from an account with // address addr. For vesting accounts, delegations amounts are tracked for both // vesting and vested coins. @@ -115,6 +190,9 @@ func (keeper BaseKeeper) UndelegateCoins( return undelegateCoins(ctx, keeper.ak, addr, amt) } +//----------------------------------------------------------------------------- +// SendKeeper + // SendKeeper defines a module interface that facilitates the transfer of coins // between accounts without the possibility of creating coins. type SendKeeper interface { @@ -128,21 +206,32 @@ type SendKeeper interface { var _ SendKeeper = (*BaseSendKeeper)(nil) +//----------------------------------------------------------------------------- +// BaseSendKeeper + // BaseSendKeeper only allows transfers between accounts without the possibility of // creating coins. It implements the SendKeeper interface. type BaseSendKeeper struct { BaseViewKeeper - + cdc *codec.Codec + storeKey sdk.StoreKey ak auth.AccountKeeper paramSpace params.Subspace } // NewBaseSendKeeper returns a new BaseSendKeeper. -func NewBaseSendKeeper(ak auth.AccountKeeper, - paramSpace params.Subspace, codespace sdk.CodespaceType) BaseSendKeeper { +func NewBaseSendKeeper( + cdc *codec.Codec, + key sdk.StoreKey, + ak auth.AccountKeeper, + paramSpace params.Subspace, + codespace sdk.CodespaceType, +) BaseSendKeeper { return BaseSendKeeper{ - BaseViewKeeper: NewBaseViewKeeper(ak, codespace), + BaseViewKeeper: NewBaseViewKeeper(cdc, key, ak, codespace), + cdc: cdc, + storeKey: key, ak: ak, paramSpace: paramSpace, } @@ -172,6 +261,9 @@ func (keeper BaseSendKeeper) SetSendEnabled(ctx sdk.Context, enabled bool) { keeper.paramSpace.Set(ctx, ParamStoreKeySendEnabled, &enabled) } +//----------------------------------------------------------------------------- +// ViewKeeper + var _ ViewKeeper = (*BaseViewKeeper)(nil) // ViewKeeper defines a module interface that facilitates read only access to @@ -185,13 +277,25 @@ type ViewKeeper interface { // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { + cdc *codec.Codec + storeKey sdk.StoreKey ak auth.AccountKeeper codespace sdk.CodespaceType } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper(ak auth.AccountKeeper, codespace sdk.CodespaceType) BaseViewKeeper { - return BaseViewKeeper{ak: ak, codespace: codespace} +func NewBaseViewKeeper( + cdc *codec.Codec, + key sdk.StoreKey, + ak auth.AccountKeeper, + codespace sdk.CodespaceType, +) BaseViewKeeper { + return BaseViewKeeper{ + cdc: cdc, + storeKey: key, + ak: ak, + codespace: codespace, + } } // GetCoins returns the coins at the addr. @@ -209,6 +313,9 @@ func (keeper BaseViewKeeper) Codespace() sdk.CodespaceType { return keeper.codespace } +//----------------------------------------------------------------------------- +// private functions + func getCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress) sdk.Coins { acc := am.GetAccount(ctx, addr) if acc == nil { @@ -356,6 +463,9 @@ func inputOutputCoins(ctx sdk.Context, am auth.AccountKeeper, inputs []Input, ou return allTags, nil } +//----------------------------------------------------------------------------- +// staking + func delegateCoins( ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins, ) (sdk.Tags, sdk.Error) { diff --git a/x/supply/keys.go b/x/bank/keys.go similarity index 79% rename from x/supply/keys.go rename to x/bank/keys.go index 948b2bdb5f76..83c3a54467fe 100644 --- a/x/supply/keys.go +++ b/x/bank/keys.go @@ -1,11 +1,8 @@ -package supply +package bank const ( // ModuleName is the name of the module - ModuleName = "supply" - - // DefaultParamspace for params keeper - DefaultParamspace = ModuleName + ModuleName = "bank" // StoreKey is the default store key for mint StoreKey = ModuleName diff --git a/x/bank/token_holder.go b/x/bank/token_holder.go new file mode 100644 index 000000000000..5c814f77d611 --- /dev/null +++ b/x/bank/token_holder.go @@ -0,0 +1,51 @@ +package bank + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TokenHolder defines an instance of a module that holds tokens +type TokenHolder struct { + Module string `json:"module"` + Holdings sdk.Coins `json:"holdings"` +} + +// NewTokenHolder creates a new TokenHolder instance +func NewTokenHolder(moduleName string, initialHoldings sdk.Coins) TokenHolder { + return TokenHolder{ + Module: moduleName, + Holdings: initialHoldings, + } +} + +// HoldingsOf returns the a total coin denom holdings retained by a module +func (tk TokenHolder) HoldingsOf(denom string) sdk.Int { + return tk.Holdings.AmountOf(denom) +} + +// RequestTokens adds requested tokens to the module's holdings +func (tk TokenHolder) RequestTokens(amount sdk.Coins) error { + // get available supply (not held by a module or account) + availableSupply := keeper.GetCirculatingSupply(ctx) // TODO: move to keeper ? + if !availableSupply.IsAllGTE(amount) { + return fmt.Errorf("requested tokens greater than current circulating free supply") + } + tk.setTokenHoldings(tk.Holdings.Add(amount)) + return nil +} + +// RelinquishTokens hands over a portion of the module's holdings +func (tk TokenHolder) RelinquishTokens(amount sdk.Coins) error { + if !tk.Holdings.IsAllGTE(amount) { + return fmt.Errorf("insufficient token holdings") + } + tk.setTokenHoldings(tk.Holdings.Sub(amount)) + return nil +} + +// set new token holdings +func (tk *TokenHolder) setTokenHoldings(amount sdk.Coins) { + tk.Holdings = amount +} diff --git a/x/supply/errors.go b/x/supply/errors.go deleted file mode 100644 index 764e59c46468..000000000000 --- a/x/supply/errors.go +++ /dev/null @@ -1,31 +0,0 @@ -// nolint -package supply - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type CodeType = sdk.CodeType - -// define the supply errors codes -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - CodeInsufficientSupply CodeType = 101 - CodeInsufficientHoldings CodeType = 102 -) - -func ErrInsufficientSupply(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError( - codespace, - CodeInsufficientSupply, - "requested tokens greater than current total supply", - ) -} - -func ErrInsufficientHoldings(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError( - codespace, - CodeInsufficientHoldings, - "insufficient token holdings", - ) -} diff --git a/x/supply/keeper.go b/x/supply/keeper.go deleted file mode 100644 index ba4208ce941a..000000000000 --- a/x/supply/keeper.go +++ /dev/null @@ -1,90 +0,0 @@ -package supply - -import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" -) - -// Keeper of the supply store -type Keeper struct { - storeKey sdk.StoreKey - cdc *codec.Codec - paramSpace params.Subspace -} - -// NewKeeper defines the supply store keeper -func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, -) Keeper { - return Keeper{ - storeKey: key, - cdc: cdc, - } -} - -// GetTokenHolders returns all the token holders -func (k Keeper) GetTokenHolders(ctx sdk.Context) ( - tokenHolders []TokenHolder, err error) { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) - defer iterator.Close() - - var tokenHolder TokenHolder - for ; iterator.Valid(); iterator.Next() { - err = k.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) - if err != nil { - return - } - tokenHolders = append(tokenHolders, tokenHolder) - } - return -} - -// GetTokenHolder returns a token holder instance -func (k Keeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( - tokenHolder TokenHolder) { - store := ctx.KVStore(k.storeKey) - b := store.Get(GetTokenHolderKey(moduleName)) - if b == nil { - panic(fmt.Sprintf("module %s is not in store", moduleName)) - } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) - return -} - -// SetTokenHolder sets a holder to store -func (k Keeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { - store := ctx.KVStore(k.storeKey) - holderKey := GetTokenHolderKey(tokenHolder.module) - b := k.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) - store.Set(holderKey, b) -} - -// GetTotalSupply returns the total supply of the network -func (k Keeper) GetTotalSupply(ctx sdk.Context) (totalSupply sdk.Coins) { - holders, err := k.GetTokenHolders(ctx) - if err != nil { - panic(err) - } - - for _, holder := range holders { - totalSupply = totalSupply.Add(holder.GetHoldings()) - } - return -} - -// GetSupplyOf returns a coin's total supply -func (k Keeper) GetSupplyOf(ctx sdk.Context, denom string) (supply sdk.Int) { - holders, err := k.GetTokenHolders(ctx) - if err != nil { - panic(err) - } - - for _, holder := range holders { - supply = supply.Add(holder.GetHoldingsOf(denom)) - } - return -} diff --git a/x/supply/token_holder.go b/x/supply/token_holder.go deleted file mode 100644 index 62fe9b01838b..000000000000 --- a/x/supply/token_holder.go +++ /dev/null @@ -1,52 +0,0 @@ -package supply - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// TokenHolder defines an instance of a module that holds tokens -type TokenHolder struct { - module string - tokenHoldings sdk.Coins -} - -// NewTokenHolder creates a new TokenHolder instance -func NewTokenHolder(moduleName string, initialHoldings sdk.Coins) TokenHolder { - return TokenHolder{ - module: moduleName, - tokenHoldings: initialHoldings, - } -} - -// GetHoldings returns the total tokens held by a module -func (tk TokenHolder) GetHoldings() sdk.Coins { - return tk.tokenHoldings -} - -// GetHoldingsOf returns the a total coin denom holdings retained by a module -func (tk TokenHolder) GetHoldingsOf(denom string) sdk.Int { - return tk.tokenHoldings.AmountOf(denom) -} - -// RequestTokens re -func (tk TokenHolder) RequestTokens(amount sdk.Coins) (err sdk.Error) { - // get available supply (not held by a module or account) - // check if supply > amount - // - return -} - -// RelinquishTokens hands over a portion of the module's holdings -func (tk TokenHolder) RelinquishTokens(amount sdk.Coins) (err sdk.Error) { - holdings := tk.GetHoldings() - if !holdings.IsAllGTE(amount) { - return ErrInsufficientHoldings(DefaultCodespace) - } - tk.setTokenHoldings(holdings.Sub(amount)) - return -} - -// set new token holdings -func (tk *TokenHolder) setTokenHoldings(amount sdk.Coins) { - tk.tokenHoldings = amount -} From e2c52169b6832bef67d4def5f1700338bfb33356 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 11 Apr 2019 14:32:02 +0200 Subject: [PATCH 03/46] token minter --- x/bank/token_holder.go | 118 ++++++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 19 deletions(-) diff --git a/x/bank/token_holder.go b/x/bank/token_holder.go index 5c814f77d611..27296972d8b3 100644 --- a/x/bank/token_holder.go +++ b/x/bank/token_holder.go @@ -6,46 +6,126 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// TokenHolder defines an instance of a module that holds tokens -type TokenHolder struct { +// TokenHolder defines the BaseTokenHolder interface +type TokenHolder interface { + HoldingsOf() + RequestTokens() + RelinquishTokens() +} + +// TokenMinter defines the BaseTokenMinter interface +type TokenMinter interface { + TokenHolder + + MintTokens() + BurnTokens() +} + +//----------------------------------------------------------------------------- +// BaseTokenHolder + +// BaseTokenHolder defines an instance of a module that holds tokens +type BaseTokenHolder struct { Module string `json:"module"` - Holdings sdk.Coins `json:"holdings"` + Holdings sdk.Coins `json:"holdings"` // holdings from free available supply (not held by modules or accounts) } -// NewTokenHolder creates a new TokenHolder instance -func NewTokenHolder(moduleName string, initialHoldings sdk.Coins) TokenHolder { - return TokenHolder{ +// NewBaseTokenHolder creates a new BaseTokenHolder instance +func NewBaseTokenHolder(moduleName string, initialHoldings sdk.Coins) BaseTokenHolder { + return BaseTokenHolder{ Module: moduleName, Holdings: initialHoldings, } } // HoldingsOf returns the a total coin denom holdings retained by a module -func (tk TokenHolder) HoldingsOf(denom string) sdk.Int { - return tk.Holdings.AmountOf(denom) +func (btk BaseTokenHolder) HoldingsOf(denom string) sdk.Int { + return btk.Holdings.AmountOf(denom) } // RequestTokens adds requested tokens to the module's holdings -func (tk TokenHolder) RequestTokens(amount sdk.Coins) error { - // get available supply (not held by a module or account) - availableSupply := keeper.GetCirculatingSupply(ctx) // TODO: move to keeper ? - if !availableSupply.IsAllGTE(amount) { - return fmt.Errorf("requested tokens greater than current circulating free supply") +func (btk BaseTokenHolder) RequestTokens(amount sdk.Coins) error { + if !amount.IsValid() { + return fmt.Errorf("invalid requested amount") } - tk.setTokenHoldings(tk.Holdings.Add(amount)) + // get available supply (not held by a module or account) + // availableSupply := keeper.GetCirculatingSupply(ctx) // TODO: move to keeper ? + // if !availableSupply.IsAllGTE(amount) { + // return fmt.Errorf("requested tokens greater than current circulating free supply") + // } + // TODO: decrease free supply + btk.setTokenHoldings(btk.Holdings.Add(amount)) return nil } // RelinquishTokens hands over a portion of the module's holdings -func (tk TokenHolder) RelinquishTokens(amount sdk.Coins) error { - if !tk.Holdings.IsAllGTE(amount) { +func (btk BaseTokenHolder) RelinquishTokens(amount sdk.Coins) error { + if !amount.IsValid() { + return fmt.Errorf("invalid provided relenquished amount") + } + if !btk.Holdings.IsAllGTE(amount) { return fmt.Errorf("insufficient token holdings") } - tk.setTokenHoldings(tk.Holdings.Sub(amount)) + btk.setTokenHoldings(btk.Holdings.Sub(amount)) + //TODO: add to free supply return nil } // set new token holdings -func (tk *TokenHolder) setTokenHoldings(amount sdk.Coins) { - tk.Holdings = amount +func (btk *BaseTokenHolder) setTokenHoldings(amount sdk.Coins) { + btk.Holdings = amount +} + +//----------------------------------------------------------------------------- +// BaseTokenMinter + +// BaseTokenMinter defines an instance of a module that is allowed to hold and mint tokens +type BaseTokenMinter struct { + *BaseTokenHolder + + MintedTokens sdk.Coins `json:"minted_tokens"` // TODO: should this have an allowance ? +} + +// NewBaseTokenMinter creates a new BaseTokenMinter instance +func NewBaseTokenMinter(moduleName string, initialHoldings, initialMintedTokens sdk.Coins, +) BaseTokenMinter { + + baseTokenHoler := NewBaseTokenHolder(moduleName, initialHoldings) + return BaseTokenMinter{ + BaseTokenHolder: &baseTokenHoler, + MintedTokens: initialMintedTokens, + } +} + +// MintedTokensOf returns the a total amount minted of specific coin +func (btm BaseTokenMinter) MintedTokensOf(denom string) sdk.Int { + return btm.MintedTokens.AmountOf(denom) +} + +// Mint creates new tokens and registers them to the module +func (btm BaseTokenMinter) Mint(amount sdk.Coins) error { + if !amount.IsValid() { + return fmt.Errorf("invalid provided minting amount") + } + // TODO: Check for allowance ? + btm.setMintedTokens(btm.MintedTokens.Add(amount)) + return nil +} + +// BurnTokens destroys a portion of the previously minted tokens +func (btm BaseTokenMinter) BurnTokens(amount sdk.Coins) error { + if !amount.IsValid() { + return fmt.Errorf("invalid provided burning amount") + } + if !btm.MintedTokens.IsAllGTE(amount) { + return fmt.Errorf("can't burn more tokens than current minted token balance") + } + + btm.setMintedTokens(btm.MintedTokens.Sub(amount)) + return nil +} + +// set new minted tokens +func (btm *BaseTokenMinter) setMintedTokens(amount sdk.Coins) { + btm.MintedTokens = amount } From c17322564d5ee817bc564fde59ea4c43bddbaad0 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 11 Apr 2019 16:23:09 +0200 Subject: [PATCH 04/46] fix interfaces --- x/bank/token_holder.go | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/x/bank/token_holder.go b/x/bank/token_holder.go index 27296972d8b3..86bd09835d11 100644 --- a/x/bank/token_holder.go +++ b/x/bank/token_holder.go @@ -6,24 +6,33 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// TokenHolder defines the BaseTokenHolder interface +// TokenHolder defines the interface used for modules that are allowed to hold +// tokens. This is designed to prevent held tokens to be kept in regular Accounts, +// as those are only ment for user accounts +// +// The bank module keeps track of each of the module's holdings and uses it to +// type TokenHolder interface { - HoldingsOf() - RequestTokens() - RelinquishTokens() + HoldingsOf(string) sdk.Int + RequestTokens(sdk.Coins) error + RelinquishTokens(sdk.Coins) error } -// TokenMinter defines the BaseTokenMinter interface +// TokenMinter defines the interface used for modules that are allowed to mint +// and hold tokens on their behalf type TokenMinter interface { TokenHolder - MintTokens() - BurnTokens() + MintedTokensOf(string) sdk.Int + Mint(sdk.Coins) error + BurnTokens(sdk.Coins) error } //----------------------------------------------------------------------------- // BaseTokenHolder +var _ TokenHolder = (*BaseTokenHolder)(nil) + // BaseTokenHolder defines an instance of a module that holds tokens type BaseTokenHolder struct { Module string `json:"module"` @@ -79,6 +88,8 @@ func (btk *BaseTokenHolder) setTokenHoldings(amount sdk.Coins) { //----------------------------------------------------------------------------- // BaseTokenMinter +var _ TokenMinter = (*BaseTokenMinter)(nil) + // BaseTokenMinter defines an instance of a module that is allowed to hold and mint tokens type BaseTokenMinter struct { *BaseTokenHolder From d18b617d03ae6ed3cfcc32a268bdcf16b5c1c2c7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 12 Apr 2019 21:38:09 +0200 Subject: [PATCH 05/46] supplier, bank keeper and update minting logic --- cmd/gaia/app/genesis.go | 21 +++-- x/bank/keeper.go | 67 +--------------- x/bank/keys.go | 3 +- x/bank/supply.go | 154 +++++++++++++++++++++++++++++++++++++ x/bank/token_holder.go | 67 +++++++--------- x/mint/abci_app.go | 7 +- x/mint/expected_keepers.go | 14 +++- x/mint/keeper.go | 5 +- 8 files changed, 215 insertions(+), 123 deletions(-) create mode 100644 x/bank/supply.go diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 997cd131c751..575e1252cdfd 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -168,7 +168,6 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js return genesisState, errors.New("there must be at least one genesis tx") } - stakingData := genesisState.StakingData for i, genTx := range appGenTxs { var tx auth.StdTx if err := cdc.UnmarshalJSON(genTx, &tx); err != nil { @@ -187,16 +186,7 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } } - for _, acc := range genesisState.Accounts { - for _, coin := range acc.Coins { - if coin.Denom == genesisState.StakingData.Params.BondDenom { - stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens. - Add(coin.Amount) // increase the supply - } - } - } - - genesisState.StakingData = stakingData + genesisState.BankData.CirculatingSupply = circulatingSupplyFromGenAccounts(genesisState.Accounts) genesisState.GenTxs = appGenTxs return genesisState, nil @@ -403,6 +393,15 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm return appGenTxs, persistentPeers, nil } +// circulatingSupplyFromGenAccounts returns the sum of free coins held by genesis accounts +func circulatingSupplyFromGenAccounts(genAccounts []GenesisAccount, +) (supply sdk.Coins) { + for _, genAcc := range genAccounts { + supply = supply.Add(genAcc.Coins) + } + return +} + func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount { accAuth := auth.NewBaseAccountWithAddress(addr) coins := sdk.Coins{ diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 8fee882ba35a..bde5ee43551c 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -18,6 +18,8 @@ var _ Keeper = (*BaseKeeper)(nil) type Keeper interface { SendKeeper + InflateSupply(ctx sdk.Context, amt sdk.Coins) + SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) @@ -99,69 +101,8 @@ func (keeper BaseKeeper) InputOutputCoins( return inputOutputCoins(ctx, keeper.ak, inputs, outputs) } -// GetTokenHolders returns all the token holders -func (keeper BaseKeeper) GetTokenHolders(ctx sdk.Context) ( - tokenHolders []TokenHolder, err error) { - store := ctx.KVStore(keeper.storeKey) - iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) - defer iterator.Close() - - var tokenHolder TokenHolder - for ; iterator.Valid(); iterator.Next() { - err = keeper.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) - if err != nil { - return - } - tokenHolders = append(tokenHolders, tokenHolder) - } - return -} - -// GetTokenHolder returns a token holder instance -func (keeper BaseKeeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( - tokenHolder TokenHolder) { - store := ctx.KVStore(keeper.storeKey) - b := store.Get(GetTokenHolderKey(moduleName)) - if b == nil { - panic(fmt.Sprintf("module %s is not in store", moduleName)) - } - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) - return -} - -// SetTokenHolder sets a holder to store -func (keeper BaseKeeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { - store := ctx.KVStore(keeper.storeKey) - holderKey := GetTokenHolderKey(tokenHolder.Module) - b := keeper.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) - store.Set(holderKey, b) -} - -// GetTotalSupply returns the total supply of the network -func (keeper BaseKeeper) GetTotalSupply(ctx sdk.Context) (totalSupply sdk.Coins) { - holders, err := keeper.GetTokenHolders(ctx) - if err != nil { - panic(err) - } - - for _, holder := range holders { - totalSupply = totalSupply.Add(holder.Holdings) - } - return -} - -// GetSupplyOf returns a coin's total supply -func (keeper BaseKeeper) GetSupplyOf(ctx sdk.Context, denom string) (supply sdk.Int) { - holders, err := keeper.GetTokenHolders(ctx) - if err != nil { - panic(err) - } - - for _, holder := range holders { - supply = supply.Add(holder.HoldingsOf(denom)) - } - return -} +//------------------ Staking logic ------------------ +// TODO: consider moving out this of bank // DelegateCoins performs delegation by deducting amt coins from an account with // address addr. For vesting accounts, delegations amounts are tracked for both diff --git a/x/bank/keys.go b/x/bank/keys.go index 83c3a54467fe..9c487baa3333 100644 --- a/x/bank/keys.go +++ b/x/bank/keys.go @@ -12,7 +12,8 @@ const ( ) var ( - holderKeyPrefix = []byte{0x00} + supplierKey = []byte{0x00} + holderKeyPrefix = []byte{0x01} ) // GetTokenHolderKey returns the store key of the given module diff --git a/x/bank/supply.go b/x/bank/supply.go new file mode 100644 index 000000000000..01e4c57720e0 --- /dev/null +++ b/x/bank/supply.go @@ -0,0 +1,154 @@ +package bank + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Supplier represents the keeps track of the total supply amounts in the network +type Supplier struct { + CirculatingSupply sdk.Coins `json:"circulating_supply"` // supply held by accounts that's not vesting + VestingSupply sdk.Coins `json:"vesting_supply"` // locked supply held by vesting accounts + HoldersSupply sdk.Coins `json:"holders_supply"` // supply held by non acccount token holders (e.g modules) + TotalSupply sdk.Coins `json:"total_supply"` // total supply of the network +} + +// CirculatingAmountOf returns the circulating supply of a coin denomination +func (supplier Supplier) CirculatingAmountOf(denom string) sdk.Int { + return supplier.CirculatingSupply.AmountOf(denom) +} + +// VestingAmountOf returns the vesting supply of a coin denomination +func (supplier Supplier) VestingAmountOf(denom string) sdk.Int { + return supplier.VestingSupply.AmountOf(denom) +} + +// HoldersAmountOf returns the total token holders' supply of a coin denomination +func (supplier Supplier) HoldersAmountOf(denom string) sdk.Int { + return supplier.HoldersSupply.AmountOf(denom) +} + +// TotalAmountOf returns the total supply of a coin denomination +func (supplier Supplier) TotalAmountOf(denom string) sdk.Int { + return supplier.TotalSupply.AmountOf(denom) +} + +// GetSupplier retrieves the Supplier from store +func (keeper BaseKeeper) GetSupplier(ctx sdk.Context) (supplier Supplier) { + store := ctx.KVStore(keeper.storeKey) + b := store.Get(supplierKey) + if b == nil { + panic("Stored fee pool should not have been nil") + } + keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, &supplier) + return +} + +// SetSupplier sets the Supplier to store +func (keeper BaseKeeper) SetSupplier(ctx sdk.Context, supplier Supplier) { + store := ctx.KVStore(keeper.storeKey) + b := keeper.cdc.MustMarshalBinaryLengthPrefixed(supplier) + store.Set(supplierKey, b) +} + +// GetTokenHolders returns all the token holders +func (keeper BaseKeeper) GetTokenHolders(ctx sdk.Context) ( + tokenHolders []TokenHolder, err error) { + store := ctx.KVStore(keeper.storeKey) + iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) + defer iterator.Close() + + var tokenHolder TokenHolder + for ; iterator.Valid(); iterator.Next() { + err = keeper.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) + if err != nil { + return + } + tokenHolders = append(tokenHolders, tokenHolder) + } + return +} + +// GetTokenHolder returns a token holder instance +func (keeper BaseKeeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( + tokenHolder TokenHolder, err error) { + store := ctx.KVStore(keeper.storeKey) + b := store.Get(GetTokenHolderKey(moduleName)) + if b == nil { + err = fmt.Errorf("module %s doesn't exist", moduleName) + return + } + keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) + return +} + +// SetTokenHolder sets a holder to store +func (keeper BaseKeeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { + store := ctx.KVStore(keeper.storeKey) + holderKey := GetTokenHolderKey(tokenHolder.GetModuleName()) + b := keeper.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) + store.Set(holderKey, b) +} + +// InflateSupply adds tokens to the circulating supply +func (keeper BaseKeeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { + supplier := keeper.GetSupplier(ctx) + supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) + keeper.SetSupplier(ctx, supplier) +} + +// RequestTokens adds requested tokens to the module's holdings +func (keeper BaseKeeper) RequestTokens( + ctx sdk.Context, moduleName string, amount sdk.Coins, +) (err error) { + if !amount.IsValid() { + return fmt.Errorf("invalid requested amount") + } + + holder, err := keeper.GetTokenHolder(ctx, moduleName) + if err != nil { + return fmt.Errorf("module %s doesn't exist", moduleName) + } + + supplier := keeper.GetSupplier(ctx) + supplier.HoldersSupply = supplier.HoldersSupply.Add(amount) + + holder.SetHoldings(holder.GetHoldings().Add(amount)) + + keeper.SetTokenHolder(ctx, holder) + keeper.SetSupplier(ctx, supplier) + return +} + +// RelinquishTokens hands over a portion of the module's holdings +func (keeper BaseKeeper) RelinquishTokens( + ctx sdk.Context, moduleName string, amount sdk.Coins, +) error { + if !amount.IsValid() { + return fmt.Errorf("invalid provided relenquished amount") + } + + holder, err := keeper.GetTokenHolder(ctx, moduleName) + if err != nil { + return fmt.Errorf("module %s doesn't exist", moduleName) + } + + newHoldings, ok := holder.GetHoldings().SafeSub(amount) + if !ok { + return fmt.Errorf("insufficient token holdings") + } + + supplier := keeper.GetSupplier(ctx) + newHoldersSupply, ok := supplier.HoldersSupply.SafeSub(amount) + if !ok { + panic("total holders supply should be greater than relinquished amount") + } + supplier.HoldersSupply = newHoldersSupply + + holder.SetHoldings(newHoldings) + + keeper.SetTokenHolder(ctx, holder) + keeper.SetSupplier(ctx, supplier) + return nil +} diff --git a/x/bank/token_holder.go b/x/bank/token_holder.go index 86bd09835d11..83b6b19db1d4 100644 --- a/x/bank/token_holder.go +++ b/x/bank/token_holder.go @@ -11,11 +11,14 @@ import ( // as those are only ment for user accounts // // The bank module keeps track of each of the module's holdings and uses it to -// +// calculate the total supply type TokenHolder interface { - HoldingsOf(string) sdk.Int - RequestTokens(sdk.Coins) error - RelinquishTokens(sdk.Coins) error + GetModuleName() string + + GetHoldings() sdk.Coins + SetHoldings(sdk.Coins) + + GetHoldingsOf(string) sdk.Int } // TokenMinter defines the interface used for modules that are allowed to mint @@ -23,9 +26,8 @@ type TokenHolder interface { type TokenMinter interface { TokenHolder - MintedTokensOf(string) sdk.Int - Mint(sdk.Coins) error - BurnTokens(sdk.Coins) error + GetMintedTokens() sdk.Coins + GetMintedTokensOf(string) sdk.Int } //----------------------------------------------------------------------------- @@ -47,42 +49,24 @@ func NewBaseTokenHolder(moduleName string, initialHoldings sdk.Coins) BaseTokenH } } -// HoldingsOf returns the a total coin denom holdings retained by a module -func (btk BaseTokenHolder) HoldingsOf(denom string) sdk.Int { - return btk.Holdings.AmountOf(denom) +// GetModuleName returns the the name of the holder's module +func (bth BaseTokenHolder) GetModuleName() string { + return bth.Module } -// RequestTokens adds requested tokens to the module's holdings -func (btk BaseTokenHolder) RequestTokens(amount sdk.Coins) error { - if !amount.IsValid() { - return fmt.Errorf("invalid requested amount") - } - // get available supply (not held by a module or account) - // availableSupply := keeper.GetCirculatingSupply(ctx) // TODO: move to keeper ? - // if !availableSupply.IsAllGTE(amount) { - // return fmt.Errorf("requested tokens greater than current circulating free supply") - // } - // TODO: decrease free supply - btk.setTokenHoldings(btk.Holdings.Add(amount)) - return nil +// GetHoldings returns the a total coin denom holdings retained by a module +func (bth BaseTokenHolder) GetHoldings() sdk.Coins { + return bth.Holdings } -// RelinquishTokens hands over a portion of the module's holdings -func (btk BaseTokenHolder) RelinquishTokens(amount sdk.Coins) error { - if !amount.IsValid() { - return fmt.Errorf("invalid provided relenquished amount") - } - if !btk.Holdings.IsAllGTE(amount) { - return fmt.Errorf("insufficient token holdings") - } - btk.setTokenHoldings(btk.Holdings.Sub(amount)) - //TODO: add to free supply - return nil +// GetHoldings returns the a total coin denom holdings retained by a module +func (bth *BaseTokenHolder) SetHoldings(amount sdk.Coins) { + bth.Holdings = amount } -// set new token holdings -func (btk *BaseTokenHolder) setTokenHoldings(amount sdk.Coins) { - btk.Holdings = amount +// GetHoldingsOf returns the a total coin denom holdings retained by a module +func (bth BaseTokenHolder) GetHoldingsOf(denom string) sdk.Int { + return bth.Holdings.AmountOf(denom) } //----------------------------------------------------------------------------- @@ -108,8 +92,13 @@ func NewBaseTokenMinter(moduleName string, initialHoldings, initialMintedTokens } } -// MintedTokensOf returns the a total amount minted of specific coin -func (btm BaseTokenMinter) MintedTokensOf(denom string) sdk.Int { +// GetMintedTokens returns the a total amount minted of specific coin +func (btm BaseTokenMinter) GetMintedTokens() sdk.Coins { + return btm.MintedTokens +} + +// GetMintedTokensOf returns the a total amount minted of specific coin +func (btm BaseTokenMinter) GetMintedTokensOf(denom string) sdk.Int { return btm.MintedTokens.AmountOf(denom) } diff --git a/x/mint/abci_app.go b/x/mint/abci_app.go index 5016a464d18a..24d7947114fc 100644 --- a/x/mint/abci_app.go +++ b/x/mint/abci_app.go @@ -12,15 +12,16 @@ func BeginBlocker(ctx sdk.Context, k Keeper) { params := k.GetParams(ctx) // recalculate inflation rate - totalSupply := k.sk.TotalTokens(ctx) + supplier := k.bk.GetSupplier(ctx) + atomSupply := supplier.TotalAmountOf(k.sk.BondDenom(ctx)) bondedRatio := k.sk.BondedRatio(ctx) minter.Inflation = minter.NextInflationRate(params, bondedRatio) - minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalSupply) + minter.AnnualProvisions = minter.NextAnnualProvisions(params, atomSupply) k.SetMinter(ctx, minter) // mint coins, add to collected fees, update supply mintedCoin := minter.BlockProvision(params) k.fck.AddCollectedFees(ctx, sdk.Coins{mintedCoin}) - k.sk.InflateSupply(ctx, mintedCoin.Amount) + k.bk.InflateSupply(ctx, sdk.Coins{mintedCoin}) } diff --git a/x/mint/expected_keepers.go b/x/mint/expected_keepers.go index 5169b0957668..6a45bf9e1846 100644 --- a/x/mint/expected_keepers.go +++ b/x/mint/expected_keepers.go @@ -2,16 +2,22 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" ) -// expected staking keeper +// BankKeeper defines the expected bank keeper +type BankKeeper interface { + GetSupplier(ctx sdk.Context) bank.Supplier + InflateSupply(ctx sdk.Context, amt sdk.Coins) +} + +// StakingKeeper defines the expected staking keeper type StakingKeeper interface { - TotalTokens(ctx sdk.Context) sdk.Int BondedRatio(ctx sdk.Context) sdk.Dec - InflateSupply(ctx sdk.Context, newTokens sdk.Int) + BondDenom(ctx sdk.Context) string } -// expected fee collection keeper interface +// FeeCollectionKeeper defines the expected fee collection keeper type FeeCollectionKeeper interface { AddCollectedFees(sdk.Context, sdk.Coins) sdk.Coins } diff --git a/x/mint/keeper.go b/x/mint/keeper.go index 42a9f19fbaa5..a994cd58f4b4 100644 --- a/x/mint/keeper.go +++ b/x/mint/keeper.go @@ -25,12 +25,13 @@ type Keeper struct { storeKey sdk.StoreKey cdc *codec.Codec paramSpace params.Subspace + bk BankKeeper sk StakingKeeper fck FeeCollectionKeeper } func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, - paramSpace params.Subspace, sk StakingKeeper, fck FeeCollectionKeeper) Keeper { + paramSpace params.Subspace, bk BankKeeper, sk StakingKeeper, fck FeeCollectionKeeper) Keeper { keeper := Keeper{ storeKey: key, @@ -66,7 +67,7 @@ func (k Keeper) GetMinter(ctx sdk.Context) (minter Minter) { store := ctx.KVStore(k.storeKey) b := store.Get(minterKey) if b == nil { - panic("Stored fee pool should not have been nil") + panic("Stored minter should not have been nil") } k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &minter) return From a8b2f9cc26dffb4ab3f52e98b79439af34d6a059 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sat, 13 Apr 2019 09:45:51 +0200 Subject: [PATCH 06/46] remove token minter as per Alessio's comments --- x/bank/token_holder.go | 72 ------------------------------------------ 1 file changed, 72 deletions(-) diff --git a/x/bank/token_holder.go b/x/bank/token_holder.go index 83b6b19db1d4..d1c67d71fb5b 100644 --- a/x/bank/token_holder.go +++ b/x/bank/token_holder.go @@ -1,8 +1,6 @@ package bank import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -21,15 +19,6 @@ type TokenHolder interface { GetHoldingsOf(string) sdk.Int } -// TokenMinter defines the interface used for modules that are allowed to mint -// and hold tokens on their behalf -type TokenMinter interface { - TokenHolder - - GetMintedTokens() sdk.Coins - GetMintedTokensOf(string) sdk.Int -} - //----------------------------------------------------------------------------- // BaseTokenHolder @@ -68,64 +57,3 @@ func (bth *BaseTokenHolder) SetHoldings(amount sdk.Coins) { func (bth BaseTokenHolder) GetHoldingsOf(denom string) sdk.Int { return bth.Holdings.AmountOf(denom) } - -//----------------------------------------------------------------------------- -// BaseTokenMinter - -var _ TokenMinter = (*BaseTokenMinter)(nil) - -// BaseTokenMinter defines an instance of a module that is allowed to hold and mint tokens -type BaseTokenMinter struct { - *BaseTokenHolder - - MintedTokens sdk.Coins `json:"minted_tokens"` // TODO: should this have an allowance ? -} - -// NewBaseTokenMinter creates a new BaseTokenMinter instance -func NewBaseTokenMinter(moduleName string, initialHoldings, initialMintedTokens sdk.Coins, -) BaseTokenMinter { - - baseTokenHoler := NewBaseTokenHolder(moduleName, initialHoldings) - return BaseTokenMinter{ - BaseTokenHolder: &baseTokenHoler, - MintedTokens: initialMintedTokens, - } -} - -// GetMintedTokens returns the a total amount minted of specific coin -func (btm BaseTokenMinter) GetMintedTokens() sdk.Coins { - return btm.MintedTokens -} - -// GetMintedTokensOf returns the a total amount minted of specific coin -func (btm BaseTokenMinter) GetMintedTokensOf(denom string) sdk.Int { - return btm.MintedTokens.AmountOf(denom) -} - -// Mint creates new tokens and registers them to the module -func (btm BaseTokenMinter) Mint(amount sdk.Coins) error { - if !amount.IsValid() { - return fmt.Errorf("invalid provided minting amount") - } - // TODO: Check for allowance ? - btm.setMintedTokens(btm.MintedTokens.Add(amount)) - return nil -} - -// BurnTokens destroys a portion of the previously minted tokens -func (btm BaseTokenMinter) BurnTokens(amount sdk.Coins) error { - if !amount.IsValid() { - return fmt.Errorf("invalid provided burning amount") - } - if !btm.MintedTokens.IsAllGTE(amount) { - return fmt.Errorf("can't burn more tokens than current minted token balance") - } - - btm.setMintedTokens(btm.MintedTokens.Sub(amount)) - return nil -} - -// set new minted tokens -func (btm *BaseTokenMinter) setMintedTokens(amount sdk.Coins) { - btm.MintedTokens = amount -} From f8112f382850440c23beefd4b650672b5bbd34ee Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sat, 13 Apr 2019 10:00:29 +0200 Subject: [PATCH 07/46] minor fixes to supply and keeper interfaces --- cmd/gaia/app/genesis.go | 5 ++- x/bank/genesis.go | 28 ++++++++--------- x/bank/keeper.go | 9 ++++++ x/bank/supply.go | 69 ++++++++++++++++++++++++++++++++++------- x/mint/abci_app.go | 8 ++--- 5 files changed, 85 insertions(+), 34 deletions(-) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 575e1252cdfd..5b050c07fdad 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -186,7 +186,7 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } } - genesisState.BankData.CirculatingSupply = circulatingSupplyFromGenAccounts(genesisState.Accounts) + genesisState.BankData.Supply = supplyFromGenAccounts(genesisState.Accounts) genesisState.GenTxs = appGenTxs return genesisState, nil @@ -393,8 +393,7 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm return appGenTxs, persistentPeers, nil } -// circulatingSupplyFromGenAccounts returns the sum of free coins held by genesis accounts -func circulatingSupplyFromGenAccounts(genAccounts []GenesisAccount, +func supplyFromGenAccounts(genAccounts []GenesisAccount, ) (supply sdk.Coins) { for _, genAcc := range genAccounts { supply = supply.Add(genAcc.Coins) diff --git a/x/bank/genesis.go b/x/bank/genesis.go index 6dc22b8b6964..f8aea895aae3 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -8,33 +8,33 @@ import ( // GenesisState is the bank state that must be provided at genesis. type GenesisState struct { - SendEnabled bool `json:"send_enabled"` - CirculatingSupply sdk.Coins `json:"circulating_supply"` - ModulesHoldings []TokenHolder `json:"modules_holdings"` + SendEnabled bool `json:"send_enabled"` + Supplier Supplier `json:"supplier"` + ModulesHoldings []TokenHolder `json:"modules_holdings"` } // NewGenesisState creates a new genesis state. func NewGenesisState( - sendEnabled bool, circulatingSupply sdk.Coins, holdings []TokenHolder, + sendEnabled bool, supplier Supplier, holdings []TokenHolder, ) GenesisState { return GenesisState{ - SendEnabled: sendEnabled, - CirculatingSupply: circulatingSupply, - ModulesHoldings: holdings, + SendEnabled: sendEnabled, + Supplier: supplier, + ModulesHoldings: holdings, } } // DefaultGenesisState returns a default genesis state func DefaultGenesisState() GenesisState { - return NewGenesisState(true, sdk.Coins{}, []TokenHolder{}) + return NewGenesisState(true, DefaultSupplier(), []TokenHolder{}) } // InitGenesis sets distribution information for genesis. func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { keeper.SetSendEnabled(ctx, data.SendEnabled) - keeper.SetCirculatingSupply(ctx, data.CirculatingSupply) + keeper.SetSupplier(ctx, data.Supplier) for _, holder := range data.ModulesHoldings { - keeper.SetTokenHolder(ctx, holder.Module) + keeper.SetTokenHolder(ctx, holder) } } @@ -42,7 +42,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { return NewGenesisState( keeper.GetSendEnabled(ctx), - keeper.GetCirculatingSupply(ctx), + keeper.GetSupplier(ctx), keeper.GetTokenHolders(ctx), ) } @@ -50,8 +50,6 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { // ValidateGenesis performs basic validation of bank genesis data returning an // error for any failed validation criteria. func ValidateGenesis(data GenesisState) error { - if !data.CirculatingSupply.IsValid() { - return fmt.Errorf("circulating supply coins are not valid") - } - return nil + err := data.Supplier.ValidateBasic().Error() + return fmt.Errorf(err) } diff --git a/x/bank/keeper.go b/x/bank/keeper.go index bde5ee43551c..79765c5712fe 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -18,8 +18,17 @@ var _ Keeper = (*BaseKeeper)(nil) type Keeper interface { SendKeeper + GetSupplier(ctx sdk.Context) Supplier + SetSupplier(ctx sdk.Context, supplier Supplier) InflateSupply(ctx sdk.Context, amt sdk.Coins) + GetTokenHolders(ctx sdk.Context) []TokenHolder + GetTokenHolder(ctx sdk.Context, moduleName string) (TokenHolder, error) + SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) + + RequestTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) error + RelinquishTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) error + SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) diff --git a/x/bank/supply.go b/x/bank/supply.go index 01e4c57720e0..fe98894c79ce 100644 --- a/x/bank/supply.go +++ b/x/bank/supply.go @@ -14,6 +14,21 @@ type Supplier struct { TotalSupply sdk.Coins `json:"total_supply"` // total supply of the network } +// NewSupplier creates a new Supplier instance +func NewSupplier(circulating, vesting, holders, total sdk.Coins) Supplier { + return Supplier{ + CirculatingSupply: circulating, + VestingSupply: vesting, + HoldersSupply: holders, + TotalSupply: total, + } +} + +// DefaultSupplier creates an empty Supplier +func DefaultSupplier() Supplier { + return NewSupplier(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) +} + // CirculatingAmountOf returns the circulating supply of a coin denomination func (supplier Supplier) CirculatingAmountOf(denom string) sdk.Int { return supplier.CirculatingSupply.AmountOf(denom) @@ -34,6 +49,36 @@ func (supplier Supplier) TotalAmountOf(denom string) sdk.Int { return supplier.TotalSupply.AmountOf(denom) } +// ValidateBasic validates the Supply coins and returns error if invalid +func (supplier Supplier) ValidateBasic() sdk.Error { + if !supplier.CirculatingSupply.IsValid() { + return sdk.ErrInvalidCoins(supplier.CirculatingSupply.String()) + } + if !supplier.VestingSupply.IsValid() { + return sdk.ErrInvalidCoins(supplier.VestingSupply.String()) + } + if !supplier.HoldersSupply.IsValid() { + return sdk.ErrInvalidCoins(supplier.HoldersSupply.String()) + } + if !supplier.TotalSupply.IsValid() { + return sdk.ErrInvalidCoins(supplier.TotalSupply.String()) + } + return nil +} + +// String returns a human readable string representation of a supplier. +func (supplier Supplier) String() string { + return fmt.Sprintf(`Supplier: + Circulating Supply: %s + Vesting Supply: %s + Holders Supply: %s + Total Supply: %s`, + supplier.CirculatingSupply.String(), + supplier.VestingSupply.String(), + supplier.HoldersSupply.String(), + supplier.TotalSupply.String()) +} + // GetSupplier retrieves the Supplier from store func (keeper BaseKeeper) GetSupplier(ctx sdk.Context) (supplier Supplier) { store := ctx.KVStore(keeper.storeKey) @@ -52,18 +97,25 @@ func (keeper BaseKeeper) SetSupplier(ctx sdk.Context, supplier Supplier) { store.Set(supplierKey, b) } +// InflateSupply adds tokens to the circulating supply +func (keeper BaseKeeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { + supplier := keeper.GetSupplier(ctx) + supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) + keeper.SetSupplier(ctx, supplier) +} + // GetTokenHolders returns all the token holders func (keeper BaseKeeper) GetTokenHolders(ctx sdk.Context) ( - tokenHolders []TokenHolder, err error) { + tokenHolders []TokenHolder) { store := ctx.KVStore(keeper.storeKey) iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) defer iterator.Close() var tokenHolder TokenHolder for ; iterator.Valid(); iterator.Next() { - err = keeper.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) + err := keeper.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) if err != nil { - return + panic(err) } tokenHolders = append(tokenHolders, tokenHolder) } @@ -91,17 +143,10 @@ func (keeper BaseKeeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder store.Set(holderKey, b) } -// InflateSupply adds tokens to the circulating supply -func (keeper BaseKeeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { - supplier := keeper.GetSupplier(ctx) - supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) - keeper.SetSupplier(ctx, supplier) -} - // RequestTokens adds requested tokens to the module's holdings func (keeper BaseKeeper) RequestTokens( ctx sdk.Context, moduleName string, amount sdk.Coins, -) (err error) { +) error { if !amount.IsValid() { return fmt.Errorf("invalid requested amount") } @@ -118,7 +163,7 @@ func (keeper BaseKeeper) RequestTokens( keeper.SetTokenHolder(ctx, holder) keeper.SetSupplier(ctx, supplier) - return + return nil } // RelinquishTokens hands over a portion of the module's holdings diff --git a/x/mint/abci_app.go b/x/mint/abci_app.go index 24d7947114fc..df846c4774f9 100644 --- a/x/mint/abci_app.go +++ b/x/mint/abci_app.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Inflate every block, update inflation parameters once per hour +// BeginBlocker inflates every block and updates inflation parameters once per hour func BeginBlocker(ctx sdk.Context, k Keeper) { // fetch stored minter & params @@ -13,15 +13,15 @@ func BeginBlocker(ctx sdk.Context, k Keeper) { // recalculate inflation rate supplier := k.bk.GetSupplier(ctx) - atomSupply := supplier.TotalAmountOf(k.sk.BondDenom(ctx)) + bondingTokenSupply := supplier.TotalAmountOf(k.sk.BondDenom(ctx)) bondedRatio := k.sk.BondedRatio(ctx) minter.Inflation = minter.NextInflationRate(params, bondedRatio) - minter.AnnualProvisions = minter.NextAnnualProvisions(params, atomSupply) + minter.AnnualProvisions = minter.NextAnnualProvisions(params, bondingTokenSupply) k.SetMinter(ctx, minter) // mint coins, add to collected fees, update supply mintedCoin := minter.BlockProvision(params) k.fck.AddCollectedFees(ctx, sdk.Coins{mintedCoin}) k.bk.InflateSupply(ctx, sdk.Coins{mintedCoin}) - + // k.sk.InflateSupply(ctx) // TODO: increase not bonded tokens } From 8dc2378725a8eb90a5af1c726f311ef26e9b9d5e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 15 Apr 2019 10:33:57 +0200 Subject: [PATCH 08/46] genesis, add codec and cleanup --- cmd/gaia/app/genesis.go | 15 +++-- x/bank/codec.go | 2 + x/bank/keeper.go | 119 ++++++++++++++++++++++++++++++++++++++++ x/bank/keys.go | 4 +- x/bank/supply.go | 119 ---------------------------------------- 5 files changed, 134 insertions(+), 125 deletions(-) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 5b050c07fdad..30f3304e6943 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -186,7 +186,9 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } } - genesisState.BankData.Supply = supplyFromGenAccounts(genesisState.Accounts) + circulatingSupply, vestingSupply := supplyFromGenAccounts(genesisState.Accounts) + genesisState.BankData.Supplier.CirculatingSupply = circulatingSupply + genesisState.BankData.Supplier.VestingSupply = vestingSupply genesisState.GenTxs = appGenTxs return genesisState, nil @@ -282,7 +284,7 @@ func validateGenesisStateAccounts(accs []GenesisAccount) error { return nil } -// GaiaAppGenState but with JSON +// GaiaAppGenStateJSON GaiaAppGenState but with JSON func GaiaAppGenStateJSON(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) ( appState json.RawMessage, err error) { // create the final app state @@ -393,10 +395,15 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm return appGenTxs, persistentPeers, nil } +// supplyFromGenAccounts calculates the circulating and vesting total supply from +// the genesis accounts func supplyFromGenAccounts(genAccounts []GenesisAccount, -) (supply sdk.Coins) { +) (circulatingSupply, vestingSupply sdk.Coins) { for _, genAcc := range genAccounts { - supply = supply.Add(genAcc.Coins) + circulatingSupply = circulatingSupply.Add(genAcc.Coins) + if genAcc.DelegatedVesting.IsAllPositive() { + vestingSupply = vestingSupply.Add(genAcc.OriginalVesting) + } } return } diff --git a/x/bank/codec.go b/x/bank/codec.go index 58c59d5f6ac9..72f03e7c5ced 100644 --- a/x/bank/codec.go +++ b/x/bank/codec.go @@ -8,6 +8,8 @@ import ( func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/MsgSend", nil) cdc.RegisterConcrete(MsgMultiSend{}, "cosmos-sdk/MsgMultiSend", nil) + cdc.RegisterInterface((*TokenHolder)(nil), nil) + cdc.RegisterConcrete(&BaseTokenHolder{}, "bank/BaseTokenHolder", nil) } var msgCdc = codec.New() diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 79765c5712fe..bbc597984e6b 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -69,6 +69,125 @@ func NewBaseKeeper( } } +// GetSupplier retrieves the Supplier from store +func (keeper BaseKeeper) GetSupplier(ctx sdk.Context) (supplier Supplier) { + store := ctx.KVStore(keeper.storeKey) + b := store.Get(supplierKey) + if b == nil { + panic("Stored fee pool should not have been nil") + } + keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, &supplier) + return +} + +// SetSupplier sets the Supplier to store +func (keeper BaseKeeper) SetSupplier(ctx sdk.Context, supplier Supplier) { + store := ctx.KVStore(keeper.storeKey) + b := keeper.cdc.MustMarshalBinaryLengthPrefixed(supplier) + store.Set(supplierKey, b) +} + +// InflateSupply adds tokens to the circulating supply +func (keeper BaseKeeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { + supplier := keeper.GetSupplier(ctx) + supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) + keeper.SetSupplier(ctx, supplier) +} + +// GetTokenHolders returns all the token holders +func (keeper BaseKeeper) GetTokenHolders(ctx sdk.Context) ( + tokenHolders []TokenHolder) { + store := ctx.KVStore(keeper.storeKey) + iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) + defer iterator.Close() + + var tokenHolder TokenHolder + for ; iterator.Valid(); iterator.Next() { + err := keeper.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) + if err != nil { + panic(err) + } + tokenHolders = append(tokenHolders, tokenHolder) + } + return +} + +// GetTokenHolder returns a token holder instance +func (keeper BaseKeeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( + tokenHolder TokenHolder, err error) { + store := ctx.KVStore(keeper.storeKey) + b := store.Get(GetTokenHolderKey(moduleName)) + if b == nil { + err = fmt.Errorf("module %s doesn't exist", moduleName) + return + } + keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) + return +} + +// SetTokenHolder sets a holder to store +func (keeper BaseKeeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { + store := ctx.KVStore(keeper.storeKey) + holderKey := GetTokenHolderKey(tokenHolder.GetModuleName()) + b := keeper.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) + store.Set(holderKey, b) +} + +// RequestTokens adds requested tokens to the module's holdings +func (keeper BaseKeeper) RequestTokens( + ctx sdk.Context, moduleName string, amount sdk.Coins, +) error { + if !amount.IsValid() { + return fmt.Errorf("invalid requested amount") + } + + holder, err := keeper.GetTokenHolder(ctx, moduleName) + if err != nil { + return fmt.Errorf("module %s doesn't exist", moduleName) + } + + supplier := keeper.GetSupplier(ctx) + supplier.HoldersSupply = supplier.HoldersSupply.Add(amount) + + holder.SetHoldings(holder.GetHoldings().Add(amount)) + + keeper.SetTokenHolder(ctx, holder) + keeper.SetSupplier(ctx, supplier) + return nil +} + +// RelinquishTokens hands over a portion of the module's holdings +func (keeper BaseKeeper) RelinquishTokens( + ctx sdk.Context, moduleName string, amount sdk.Coins, +) error { + if !amount.IsValid() { + return fmt.Errorf("invalid provided relenquished amount") + } + + holder, err := keeper.GetTokenHolder(ctx, moduleName) + if err != nil { + return fmt.Errorf("module %s doesn't exist", moduleName) + } + + newHoldings, ok := holder.GetHoldings().SafeSub(amount) + if !ok { + return fmt.Errorf("insufficient token holdings") + } + + supplier := keeper.GetSupplier(ctx) + newHoldersSupply, ok := supplier.HoldersSupply.SafeSub(amount) + if !ok { + panic("total holders supply should be greater than relinquished amount") + } + supplier.HoldersSupply = newHoldersSupply + + holder.SetHoldings(newHoldings) + + keeper.SetTokenHolder(ctx, holder) + keeper.SetSupplier(ctx, supplier) + return nil +} + // SetCoins sets the coins at the addr. func (keeper BaseKeeper) SetCoins( ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins, diff --git a/x/bank/keys.go b/x/bank/keys.go index 9c487baa3333..1fcaa41a2923 100644 --- a/x/bank/keys.go +++ b/x/bank/keys.go @@ -4,10 +4,10 @@ const ( // ModuleName is the name of the module ModuleName = "bank" - // StoreKey is the default store key for mint + // StoreKey is the default store key for supply StoreKey = ModuleName - // QuerierRoute is the querier route for the suply store. + // QuerierRoute is the querier route for the supply store. QuerierRoute = StoreKey ) diff --git a/x/bank/supply.go b/x/bank/supply.go index fe98894c79ce..80466d341f55 100644 --- a/x/bank/supply.go +++ b/x/bank/supply.go @@ -78,122 +78,3 @@ func (supplier Supplier) String() string { supplier.HoldersSupply.String(), supplier.TotalSupply.String()) } - -// GetSupplier retrieves the Supplier from store -func (keeper BaseKeeper) GetSupplier(ctx sdk.Context) (supplier Supplier) { - store := ctx.KVStore(keeper.storeKey) - b := store.Get(supplierKey) - if b == nil { - panic("Stored fee pool should not have been nil") - } - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, &supplier) - return -} - -// SetSupplier sets the Supplier to store -func (keeper BaseKeeper) SetSupplier(ctx sdk.Context, supplier Supplier) { - store := ctx.KVStore(keeper.storeKey) - b := keeper.cdc.MustMarshalBinaryLengthPrefixed(supplier) - store.Set(supplierKey, b) -} - -// InflateSupply adds tokens to the circulating supply -func (keeper BaseKeeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { - supplier := keeper.GetSupplier(ctx) - supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) - keeper.SetSupplier(ctx, supplier) -} - -// GetTokenHolders returns all the token holders -func (keeper BaseKeeper) GetTokenHolders(ctx sdk.Context) ( - tokenHolders []TokenHolder) { - store := ctx.KVStore(keeper.storeKey) - iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) - defer iterator.Close() - - var tokenHolder TokenHolder - for ; iterator.Valid(); iterator.Next() { - err := keeper.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) - if err != nil { - panic(err) - } - tokenHolders = append(tokenHolders, tokenHolder) - } - return -} - -// GetTokenHolder returns a token holder instance -func (keeper BaseKeeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( - tokenHolder TokenHolder, err error) { - store := ctx.KVStore(keeper.storeKey) - b := store.Get(GetTokenHolderKey(moduleName)) - if b == nil { - err = fmt.Errorf("module %s doesn't exist", moduleName) - return - } - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) - return -} - -// SetTokenHolder sets a holder to store -func (keeper BaseKeeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { - store := ctx.KVStore(keeper.storeKey) - holderKey := GetTokenHolderKey(tokenHolder.GetModuleName()) - b := keeper.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) - store.Set(holderKey, b) -} - -// RequestTokens adds requested tokens to the module's holdings -func (keeper BaseKeeper) RequestTokens( - ctx sdk.Context, moduleName string, amount sdk.Coins, -) error { - if !amount.IsValid() { - return fmt.Errorf("invalid requested amount") - } - - holder, err := keeper.GetTokenHolder(ctx, moduleName) - if err != nil { - return fmt.Errorf("module %s doesn't exist", moduleName) - } - - supplier := keeper.GetSupplier(ctx) - supplier.HoldersSupply = supplier.HoldersSupply.Add(amount) - - holder.SetHoldings(holder.GetHoldings().Add(amount)) - - keeper.SetTokenHolder(ctx, holder) - keeper.SetSupplier(ctx, supplier) - return nil -} - -// RelinquishTokens hands over a portion of the module's holdings -func (keeper BaseKeeper) RelinquishTokens( - ctx sdk.Context, moduleName string, amount sdk.Coins, -) error { - if !amount.IsValid() { - return fmt.Errorf("invalid provided relenquished amount") - } - - holder, err := keeper.GetTokenHolder(ctx, moduleName) - if err != nil { - return fmt.Errorf("module %s doesn't exist", moduleName) - } - - newHoldings, ok := holder.GetHoldings().SafeSub(amount) - if !ok { - return fmt.Errorf("insufficient token holdings") - } - - supplier := keeper.GetSupplier(ctx) - newHoldersSupply, ok := supplier.HoldersSupply.SafeSub(amount) - if !ok { - panic("total holders supply should be greater than relinquished amount") - } - supplier.HoldersSupply = newHoldersSupply - - holder.SetHoldings(newHoldings) - - keeper.SetTokenHolder(ctx, holder) - keeper.SetSupplier(ctx, supplier) - return nil -} From 908d78b5f254ddaae408be9edbb8f2ea5b62584a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 15 Apr 2019 12:50:01 +0200 Subject: [PATCH 09/46] rename pool supply; genesis supply --- cmd/gaia/app/app.go | 6 +++++- cmd/gaia/app/genesis.go | 26 +++++++++++++++++++++----- x/bank/keeper.go | 10 +++++----- x/bank/token_holder.go | 2 +- x/mint/abci_app.go | 6 ++---- x/mint/expected_keepers.go | 2 ++ x/mint/keeper.go | 1 + x/staking/keeper/alias_functions.go | 6 +++--- x/staking/types/pool.go | 16 ++++++++-------- 9 files changed, 48 insertions(+), 27 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index a856094728a7..afca4f1976ef 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -45,6 +45,7 @@ type GaiaApp struct { // keys to access the substores keyMain *sdk.KVStoreKey keyAccount *sdk.KVStoreKey + keySupply *sdk.KVStoreKey keyStaking *sdk.KVStoreKey tkeyStaking *sdk.TransientStoreKey keySlashing *sdk.KVStoreKey @@ -83,6 +84,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, cdc: cdc, keyMain: sdk.NewKVStoreKey(bam.MainStoreKey), keyAccount: sdk.NewKVStoreKey(auth.StoreKey), + keySupply: sdk.NewKVStoreKey(bank.StoreKey), keyStaking: sdk.NewKVStoreKey(staking.StoreKey), tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey), keyMint: sdk.NewKVStoreKey(mint.StoreKey), @@ -107,6 +109,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, // add handlers app.bankKeeper = bank.NewBaseKeeper( + cdc, + app.keySupply, app.accountKeeper, app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, @@ -123,7 +127,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, ) app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, app.paramsKeeper.Subspace(mint.DefaultParamspace), - &stakingKeeper, app.feeCollectionKeeper, + app.bankKeeper, &stakingKeeper, app.feeCollectionKeeper, ) app.distrKeeper = distr.NewKeeper( app.cdc, diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 30f3304e6943..41c058ff0c16 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -186,9 +186,12 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } } - circulatingSupply, vestingSupply := supplyFromGenAccounts(genesisState.Accounts) + circulatingSupply, vestingSupply, notBondedSupply, bondedSupply := + supplyFromGenAccounts(genesisState.Accounts, genesisState.StakingData.Params.BondDenom) genesisState.BankData.Supplier.CirculatingSupply = circulatingSupply genesisState.BankData.Supplier.VestingSupply = vestingSupply + genesisState.StakingData.Pool.NotBondedTokens = notBondedSupply + genesisState.StakingData.Pool.BondedTokens = bondedSupply genesisState.GenTxs = appGenTxs return genesisState, nil @@ -395,14 +398,27 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm return appGenTxs, persistentPeers, nil } -// supplyFromGenAccounts calculates the circulating and vesting total supply from -// the genesis accounts -func supplyFromGenAccounts(genAccounts []GenesisAccount, -) (circulatingSupply, vestingSupply sdk.Coins) { +// supplyFromGenAccounts calculates the circulating, vesting, and stakingToken +// (bonded and not bonded) total supply from the genesis accounts +func supplyFromGenAccounts(genAccounts []GenesisAccount, bondDenom string, +) ( + circulatingSupply, vestingSupply sdk.Coins, + notBondedTokens, bondedTokens sdk.Int, +) { for _, genAcc := range genAccounts { + // circulating amount not subject to vesting (i.e free) circulatingSupply = circulatingSupply.Add(genAcc.Coins) + + // vesting and bonded supply from vesting accounts if genAcc.DelegatedVesting.IsAllPositive() { vestingSupply = vestingSupply.Add(genAcc.OriginalVesting) + bondedTokens = bondedTokens.Add(genAcc.DelegatedVesting.AmountOf(bondDenom)) + } + + // staking pool's not bonded supply + notBondedAmount := genAcc.Coins.AmountOf(bondDenom) + if notBondedAmount.GT(sdk.ZeroInt()) { + notBondedTokens = notBondedTokens.Add(notBondedAmount) } } return diff --git a/x/bank/keeper.go b/x/bank/keeper.go index bbc597984e6b..c76db4994893 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -259,7 +259,7 @@ func (keeper BaseKeeper) UndelegateCoins( return undelegateCoins(ctx, keeper.ak, addr, amt) } -//----------------------------------------------------------------------------- +//------------------------------------------------------- // SendKeeper // SendKeeper defines a module interface that facilitates the transfer of coins @@ -275,7 +275,7 @@ type SendKeeper interface { var _ SendKeeper = (*BaseSendKeeper)(nil) -//----------------------------------------------------------------------------- +//------------------------------------------------------- // BaseSendKeeper // BaseSendKeeper only allows transfers between accounts without the possibility of @@ -330,7 +330,7 @@ func (keeper BaseSendKeeper) SetSendEnabled(ctx sdk.Context, enabled bool) { keeper.paramSpace.Set(ctx, ParamStoreKeySendEnabled, &enabled) } -//----------------------------------------------------------------------------- +//------------------------------------------------------- // ViewKeeper var _ ViewKeeper = (*BaseViewKeeper)(nil) @@ -382,7 +382,7 @@ func (keeper BaseViewKeeper) Codespace() sdk.CodespaceType { return keeper.codespace } -//----------------------------------------------------------------------------- +//------------------------------------------------------- // private functions func getCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress) sdk.Coins { @@ -532,7 +532,7 @@ func inputOutputCoins(ctx sdk.Context, am auth.AccountKeeper, inputs []Input, ou return allTags, nil } -//----------------------------------------------------------------------------- +//------------------------------------------------------- // staking func delegateCoins( diff --git a/x/bank/token_holder.go b/x/bank/token_holder.go index d1c67d71fb5b..2b2367a78619 100644 --- a/x/bank/token_holder.go +++ b/x/bank/token_holder.go @@ -48,7 +48,7 @@ func (bth BaseTokenHolder) GetHoldings() sdk.Coins { return bth.Holdings } -// GetHoldings returns the a total coin denom holdings retained by a module +// SetHoldings updates the holdings to the provided amount func (bth *BaseTokenHolder) SetHoldings(amount sdk.Coins) { bth.Holdings = amount } diff --git a/x/mint/abci_app.go b/x/mint/abci_app.go index df846c4774f9..837069892e1c 100644 --- a/x/mint/abci_app.go +++ b/x/mint/abci_app.go @@ -12,16 +12,14 @@ func BeginBlocker(ctx sdk.Context, k Keeper) { params := k.GetParams(ctx) // recalculate inflation rate - supplier := k.bk.GetSupplier(ctx) - bondingTokenSupply := supplier.TotalAmountOf(k.sk.BondDenom(ctx)) bondedRatio := k.sk.BondedRatio(ctx) minter.Inflation = minter.NextInflationRate(params, bondedRatio) - minter.AnnualProvisions = minter.NextAnnualProvisions(params, bondingTokenSupply) + minter.AnnualProvisions = minter.NextAnnualProvisions(params, k.sk.StakingTokenSupply(ctx)) k.SetMinter(ctx, minter) // mint coins, add to collected fees, update supply mintedCoin := minter.BlockProvision(params) k.fck.AddCollectedFees(ctx, sdk.Coins{mintedCoin}) k.bk.InflateSupply(ctx, sdk.Coins{mintedCoin}) - // k.sk.InflateSupply(ctx) // TODO: increase not bonded tokens + k.sk.InflateNotBondedTokenSupply(ctx, mintedCoin.Amount) // TODO: verify invariance with bank bond denom supply } diff --git a/x/mint/expected_keepers.go b/x/mint/expected_keepers.go index 6a45bf9e1846..4298f7dee7a5 100644 --- a/x/mint/expected_keepers.go +++ b/x/mint/expected_keepers.go @@ -15,6 +15,8 @@ type BankKeeper interface { type StakingKeeper interface { BondedRatio(ctx sdk.Context) sdk.Dec BondDenom(ctx sdk.Context) string + InflateNotBondedTokenSupply(ctx sdk.Context, amt sdk.Int) + StakingTokenSupply(ctx sdk.Context) sdk.Int } // FeeCollectionKeeper defines the expected fee collection keeper diff --git a/x/mint/keeper.go b/x/mint/keeper.go index a994cd58f4b4..b0e61ed9187e 100644 --- a/x/mint/keeper.go +++ b/x/mint/keeper.go @@ -37,6 +37,7 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, storeKey: key, cdc: cdc, paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), + bk: bk, sk: sk, fck: fck, } diff --git a/x/staking/keeper/alias_functions.go b/x/staking/keeper/alias_functions.go index aff57bda9fc5..dd1877259208 100644 --- a/x/staking/keeper/alias_functions.go +++ b/x/staking/keeper/alias_functions.go @@ -94,9 +94,9 @@ func (k Keeper) TotalBondedTokens(ctx sdk.Context) sdk.Int { } // total staking tokens supply bonded and unbonded -func (k Keeper) TotalTokens(ctx sdk.Context) sdk.Int { +func (k Keeper) StakingTokenSupply(ctx sdk.Context) sdk.Int { pool := k.GetPool(ctx) - return pool.TokenSupply() + return pool.StakingTokenSupply() } // the fraction of the staking tokens which are currently bonded @@ -106,7 +106,7 @@ func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec { } // when minting new tokens -func (k Keeper) InflateSupply(ctx sdk.Context, newTokens sdk.Int) { +func (k Keeper) InflateNotBondedTokenSupply(ctx sdk.Context, newTokens sdk.Int) { pool := k.GetPool(ctx) pool.NotBondedTokens = pool.NotBondedTokens.Add(newTokens) k.SetPool(ctx, pool) diff --git a/x/staking/types/pool.go b/x/staking/types/pool.go index d3905085a6c7..772442ada973 100644 --- a/x/staking/types/pool.go +++ b/x/staking/types/pool.go @@ -14,7 +14,7 @@ type Pool struct { BondedTokens sdk.Int `json:"bonded_tokens"` // tokens which are currently bonded to a validator } -// nolint +// Equal check if two pool intances are equal // TODO: This is slower than comparing struct fields directly func (p Pool) Equal(p2 Pool) bool { bz1 := MsgCdc.MustMarshalBinaryLengthPrefixed(&p) @@ -22,7 +22,7 @@ func (p Pool) Equal(p2 Pool) bool { return bytes.Equal(bz1, bz2) } -// initial pool for testing +// InitialPool default pool; used for testing func InitialPool() Pool { return Pool{ NotBondedTokens: sdk.ZeroInt(), @@ -30,14 +30,14 @@ func InitialPool() Pool { } } -// Sum total of all staking tokens in the pool -func (p Pool) TokenSupply() sdk.Int { +// StakingTokenSupply returns the total supply of all staking tokens in the pool +func (p Pool) StakingTokenSupply() sdk.Int { return p.NotBondedTokens.Add(p.BondedTokens) } -// Get the fraction of the staking token which is currently bonded +// BondedRatio gets the fraction of the staking token which is currently bonded func (p Pool) BondedRatio() sdk.Dec { - supply := p.TokenSupply() + supply := p.StakingTokenSupply() if supply.IsPositive() { return p.BondedTokens.ToDec().QuoInt(supply) } @@ -67,9 +67,9 @@ func (p Pool) String() string { return fmt.Sprintf(`Pool: Loose Tokens: %s Bonded Tokens: %s - Token Supply: %s + Staking Token Supply: %s Bonded Ratio: %v`, p.NotBondedTokens, - p.BondedTokens, p.TokenSupply(), + p.BondedTokens, p.StakingTokenSupply(), p.BondedRatio()) } From 5c1cd32b70b2b3566aef445e59e95b3ef09e45b0 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 15 Apr 2019 17:46:21 +0200 Subject: [PATCH 10/46] update bank keeper and holders --- x/bank/bench_test.go | 2 ++ x/bank/errors.go | 9 ++++++++ x/bank/keeper.go | 50 ++++++++++++++++++++++++++++++------------ x/bank/keeper_test.go | 22 ++++++++++--------- x/bank/token_holder.go | 4 ++-- 5 files changed, 61 insertions(+), 26 deletions(-) diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index 95918110c4de..dee28bc60423 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -17,6 +17,8 @@ func getBenchmarkMockApp() (*mock.App, error) { RegisterCodec(mapp.Cdc) bankKeeper := NewBaseKeeper( + mapp.Cdc, + sdk.NewKVStoreKey(StoreKey), mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace, diff --git a/x/bank/errors.go b/x/bank/errors.go index b74f64cc4bb2..8c49068727b9 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -13,6 +13,7 @@ const ( CodeSendDisabled CodeType = 101 CodeInvalidInputsOutputs CodeType = 102 + CodeUnknownTokenHolder CodeType = 103 ) // ErrNoInputs is an error @@ -34,3 +35,11 @@ func ErrInputOutputMismatch(codespace sdk.CodespaceType) sdk.Error { func ErrSendDisabled(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeSendDisabled, "send transactions are currently disabled") } + +// ErrUnknownTokenHolder is an error +func ErrUnknownTokenHolder(codespace sdk.CodespaceType, msg string) sdk.Error { + if msg != "" { + return sdk.NewError(codespace, CodeUnknownTokenHolder, msg) + } + return sdk.NewError(codespace, CodeUnknownTokenHolder, "unknown token holder") +} diff --git a/x/bank/keeper.go b/x/bank/keeper.go index c76db4994893..9c341674bf8d 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -81,7 +81,7 @@ func (keeper BaseKeeper) GetSupplier(ctx sdk.Context) (supplier Supplier) { } // SetSupplier sets the Supplier to store -func (keeper BaseKeeper) SetSupplier(ctx sdk.Context, supplier Supplier) { +func (keeper BaseKeeper) setSupplier(ctx sdk.Context, supplier Supplier) { store := ctx.KVStore(keeper.storeKey) b := keeper.cdc.MustMarshalBinaryLengthPrefixed(supplier) store.Set(supplierKey, b) @@ -91,7 +91,7 @@ func (keeper BaseKeeper) SetSupplier(ctx sdk.Context, supplier Supplier) { func (keeper BaseKeeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { supplier := keeper.GetSupplier(ctx) supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) - keeper.SetSupplier(ctx, supplier) + keeper.setSupplier(ctx, supplier) } // GetTokenHolders returns all the token holders @@ -118,15 +118,29 @@ func (keeper BaseKeeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( store := ctx.KVStore(keeper.storeKey) b := store.Get(GetTokenHolderKey(moduleName)) if b == nil { - err = fmt.Errorf("module %s doesn't exist", moduleName) + err = fmt.Errorf("token holder with module %s doesn't exist", moduleName) return } keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) return } +// AddTokenHolder creates and sets a token holder instance to store +func (keeper BaseKeeper) AddTokenHolder(ctx sdk.Context, moduleName string) ( + tokenHolder TokenHolder, err error) { + store := ctx.KVStore(keeper.storeKey) + if store.Has(GetTokenHolderKey(moduleName)) { + err = fmt.Errorf("token holder with module %s already exist", moduleName) + return + } + + tokenHolder = NewBaseTokenHolder(moduleName, sdk.Coins{}) + keeper.setTokenHolder(ctx, tokenHolder) + return +} + // SetTokenHolder sets a holder to store -func (keeper BaseKeeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { +func (keeper BaseKeeper) setTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { store := ctx.KVStore(keeper.storeKey) holderKey := GetTokenHolderKey(tokenHolder.GetModuleName()) b := keeper.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) @@ -136,23 +150,27 @@ func (keeper BaseKeeper) SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder // RequestTokens adds requested tokens to the module's holdings func (keeper BaseKeeper) RequestTokens( ctx sdk.Context, moduleName string, amount sdk.Coins, -) error { +) sdk.Error { if !amount.IsValid() { - return fmt.Errorf("invalid requested amount") + return sdk.ErrInvalidCoins("invalid requested amount") } holder, err := keeper.GetTokenHolder(ctx, moduleName) if err != nil { - return fmt.Errorf("module %s doesn't exist", moduleName) + return ErrUnknownTokenHolder( + DefaultCodespace, + fmt.Sprintf("token holder %s doesn't exist", moduleName), + ) } + // update global supply held by token holders supplier := keeper.GetSupplier(ctx) supplier.HoldersSupply = supplier.HoldersSupply.Add(amount) holder.SetHoldings(holder.GetHoldings().Add(amount)) - keeper.SetTokenHolder(ctx, holder) - keeper.SetSupplier(ctx, supplier) + keeper.setTokenHolder(ctx, holder) + keeper.setSupplier(ctx, supplier) return nil } @@ -161,19 +179,23 @@ func (keeper BaseKeeper) RelinquishTokens( ctx sdk.Context, moduleName string, amount sdk.Coins, ) error { if !amount.IsValid() { - return fmt.Errorf("invalid provided relenquished amount") + return sdk.ErrInvalidCoins("invalid provided relenquished amount") } holder, err := keeper.GetTokenHolder(ctx, moduleName) if err != nil { - return fmt.Errorf("module %s doesn't exist", moduleName) + return ErrUnknownTokenHolder( + DefaultCodespace, + fmt.Sprintf("token holder %s doesn't exist", moduleName), + ) } newHoldings, ok := holder.GetHoldings().SafeSub(amount) if !ok { - return fmt.Errorf("insufficient token holdings") + return sdk.ErrInsufficientCoins("insufficient token holdings") } + // update global supply held by token holders supplier := keeper.GetSupplier(ctx) newHoldersSupply, ok := supplier.HoldersSupply.SafeSub(amount) if !ok { @@ -183,8 +205,8 @@ func (keeper BaseKeeper) RelinquishTokens( holder.SetHoldings(newHoldings) - keeper.SetTokenHolder(ctx, holder) - keeper.SetSupplier(ctx, supplier) + keeper.setTokenHolder(ctx, holder) + keeper.setSupplier(ctx, supplier) return nil } diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index 28db4a3dcc52..fc206940d374 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -20,6 +20,7 @@ import ( type testInput struct { cdc *codec.Codec ctx sdk.Context + key sdk.StoreKey ak auth.AccountKeeper pk params.Keeper } @@ -32,6 +33,7 @@ func setupTestInput() testInput { authCapKey := sdk.NewKVStoreKey("authCapKey") fckCapKey := sdk.NewKVStoreKey("fckCapKey") + keySupply := sdk.NewKVStoreKey("bank") keyParams := sdk.NewKVStoreKey("params") tkeyParams := sdk.NewTransientStoreKey("transient_params") @@ -50,13 +52,13 @@ func setupTestInput() testInput { ak.SetParams(ctx, auth.DefaultParams()) - return testInput{cdc: cdc, ctx: ctx, ak: ak, pk: pk} + return testInput{cdc: cdc, key: keySupply, ctx: ctx, ak: ak, pk: pk} } func TestKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx - bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr := sdk.AccAddress([]byte("addr1")) @@ -137,8 +139,8 @@ func TestSendKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx paramSpace := input.pk.Subspace(DefaultParamspace) - bankKeeper := NewBaseKeeper(input.ak, paramSpace, DefaultCodespace) - sendKeeper := NewBaseSendKeeper(input.ak, paramSpace, DefaultCodespace) + bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, paramSpace, DefaultCodespace) + sendKeeper := NewBaseSendKeeper(input.cdc, input.key, input.ak, paramSpace, DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr := sdk.AccAddress([]byte("addr1")) @@ -186,9 +188,9 @@ func TestViewKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx paramSpace := input.pk.Subspace(DefaultParamspace) - bankKeeper := NewBaseKeeper(input.ak, paramSpace, DefaultCodespace) + bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, paramSpace, DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) - viewKeeper := NewBaseViewKeeper(input.ak, DefaultCodespace) + viewKeeper := NewBaseViewKeeper(input.cdc, input.key, input.ak, DefaultCodespace) addr := sdk.AccAddress([]byte("addr1")) acc := input.ak.NewAccountWithAddress(ctx, addr) @@ -215,7 +217,7 @@ 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(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) @@ -249,7 +251,7 @@ 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(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) @@ -283,7 +285,7 @@ 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(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) @@ -320,7 +322,7 @@ 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(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) diff --git a/x/bank/token_holder.go b/x/bank/token_holder.go index 2b2367a78619..9ff2bbefecb3 100644 --- a/x/bank/token_holder.go +++ b/x/bank/token_holder.go @@ -31,8 +31,8 @@ type BaseTokenHolder struct { } // NewBaseTokenHolder creates a new BaseTokenHolder instance -func NewBaseTokenHolder(moduleName string, initialHoldings sdk.Coins) BaseTokenHolder { - return BaseTokenHolder{ +func NewBaseTokenHolder(moduleName string, initialHoldings sdk.Coins) TokenHolder { + return &BaseTokenHolder{ Module: moduleName, Holdings: initialHoldings, } From 7a3787cffb1eed237142b83d99b22ada7f714bda Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 15 Apr 2019 17:46:51 +0200 Subject: [PATCH 11/46] use token holder on gov instead of acc --- x/gov/expected_keepers.go | 12 ++++++++---- x/gov/genesis.go | 6 ++++++ x/gov/keeper.go | 35 ++++++++++++++++++++++------------- x/gov/test_common.go | 3 ++- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/x/gov/expected_keepers.go b/x/gov/expected_keepers.go index bc80bcedcba1..fd9ae395cfc3 100644 --- a/x/gov/expected_keepers.go +++ b/x/gov/expected_keepers.go @@ -1,12 +1,16 @@ package gov -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" +) // expected bank keeper type BankKeeper interface { GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + AddCoins(tx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - // TODO remove once governance doesn't require use of accounts - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - SetSendEnabled(ctx sdk.Context, enabled bool) + AddTokenHolder(ctx sdk.Context, moduleName string) (bank.TokenHolder, sdk.Error) + RequestTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) sdk.Error + RelinquishTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) sdk.Error } diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 4aeb9d862388..4ba9c4388d4e 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -107,6 +107,12 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { // TODO: Handle this with #870 panic(err) } + + _, err = k.ck.AddTokenHolder(ctx, ModuleName) + if err != nil { + panic(err) + } + k.setDepositParams(ctx, data.DepositParams) k.setVotingParams(ctx, data.VotingParams) k.setTallyParams(ctx, data.TallyParams) diff --git a/x/gov/keeper.go b/x/gov/keeper.go index a2216698bd64..12b31f991ff6 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -5,6 +5,7 @@ import ( codec "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/params" "github.com/tendermint/tendermint/crypto" @@ -58,6 +59,9 @@ type Keeper struct { // The reference to the CoinKeeper to modify balances ck BankKeeper + // The reference to the TokenHolder to hold the deposit and burn amounts + th bank.TokenHolder + // The ValidatorSet to get information about validators vs sdk.ValidatorSet @@ -79,9 +83,10 @@ type Keeper struct { // - depositing funds into proposals, and activating upon sufficient funds being deposited // - users voting on proposals, with weight proportional to stake in the system // - and tallying the result of the vote. +// CONTRACT: Token Holder needs to be added into the bank keeper before calling +// this function func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, - paramSpace params.Subspace, ck BankKeeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { - + paramSpace params.Subspace, ck BankKeeper, tokenHolder bank.TokenHolder, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { return Keeper{ storeKey: key, paramsKeeper: paramsKeeper, @@ -380,9 +385,8 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false } - // Send coins from depositor's account to DepositedCoinsAccAddr account - // TODO: Don't use an account for this purpose; it's clumsy and prone to misuse. - err := keeper.ck.SendCoins(ctx, depositorAddr, DepositedCoinsAccAddr, depositAmount) + // request coins for the governance token holder + err := keeper.ck.RequestTokens(ctx, keeper.th.GetModuleName(), depositAmount) if err != nil { return err, false } @@ -411,13 +415,13 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd return nil, activatedVotingPeriod } -// Gets all the deposits on a specific proposal as an sdk.Iterator +// GetDeposits Gets all the deposits on a specific proposal as an sdk.Iterator func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID uint64) sdk.Iterator { store := ctx.KVStore(keeper.storeKey) return sdk.KVStorePrefixIterator(store, KeyDepositsSubspace(proposalID)) } -// Refunds and deletes all the deposits on a specific proposal +// RefundDeposits Refunds and deletes all the deposits on a specific proposal func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { store := ctx.KVStore(keeper.storeKey) depositsIterator := keeper.GetDeposits(ctx, proposalID) @@ -426,16 +430,21 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { deposit := &Deposit{} keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) - err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, deposit.Depositor, deposit.Amount) + err := keeper.ck.RelinquishTokens(ctx, ModuleName, deposit.Amount) + if err != nil { + panic(err.Error()) + } + + _, err = keeper.ck.AddCoins(ctx, deposit.Depositor, deposit.Amount) if err != nil { - panic("should not happen") + panic(err.Error()) } store.Delete(depositsIterator.Key()) } } -// Deletes all the deposits on a specific proposal without refunding them +// DeleteDeposits Deletes all the deposits on a specific proposal without refunding them func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { store := ctx.KVStore(keeper.storeKey) depositsIterator := keeper.GetDeposits(ctx, proposalID) @@ -444,10 +453,10 @@ func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { deposit := &Deposit{} keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) - // TODO: Find a way to do this without using accounts. - err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, BurnedDepositCoinsAccAddr, deposit.Amount) + // Burn deposits; TODO: consider sending to community pool + err := keeper.ck.RelinquishTokens(ctx, ModuleName, deposit.Amount) if err != nil { - panic("should not happen") + panic(err.Error()) } store.Delete(depositsIterator.Key()) diff --git a/x/gov/test_common.go b/x/gov/test_common.go index a14251841d56..054eb68a4bb6 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -30,10 +30,11 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a keyStaking := sdk.NewKVStoreKey(staking.StoreKey) tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) + keySupply := sdk.NewKVStoreKey(bank.StoreKey) keyGov := sdk.NewKVStoreKey(StoreKey) pk := mapp.ParamsKeeper - ck := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + ck := bank.NewBaseKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) sk = staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, ck, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) keeper = NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, DefaultCodespace) From 949c3423d0dccb21b85084ee14f41ec1584b694c Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 15 Apr 2019 17:47:16 +0200 Subject: [PATCH 12/46] minor tests instances fixes --- cmd/gaia/cmd/gaiadebug/hack.go | 2 +- x/distribution/keeper/test_common.go | 3 ++- x/ibc/app_test.go | 3 ++- x/ibc/ibc_test.go | 3 ++- x/staking/keeper/test_common.go | 2 ++ 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 51927592a414..7b46896e05d6 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -178,7 +178,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp ) // add handlers - app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + app.bankKeeper = bank.NewBaseKeeper(app.cdc, app.keySupply, app.accountKeeper, app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) app.stakingKeeper = staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking, app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), slashing.DefaultCodespace) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index c21d6a8d2c6a..4b89e874c261 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -92,6 +92,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, keyStaking := sdk.NewKVStoreKey(staking.StoreKey) tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) + keySupply := sdk.NewKVStoreKey(bank.StoreKey) keyFeeCollection := sdk.NewKVStoreKey(auth.FeeStoreKey) keyParams := sdk.NewKVStoreKey(params.StoreKey) tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) @@ -115,7 +116,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + bankKeeper := bank.NewBaseKeeper(cdc, keySupply, accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, bankKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) sk.SetPool(ctx, staking.InitialPool()) sk.SetParams(ctx, staking.DefaultParams()) diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go index ca51ae9d8b6f..403350dac577 100644 --- a/x/ibc/app_test.go +++ b/x/ibc/app_test.go @@ -20,8 +20,9 @@ func getMockApp(t *testing.T) *mock.App { RegisterCodec(mapp.Cdc) keyIBC := sdk.NewKVStoreKey("ibc") + keySupply := sdk.NewKVStoreKey(bank.StoreKey) ibcMapper := NewMapper(mapp.Cdc, keyIBC, DefaultCodespace) - bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, + bankKeeper := bank.NewBaseKeeper(map.Cdc, keySupply, mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) mapp.Router().AddRoute("ibc", NewHandler(ibcMapper, bankKeeper)) diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index 286da66fd9c1..d7d00ed05a0c 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -34,6 +34,7 @@ func setupTestInput() testInput { ibcKey := sdk.NewKVStoreKey("ibcCapKey") authCapKey := sdk.NewKVStoreKey("authCapKey") + keySupply := sdk.NewKVStoreKey(bank.StoreKey) fckCapKey := sdk.NewKVStoreKey("fckCapKey") keyParams := sdk.NewKVStoreKey("params") tkeyParams := sdk.NewTransientStoreKey("transient_params") @@ -50,7 +51,7 @@ func setupTestInput() testInput { ak := auth.NewAccountKeeper( cdc, authCapKey, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount, ) - bk := bank.NewBaseKeeper(ak, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + bk := bank.NewBaseKeeper(cdc, keySupply, ak, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) ctx := sdk.NewContext(ms, abci.Header{ChainID: "test-chain-id"}, false, log.NewNopLogger()) ak.SetParams(ctx, auth.DefaultParams()) diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 9b5c442f1201..e1acf9495699 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -117,6 +117,8 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ) ck := bank.NewBaseKeeper( + cdc, + sdk.NewKVStoreKey(bank.StoreKey), accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, From 28b17e5634cef2e43edaa5be5b4bb0a7e5c979cb Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 16 Apr 2019 11:17:04 +0200 Subject: [PATCH 13/46] module supply --- x/bank/codec.go | 4 +- x/bank/errors.go | 9 - x/bank/expected_keepers.go | 2 +- x/bank/genesis.go | 29 +--- x/bank/keeper.go | 152 ---------------- x/bank/msgs.go | 2 +- x/bank/params.go | 4 +- x/supply/genesis.go | 52 ++++++ x/supply/keeper/keeper.go | 164 ++++++++++++++++++ x/{bank/keys.go => supply/keeper/key.go} | 4 +- x/supply/types/codec.go | 17 ++ x/supply/types/errors.go | 23 +++ .../supply.go => supply/types/supplier.go} | 2 +- x/{bank => supply/types}/token_holder.go | 2 +- 14 files changed, 272 insertions(+), 194 deletions(-) create mode 100644 x/supply/genesis.go create mode 100644 x/supply/keeper/keeper.go rename x/{bank/keys.go => supply/keeper/key.go} (92%) create mode 100644 x/supply/types/codec.go create mode 100644 x/supply/types/errors.go rename x/{bank/supply.go => supply/types/supplier.go} (99%) rename x/{bank => supply/types}/token_holder.go (99%) diff --git a/x/bank/codec.go b/x/bank/codec.go index 72f03e7c5ced..192b3f0e7e50 100644 --- a/x/bank/codec.go +++ b/x/bank/codec.go @@ -4,12 +4,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -// Register concrete types on codec codec +// RegisterCodec registers concrete types on codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/MsgSend", nil) cdc.RegisterConcrete(MsgMultiSend{}, "cosmos-sdk/MsgMultiSend", nil) - cdc.RegisterInterface((*TokenHolder)(nil), nil) - cdc.RegisterConcrete(&BaseTokenHolder{}, "bank/BaseTokenHolder", nil) } var msgCdc = codec.New() diff --git a/x/bank/errors.go b/x/bank/errors.go index 8c49068727b9..b74f64cc4bb2 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -13,7 +13,6 @@ const ( CodeSendDisabled CodeType = 101 CodeInvalidInputsOutputs CodeType = 102 - CodeUnknownTokenHolder CodeType = 103 ) // ErrNoInputs is an error @@ -35,11 +34,3 @@ func ErrInputOutputMismatch(codespace sdk.CodespaceType) sdk.Error { func ErrSendDisabled(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeSendDisabled, "send transactions are currently disabled") } - -// ErrUnknownTokenHolder is an error -func ErrUnknownTokenHolder(codespace sdk.CodespaceType, msg string) sdk.Error { - if msg != "" { - return sdk.NewError(codespace, CodeUnknownTokenHolder, msg) - } - return sdk.NewError(codespace, CodeUnknownTokenHolder, "unknown token holder") -} diff --git a/x/bank/expected_keepers.go b/x/bank/expected_keepers.go index 6d256d926d6e..7e66dbd6f440 100644 --- a/x/bank/expected_keepers.go +++ b/x/bank/expected_keepers.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// expected crisis keeper +// CrisisKeeper expected crisis keeper type CrisisKeeper interface { RegisterRoute(moduleName, route string, invar sdk.Invariant) } diff --git a/x/bank/genesis.go b/x/bank/genesis.go index f8aea895aae3..40ac810b530c 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -1,55 +1,38 @@ package bank import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" ) // GenesisState is the bank state that must be provided at genesis. type GenesisState struct { - SendEnabled bool `json:"send_enabled"` - Supplier Supplier `json:"supplier"` - ModulesHoldings []TokenHolder `json:"modules_holdings"` + SendEnabled bool `json:"send_enabled"` } // NewGenesisState creates a new genesis state. -func NewGenesisState( - sendEnabled bool, supplier Supplier, holdings []TokenHolder, -) GenesisState { +func NewGenesisState(sendEnabled bool) GenesisState { return GenesisState{ - SendEnabled: sendEnabled, - Supplier: supplier, - ModulesHoldings: holdings, + SendEnabled: sendEnabled, } } // DefaultGenesisState returns a default genesis state func DefaultGenesisState() GenesisState { - return NewGenesisState(true, DefaultSupplier(), []TokenHolder{}) + return NewGenesisState(true) } // InitGenesis sets distribution information for genesis. func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { keeper.SetSendEnabled(ctx, data.SendEnabled) - keeper.SetSupplier(ctx, data.Supplier) - for _, holder := range data.ModulesHoldings { - keeper.SetTokenHolder(ctx, holder) - } } // ExportGenesis returns a GenesisState for a given context and keeper. func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { - return NewGenesisState( - keeper.GetSendEnabled(ctx), - keeper.GetSupplier(ctx), - keeper.GetTokenHolders(ctx), - ) + return NewGenesisState(keeper.GetSendEnabled(ctx)) } // ValidateGenesis performs basic validation of bank genesis data returning an // error for any failed validation criteria. func ValidateGenesis(data GenesisState) error { - err := data.Supplier.ValidateBasic().Error() - return fmt.Errorf(err) + return nil } diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 9c341674bf8d..c6c7c2fc2699 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -18,17 +18,6 @@ var _ Keeper = (*BaseKeeper)(nil) type Keeper interface { SendKeeper - GetSupplier(ctx sdk.Context) Supplier - SetSupplier(ctx sdk.Context, supplier Supplier) - InflateSupply(ctx sdk.Context, amt sdk.Coins) - - GetTokenHolders(ctx sdk.Context) []TokenHolder - GetTokenHolder(ctx sdk.Context, moduleName string) (TokenHolder, error) - SetTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) - - RequestTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) error - RelinquishTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) error - SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) @@ -69,147 +58,6 @@ func NewBaseKeeper( } } -// GetSupplier retrieves the Supplier from store -func (keeper BaseKeeper) GetSupplier(ctx sdk.Context) (supplier Supplier) { - store := ctx.KVStore(keeper.storeKey) - b := store.Get(supplierKey) - if b == nil { - panic("Stored fee pool should not have been nil") - } - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, &supplier) - return -} - -// SetSupplier sets the Supplier to store -func (keeper BaseKeeper) setSupplier(ctx sdk.Context, supplier Supplier) { - store := ctx.KVStore(keeper.storeKey) - b := keeper.cdc.MustMarshalBinaryLengthPrefixed(supplier) - store.Set(supplierKey, b) -} - -// InflateSupply adds tokens to the circulating supply -func (keeper BaseKeeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { - supplier := keeper.GetSupplier(ctx) - supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) - keeper.setSupplier(ctx, supplier) -} - -// GetTokenHolders returns all the token holders -func (keeper BaseKeeper) GetTokenHolders(ctx sdk.Context) ( - tokenHolders []TokenHolder) { - store := ctx.KVStore(keeper.storeKey) - iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) - defer iterator.Close() - - var tokenHolder TokenHolder - for ; iterator.Valid(); iterator.Next() { - err := keeper.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) - if err != nil { - panic(err) - } - tokenHolders = append(tokenHolders, tokenHolder) - } - return -} - -// GetTokenHolder returns a token holder instance -func (keeper BaseKeeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( - tokenHolder TokenHolder, err error) { - store := ctx.KVStore(keeper.storeKey) - b := store.Get(GetTokenHolderKey(moduleName)) - if b == nil { - err = fmt.Errorf("token holder with module %s doesn't exist", moduleName) - return - } - keeper.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) - return -} - -// AddTokenHolder creates and sets a token holder instance to store -func (keeper BaseKeeper) AddTokenHolder(ctx sdk.Context, moduleName string) ( - tokenHolder TokenHolder, err error) { - store := ctx.KVStore(keeper.storeKey) - if store.Has(GetTokenHolderKey(moduleName)) { - err = fmt.Errorf("token holder with module %s already exist", moduleName) - return - } - - tokenHolder = NewBaseTokenHolder(moduleName, sdk.Coins{}) - keeper.setTokenHolder(ctx, tokenHolder) - return -} - -// SetTokenHolder sets a holder to store -func (keeper BaseKeeper) setTokenHolder(ctx sdk.Context, tokenHolder TokenHolder) { - store := ctx.KVStore(keeper.storeKey) - holderKey := GetTokenHolderKey(tokenHolder.GetModuleName()) - b := keeper.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) - store.Set(holderKey, b) -} - -// RequestTokens adds requested tokens to the module's holdings -func (keeper BaseKeeper) RequestTokens( - ctx sdk.Context, moduleName string, amount sdk.Coins, -) sdk.Error { - if !amount.IsValid() { - return sdk.ErrInvalidCoins("invalid requested amount") - } - - holder, err := keeper.GetTokenHolder(ctx, moduleName) - if err != nil { - return ErrUnknownTokenHolder( - DefaultCodespace, - fmt.Sprintf("token holder %s doesn't exist", moduleName), - ) - } - - // update global supply held by token holders - supplier := keeper.GetSupplier(ctx) - supplier.HoldersSupply = supplier.HoldersSupply.Add(amount) - - holder.SetHoldings(holder.GetHoldings().Add(amount)) - - keeper.setTokenHolder(ctx, holder) - keeper.setSupplier(ctx, supplier) - return nil -} - -// RelinquishTokens hands over a portion of the module's holdings -func (keeper BaseKeeper) RelinquishTokens( - ctx sdk.Context, moduleName string, amount sdk.Coins, -) error { - if !amount.IsValid() { - return sdk.ErrInvalidCoins("invalid provided relenquished amount") - } - - holder, err := keeper.GetTokenHolder(ctx, moduleName) - if err != nil { - return ErrUnknownTokenHolder( - DefaultCodespace, - fmt.Sprintf("token holder %s doesn't exist", moduleName), - ) - } - - newHoldings, ok := holder.GetHoldings().SafeSub(amount) - if !ok { - return sdk.ErrInsufficientCoins("insufficient token holdings") - } - - // update global supply held by token holders - supplier := keeper.GetSupplier(ctx) - newHoldersSupply, ok := supplier.HoldersSupply.SafeSub(amount) - if !ok { - panic("total holders supply should be greater than relinquished amount") - } - supplier.HoldersSupply = newHoldersSupply - - holder.SetHoldings(newHoldings) - - keeper.setTokenHolder(ctx, holder) - keeper.setSupplier(ctx, supplier) - return nil -} - // SetCoins sets the coins at the addr. func (keeper BaseKeeper) SetCoins( ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins, diff --git a/x/bank/msgs.go b/x/bank/msgs.go index c9b4f554482b..2455190d345b 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -5,7 +5,7 @@ import ( ) // RouterKey is they name of the bank module -const RouterKey = "bank" +const RouterKey = ModuleName // MsgSend - high level transaction of the coin module type MsgSend struct { diff --git a/x/bank/params.go b/x/bank/params.go index b381e4e847e5..e02f49487d6f 100644 --- a/x/bank/params.go +++ b/x/bank/params.go @@ -5,8 +5,10 @@ import ( ) const ( + // ModuleName is the name of the module + ModuleName = "bank" // DefaultParamspace for params keeper - DefaultParamspace = "bank" + DefaultParamspace = ModuleName // DefaultSendEnabled enabled DefaultSendEnabled = true ) diff --git a/x/supply/genesis.go b/x/supply/genesis.go new file mode 100644 index 000000000000..5cca26d2dd16 --- /dev/null +++ b/x/supply/genesis.go @@ -0,0 +1,52 @@ +package supply + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/supply/keeper" + "github.com/cosmos/cosmos-sdk/x/supply/types" +) + +// GenesisState is the supply state that must be provided at genesis. +type GenesisState struct { + Supplier types.Supplier `json:"supplier"` + ModulesHoldings []types.TokenHolder `json:"modules_holdings"` +} + +// NewGenesisState creates a new genesis state. +func NewGenesisState(supplier types.Supplier, holdings []types.TokenHolder, +) GenesisState { + return GenesisState{ + Supplier: supplier, + ModulesHoldings: holdings, + } +} + +// DefaultGenesisState returns a default genesis state +func DefaultGenesisState() GenesisState { + return NewGenesisState(types.DefaultSupplier(), []types.TokenHolder{}) +} + +// InitGenesis sets distribution information for genesis. +func InitGenesis(ctx sdk.Context, k keeper.Keeper, data GenesisState) { + k.SetSupplier(ctx, data.Supplier) + for _, holder := range data.ModulesHoldings { + k.SetTokenHolder(ctx, holder) + } +} + +// ExportGenesis returns a GenesisState for a given context and keeper. +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) GenesisState { + return NewGenesisState( + k.GetSupplier(ctx), + k.GetTokenHolders(ctx), + ) +} + +// ValidateGenesis performs basic validation of bank genesis data returning an +// error for any failed validation criteria. +func ValidateGenesis(data GenesisState) error { + err := data.Supplier.ValidateBasic().Error() + return fmt.Errorf(err) +} diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go new file mode 100644 index 000000000000..13845d3fb89b --- /dev/null +++ b/x/supply/keeper/keeper.go @@ -0,0 +1,164 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" +) + +// Keeper defines the k of the supply store +type Keeper struct { + cdc *codec.Codec + storeKey sdk.StoreKey +} + +// NewKeeper creates a new supply Keeper instance +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper { + return Keeper{ + cdc: cdc, + storeKey: key, + } +} + +// GetSupplier retrieves the Supplier from store +func (k Keeper) GetSupplier(ctx sdk.Context) (supplier types.Supplier) { + store := ctx.KVStore(k.storeKey) + b := store.Get(supplierKey) + if b == nil { + panic("Stored fee pool should not have been nil") + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &supplier) + return +} + +// SetSupplier sets the Supplier to store +func (k Keeper) SetSupplier(ctx sdk.Context, supplier types.Supplier) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshalBinaryLengthPrefixed(supplier) + store.Set(supplierKey, b) +} + +// InflateSupply adds tokens to the circulating supply +func (k Keeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { + supplier := k.GetSupplier(ctx) + supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) + k.SetSupplier(ctx, supplier) +} + +// GetTokenHolders returns all the token holders +func (k Keeper) GetTokenHolders(ctx sdk.Context) ( + tokenHolders []types.TokenHolder) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) + defer iterator.Close() + + var tokenHolder types.TokenHolder + for ; iterator.Valid(); iterator.Next() { + err := k.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) + if err != nil { + panic(err) + } + tokenHolders = append(tokenHolders, tokenHolder) + } + return +} + +// GetTokenHolder returns a token holder instance +func (k Keeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( + tokenHolder types.TokenHolder, err error) { + store := ctx.KVStore(k.storeKey) + b := store.Get(GetTokenHolderKey(moduleName)) + if b == nil { + err = fmt.Errorf("token holder with module %s doesn't exist", moduleName) + return + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) + return +} + +// AddTokenHolder creates and sets a token holder instance to store +func (k Keeper) AddTokenHolder(ctx sdk.Context, moduleName string) ( + tokenHolder types.TokenHolder, err error) { + store := ctx.KVStore(k.storeKey) + if store.Has(GetTokenHolderKey(moduleName)) { + err = fmt.Errorf("token holder with module %s already exist", moduleName) + return + } + + tokenHolder = types.NewBaseTokenHolder(moduleName, sdk.Coins{}) + k.SetTokenHolder(ctx, tokenHolder) + return +} + +// SetTokenHolder sets a holder to store +func (k Keeper) SetTokenHolder(ctx sdk.Context, tokenHolder types.TokenHolder) { + store := ctx.KVStore(k.storeKey) + holderKey := GetTokenHolderKey(tokenHolder.GetModuleName()) + b := k.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) + store.Set(holderKey, b) +} + +// RequestTokens adds requested tokens to the module's holdings +func (k Keeper) RequestTokens( + ctx sdk.Context, moduleName string, amount sdk.Coins, +) sdk.Error { + if !amount.IsValid() { + return sdk.ErrInvalidCoins("invalid requested amount") + } + + holder, err := k.GetTokenHolder(ctx, moduleName) + if err != nil { + return types.ErrUnknownTokenHolder( + types.DefaultCodespace, + fmt.Sprintf("token holder %s doesn't exist", moduleName), + ) + } + + // update global supply held by token holders + supplier := k.GetSupplier(ctx) + supplier.HoldersSupply = supplier.HoldersSupply.Add(amount) + + holder.SetHoldings(holder.GetHoldings().Add(amount)) + + k.SetTokenHolder(ctx, holder) + k.SetSupplier(ctx, supplier) + return nil +} + +// RelinquishTokens hands over a portion of the module's holdings +func (k Keeper) RelinquishTokens( + ctx sdk.Context, moduleName string, amount sdk.Coins, +) error { + if !amount.IsValid() { + return sdk.ErrInvalidCoins("invalid provided relenquished amount") + } + + holder, err := k.GetTokenHolder(ctx, moduleName) + if err != nil { + return types.ErrUnknownTokenHolder( + types.DefaultCodespace, + fmt.Sprintf("token holder %s doesn't exist", moduleName), + ) + } + + newHoldings, ok := holder.GetHoldings().SafeSub(amount) + if !ok { + return sdk.ErrInsufficientCoins("insufficient token holdings") + } + + // update global supply held by token holders + supplier := k.GetSupplier(ctx) + newHoldersSupply, ok := supplier.HoldersSupply.SafeSub(amount) + if !ok { + panic("total holders supply should be greater than relinquished amount") + } + supplier.HoldersSupply = newHoldersSupply + + holder.SetHoldings(newHoldings) + + k.SetTokenHolder(ctx, holder) + k.SetSupplier(ctx, supplier) + return nil +} diff --git a/x/bank/keys.go b/x/supply/keeper/key.go similarity index 92% rename from x/bank/keys.go rename to x/supply/keeper/key.go index 1fcaa41a2923..46f3a13dfc7b 100644 --- a/x/bank/keys.go +++ b/x/supply/keeper/key.go @@ -1,8 +1,8 @@ -package bank +package keeper const ( // ModuleName is the name of the module - ModuleName = "bank" + ModuleName = "supply" // StoreKey is the default store key for supply StoreKey = ModuleName diff --git a/x/supply/types/codec.go b/x/supply/types/codec.go new file mode 100644 index 000000000000..9f32934c34b2 --- /dev/null +++ b/x/supply/types/codec.go @@ -0,0 +1,17 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +// RegisterCodec registers concrete types on codec +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*TokenHolder)(nil), nil) + cdc.RegisterConcrete(&BaseTokenHolder{}, "bank/BaseTokenHolder", nil) +} + +var msgCdc = codec.New() + +func init() { + RegisterCodec(msgCdc) +} diff --git a/x/supply/types/errors.go b/x/supply/types/errors.go new file mode 100644 index 000000000000..df8e9c3bee3f --- /dev/null +++ b/x/supply/types/errors.go @@ -0,0 +1,23 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// CodeType definition +type CodeType = sdk.CodeType + +// Supply errors reserve 550 - 599 +const ( + DefaultCodespace sdk.CodespaceType = "supply" + + CodeUnknownTokenHolder CodeType = 550 +) + +// ErrUnknownTokenHolder is an error +func ErrUnknownTokenHolder(codespace sdk.CodespaceType, msg string) sdk.Error { + if msg != "" { + return sdk.NewError(codespace, CodeUnknownTokenHolder, msg) + } + return sdk.NewError(codespace, CodeUnknownTokenHolder, "unknown token holder") +} diff --git a/x/bank/supply.go b/x/supply/types/supplier.go similarity index 99% rename from x/bank/supply.go rename to x/supply/types/supplier.go index 80466d341f55..5f23134ce4e0 100644 --- a/x/bank/supply.go +++ b/x/supply/types/supplier.go @@ -1,4 +1,4 @@ -package bank +package types import ( "fmt" diff --git a/x/bank/token_holder.go b/x/supply/types/token_holder.go similarity index 99% rename from x/bank/token_holder.go rename to x/supply/types/token_holder.go index 9ff2bbefecb3..60fef2b101aa 100644 --- a/x/bank/token_holder.go +++ b/x/supply/types/token_holder.go @@ -1,4 +1,4 @@ -package bank +package types import ( sdk "github.com/cosmos/cosmos-sdk/types" From 3a5eed9e74b0d96c4bfc8e86bcca31a3f505a5ab Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 16 Apr 2019 12:08:09 +0200 Subject: [PATCH 14/46] more cleanup --- cmd/gaia/app/app.go | 12 ++++++--- cmd/gaia/app/genesis.go | 27 ++++++++++++++------ cmd/gaia/cmd/gaiadebug/hack.go | 2 +- x/bank/bench_test.go | 2 -- x/bank/genesis.go | 12 +++------ x/bank/keeper.go | 24 +++--------------- x/bank/keeper_test.go | 21 ++++++++-------- x/distribution/keeper/test_common.go | 3 +-- x/gov/expected_keepers.go | 9 ++++--- x/gov/keeper.go | 24 +++++++++--------- x/gov/test_common.go | 16 ++++++------ x/ibc/app_test.go | 3 +-- x/ibc/ibc_test.go | 3 +-- x/mint/abci_app.go | 2 +- x/mint/expected_keepers.go | 8 +++--- x/mint/keeper.go | 31 ++++++++++++----------- x/staking/keeper/test_common.go | 2 -- x/supply/alias.go | 37 ++++++++++++++++++++++++++++ x/supply/keeper/keeper.go | 2 +- 19 files changed, 134 insertions(+), 106 deletions(-) create mode 100644 x/supply/alias.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index afca4f1976ef..38a7008e4f36 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -23,6 +23,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/supply" ) const ( @@ -84,7 +85,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, cdc: cdc, keyMain: sdk.NewKVStoreKey(bam.MainStoreKey), keyAccount: sdk.NewKVStoreKey(auth.StoreKey), - keySupply: sdk.NewKVStoreKey(bank.StoreKey), + keySupply: sdk.NewKVStoreKey(supply.StoreKey), keyStaking: sdk.NewKVStoreKey(staking.StoreKey), tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey), keyMint: sdk.NewKVStoreKey(mint.StoreKey), @@ -109,12 +110,15 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, // add handlers app.bankKeeper = bank.NewBaseKeeper( - cdc, - app.keySupply, app.accountKeeper, app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, ) + // app.supplyKeeper = supply.NewKeeper( + // app.accountKeeper, + // app.paramsKeeper.Subspace(bank.DefaultParamspace), + // bank.DefaultCodespace, + // ) app.feeCollectionKeeper = auth.NewFeeCollectionKeeper( app.cdc, app.keyFeeCollection, @@ -127,7 +131,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, ) app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, app.paramsKeeper.Subspace(mint.DefaultParamspace), - app.bankKeeper, &stakingKeeper, app.feeCollectionKeeper, + app.supplyKeeper, &stakingKeeper, app.feeCollectionKeeper, ) app.distrKeeper = distr.NewKeeper( app.cdc, diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 41c058ff0c16..b285cbc5efde 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -23,6 +23,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/supply" ) var ( @@ -42,14 +43,22 @@ type GenesisState struct { GovData gov.GenesisState `json:"gov"` CrisisData crisis.GenesisState `json:"crisis"` SlashingData slashing.GenesisState `json:"slashing"` + SupplyData supply.GenesisState `json:"slashing"` GenTxs []json.RawMessage `json:"gentxs"` } -func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, +// NewGenesisState creates a new Gaia genesis state instance +func NewGenesisState( + accounts []GenesisAccount, + authData auth.GenesisState, bankData bank.GenesisState, - stakingData staking.GenesisState, mintData mint.GenesisState, - distrData distr.GenesisState, govData gov.GenesisState, crisisData crisis.GenesisState, - slashingData slashing.GenesisState) GenesisState { + stakingData staking.GenesisState, + mintData mint.GenesisState, + distrData distr.GenesisState, + govData gov.GenesisState, + crisisData crisis.GenesisState, + slashingData slashing.GenesisState, + supplyData supply.GenesisState) GenesisState { return GenesisState{ Accounts: accounts, @@ -61,6 +70,7 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, GovData: govData, CrisisData: crisisData, SlashingData: slashingData, + SupplyData: supplyData, } } @@ -188,8 +198,8 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js circulatingSupply, vestingSupply, notBondedSupply, bondedSupply := supplyFromGenAccounts(genesisState.Accounts, genesisState.StakingData.Params.BondDenom) - genesisState.BankData.Supplier.CirculatingSupply = circulatingSupply - genesisState.BankData.Supplier.VestingSupply = vestingSupply + genesisState.SupplyData.Supplier.CirculatingSupply = circulatingSupply + genesisState.SupplyData.Supplier.VestingSupply = vestingSupply genesisState.StakingData.Pool.NotBondedTokens = notBondedSupply genesisState.StakingData.Pool.BondedTokens = bondedSupply genesisState.GenTxs = appGenTxs @@ -248,8 +258,11 @@ func GaiaValidateGenesisState(genesisState GenesisState) error { if err := crisis.ValidateGenesis(genesisState.CrisisData); err != nil { return err } + if err := slashing.ValidateGenesis(genesisState.SlashingData); err != nil { + return err + } - return slashing.ValidateGenesis(genesisState.SlashingData) + return supply.ValidateGenesis(genesisState.SupplyData) } // validateGenesisStateAccounts performs validation of genesis accounts. It diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 7b46896e05d6..51927592a414 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -178,7 +178,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp ) // add handlers - app.bankKeeper = bank.NewBaseKeeper(app.cdc, app.keySupply, app.accountKeeper, app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) app.stakingKeeper = staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking, app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), slashing.DefaultCodespace) diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index dee28bc60423..95918110c4de 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -17,8 +17,6 @@ func getBenchmarkMockApp() (*mock.App, error) { RegisterCodec(mapp.Cdc) bankKeeper := NewBaseKeeper( - mapp.Cdc, - sdk.NewKVStoreKey(StoreKey), mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace, diff --git a/x/bank/genesis.go b/x/bank/genesis.go index 40ac810b530c..1bdf4e7ff92a 100644 --- a/x/bank/genesis.go +++ b/x/bank/genesis.go @@ -11,15 +11,11 @@ type GenesisState struct { // NewGenesisState creates a new genesis state. func NewGenesisState(sendEnabled bool) GenesisState { - return GenesisState{ - SendEnabled: sendEnabled, - } + return GenesisState{SendEnabled: sendEnabled} } // DefaultGenesisState returns a default genesis state -func DefaultGenesisState() GenesisState { - return NewGenesisState(true) -} +func DefaultGenesisState() GenesisState { return NewGenesisState(true) } // InitGenesis sets distribution information for genesis. func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { @@ -33,6 +29,4 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { // ValidateGenesis performs basic validation of bank genesis data returning an // error for any failed validation criteria. -func ValidateGenesis(data GenesisState) error { - return nil -} +func ValidateGenesis(data GenesisState) error { return nil } diff --git a/x/bank/keeper.go b/x/bank/keeper.go index c6c7c2fc2699..38d262fb132a 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank/tags" @@ -34,25 +33,19 @@ type Keeper interface { type BaseKeeper struct { BaseSendKeeper - cdc *codec.Codec - storeKey sdk.StoreKey ak auth.AccountKeeper paramSpace params.Subspace } // NewBaseKeeper returns a new BaseKeeper func NewBaseKeeper( - cdc *codec.Codec, - key sdk.StoreKey, ak auth.AccountKeeper, paramSpace params.Subspace, codespace sdk.CodespaceType) BaseKeeper { ps := paramSpace.WithKeyTable(ParamKeyTable()) return BaseKeeper{ - BaseSendKeeper: NewBaseSendKeeper(cdc, key, ak, ps, codespace), - cdc: cdc, - storeKey: key, + BaseSendKeeper: NewBaseSendKeeper(ak, ps, codespace), ak: ak, paramSpace: ps, } @@ -152,25 +145,20 @@ var _ SendKeeper = (*BaseSendKeeper)(nil) // creating coins. It implements the SendKeeper interface. type BaseSendKeeper struct { BaseViewKeeper - cdc *codec.Codec - storeKey sdk.StoreKey + ak auth.AccountKeeper paramSpace params.Subspace } // NewBaseSendKeeper returns a new BaseSendKeeper. func NewBaseSendKeeper( - cdc *codec.Codec, - key sdk.StoreKey, ak auth.AccountKeeper, paramSpace params.Subspace, codespace sdk.CodespaceType, ) BaseSendKeeper { return BaseSendKeeper{ - BaseViewKeeper: NewBaseViewKeeper(cdc, key, ak, codespace), - cdc: cdc, - storeKey: key, + BaseViewKeeper: NewBaseViewKeeper(ak, codespace), ak: ak, paramSpace: paramSpace, } @@ -216,22 +204,16 @@ type ViewKeeper interface { // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { - cdc *codec.Codec - storeKey sdk.StoreKey ak auth.AccountKeeper codespace sdk.CodespaceType } // NewBaseViewKeeper returns a new BaseViewKeeper. func NewBaseViewKeeper( - cdc *codec.Codec, - key sdk.StoreKey, ak auth.AccountKeeper, codespace sdk.CodespaceType, ) BaseViewKeeper { return BaseViewKeeper{ - cdc: cdc, - storeKey: key, ak: ak, codespace: codespace, } diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index fc206940d374..f9be27907e99 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -33,7 +33,6 @@ func setupTestInput() testInput { authCapKey := sdk.NewKVStoreKey("authCapKey") fckCapKey := sdk.NewKVStoreKey("fckCapKey") - keySupply := sdk.NewKVStoreKey("bank") keyParams := sdk.NewKVStoreKey("params") tkeyParams := sdk.NewTransientStoreKey("transient_params") @@ -52,13 +51,13 @@ func setupTestInput() testInput { ak.SetParams(ctx, auth.DefaultParams()) - return testInput{cdc: cdc, key: keySupply, ctx: ctx, ak: ak, pk: pk} + return testInput{ctx: ctx, ak: ak, pk: pk} } func TestKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx - bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr := sdk.AccAddress([]byte("addr1")) @@ -139,8 +138,8 @@ func TestSendKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx paramSpace := input.pk.Subspace(DefaultParamspace) - bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, paramSpace, DefaultCodespace) - sendKeeper := NewBaseSendKeeper(input.cdc, input.key, input.ak, paramSpace, DefaultCodespace) + bankKeeper := NewBaseKeeper(input.ak, paramSpace, DefaultCodespace) + sendKeeper := NewBaseSendKeeper(input.ak, paramSpace, DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr := sdk.AccAddress([]byte("addr1")) @@ -188,9 +187,9 @@ func TestViewKeeper(t *testing.T) { input := setupTestInput() ctx := input.ctx paramSpace := input.pk.Subspace(DefaultParamspace) - bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, paramSpace, DefaultCodespace) + bankKeeper := NewBaseKeeper(input.ak, paramSpace, DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) - viewKeeper := NewBaseViewKeeper(input.cdc, input.key, input.ak, DefaultCodespace) + viewKeeper := NewBaseViewKeeper(input.ak, DefaultCodespace) addr := sdk.AccAddress([]byte("addr1")) acc := input.ak.NewAccountWithAddress(ctx, addr) @@ -217,7 +216,7 @@ func TestVestingAccountSend(t *testing.T) { origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) @@ -251,7 +250,7 @@ func TestVestingAccountReceive(t *testing.T) { origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) sendCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) @@ -285,7 +284,7 @@ func TestDelegateCoins(t *testing.T) { origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) @@ -322,7 +321,7 @@ func TestUndelegateCoins(t *testing.T) { origCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) delCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 50)) - bankKeeper := NewBaseKeeper(input.cdc, input.key, input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) + bankKeeper := NewBaseKeeper(input.ak, input.pk.Subspace(DefaultParamspace), DefaultCodespace) bankKeeper.SetSendEnabled(ctx, true) addr1 := sdk.AccAddress([]byte("addr1")) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 4b89e874c261..c21d6a8d2c6a 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -92,7 +92,6 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, keyStaking := sdk.NewKVStoreKey(staking.StoreKey) tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) - keySupply := sdk.NewKVStoreKey(bank.StoreKey) keyFeeCollection := sdk.NewKVStoreKey(auth.FeeStoreKey) keyParams := sdk.NewKVStoreKey(params.StoreKey) tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) @@ -116,7 +115,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(cdc, keySupply, accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, bankKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) sk.SetPool(ctx, staking.InitialPool()) sk.SetParams(ctx, staking.DefaultParams()) diff --git a/x/gov/expected_keepers.go b/x/gov/expected_keepers.go index fd9ae395cfc3..3235c2524c40 100644 --- a/x/gov/expected_keepers.go +++ b/x/gov/expected_keepers.go @@ -2,15 +2,18 @@ package gov import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/supply" ) -// expected bank keeper +// BankKeeper defines the expected bank keeper type BankKeeper interface { GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins AddCoins(tx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) +} - AddTokenHolder(ctx sdk.Context, moduleName string) (bank.TokenHolder, sdk.Error) +// SupplyKeeper defines the expected supply keeper +type SupplyKeeper interface { + AddTokenHolder(ctx sdk.Context, moduleName string) (supply.TokenHolder, sdk.Error) RequestTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) sdk.Error RelinquishTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) sdk.Error } diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 12b31f991ff6..3d4343553e53 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -5,7 +5,6 @@ import ( codec "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/params" "github.com/tendermint/tendermint/crypto" @@ -56,11 +55,11 @@ type Keeper struct { // The reference to the Paramstore to get and set gov specific params paramSpace params.Subspace - // The reference to the CoinKeeper to modify balances + // The reference to the BankKeeper to modify balances ck BankKeeper - // The reference to the TokenHolder to hold the deposit and burn amounts - th bank.TokenHolder + // The reference to the SupplyKeeper to hold deposits + sk SupplyKeeper // The ValidatorSet to get information about validators vs sdk.ValidatorSet @@ -86,12 +85,13 @@ type Keeper struct { // CONTRACT: Token Holder needs to be added into the bank keeper before calling // this function func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, - paramSpace params.Subspace, ck BankKeeper, tokenHolder bank.TokenHolder, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { + paramSpace params.Subspace, bk BankKeeper, sk SupplyKeeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { return Keeper{ storeKey: key, paramsKeeper: paramsKeeper, paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), - ck: ck, + ck: bk, + sk: sk, ds: ds, vs: ds.GetValidatorSet(), cdc: cdc, @@ -386,7 +386,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd } // request coins for the governance token holder - err := keeper.ck.RequestTokens(ctx, keeper.th.GetModuleName(), depositAmount) + err := keeper.sk.RequestTokens(ctx, ModuleName, depositAmount) if err != nil { return err, false } @@ -430,14 +430,14 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { deposit := &Deposit{} keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) - err := keeper.ck.RelinquishTokens(ctx, ModuleName, deposit.Amount) + err := keeper.sk.RelinquishTokens(ctx, ModuleName, deposit.Amount) if err != nil { - panic(err.Error()) + panic(err) } _, err = keeper.ck.AddCoins(ctx, deposit.Depositor, deposit.Amount) if err != nil { - panic(err.Error()) + panic(err) } store.Delete(depositsIterator.Key()) @@ -454,9 +454,9 @@ func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) // Burn deposits; TODO: consider sending to community pool - err := keeper.ck.RelinquishTokens(ctx, ModuleName, deposit.Amount) + err := keeper.sk.RelinquishTokens(ctx, ModuleName, deposit.Amount) if err != nil { - panic(err.Error()) + panic(err) } store.Delete(depositsIterator.Key()) diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 054eb68a4bb6..c8fcba18fd96 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -16,11 +16,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/supply" ) // initialize the mock application for this module func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []auth.Account) ( - mapp *mock.App, keeper Keeper, sk staking.Keeper, addrs []sdk.AccAddress, + mapp *mock.App, keeper Keeper, ds staking.Keeper, addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) { mapp = mock.NewApp() @@ -30,19 +31,20 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a keyStaking := sdk.NewKVStoreKey(staking.StoreKey) tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) - keySupply := sdk.NewKVStoreKey(bank.StoreKey) + keySupply := sdk.NewKVStoreKey(supply.StoreKey) keyGov := sdk.NewKVStoreKey(StoreKey) pk := mapp.ParamsKeeper - ck := bank.NewBaseKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) - sk = staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, ck, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) - keeper = NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, DefaultCodespace) + ck := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + sk := supply.NewKeeper(mapp.Cdc, keySupply) + ds = staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, ck, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) + keeper = NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, ds, DefaultCodespace) mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) mapp.QueryRouter().AddRoute(QuerierRoute, NewQuerier(keeper)) mapp.SetEndBlocker(getEndBlocker(keeper)) - mapp.SetInitChainer(getInitChainer(mapp, keeper, sk, genState)) + mapp.SetInitChainer(getInitChainer(mapp, keeper, ds, genState)) require.NoError(t, mapp.CompleteSetup(keyStaking, tkeyStaking, keyGov)) @@ -54,7 +56,7 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a mock.SetGenesis(mapp, genAccs) - return mapp, keeper, sk, addrs, pubKeys, privKeys + return mapp, keeper, ds, addrs, pubKeys, privKeys } // gov and staking endblocker diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go index 403350dac577..ca51ae9d8b6f 100644 --- a/x/ibc/app_test.go +++ b/x/ibc/app_test.go @@ -20,9 +20,8 @@ func getMockApp(t *testing.T) *mock.App { RegisterCodec(mapp.Cdc) keyIBC := sdk.NewKVStoreKey("ibc") - keySupply := sdk.NewKVStoreKey(bank.StoreKey) ibcMapper := NewMapper(mapp.Cdc, keyIBC, DefaultCodespace) - bankKeeper := bank.NewBaseKeeper(map.Cdc, keySupply, mapp.AccountKeeper, + bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) mapp.Router().AddRoute("ibc", NewHandler(ibcMapper, bankKeeper)) diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index d7d00ed05a0c..286da66fd9c1 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -34,7 +34,6 @@ func setupTestInput() testInput { ibcKey := sdk.NewKVStoreKey("ibcCapKey") authCapKey := sdk.NewKVStoreKey("authCapKey") - keySupply := sdk.NewKVStoreKey(bank.StoreKey) fckCapKey := sdk.NewKVStoreKey("fckCapKey") keyParams := sdk.NewKVStoreKey("params") tkeyParams := sdk.NewTransientStoreKey("transient_params") @@ -51,7 +50,7 @@ func setupTestInput() testInput { ak := auth.NewAccountKeeper( cdc, authCapKey, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount, ) - bk := bank.NewBaseKeeper(cdc, keySupply, ak, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + bk := bank.NewBaseKeeper(ak, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) ctx := sdk.NewContext(ms, abci.Header{ChainID: "test-chain-id"}, false, log.NewNopLogger()) ak.SetParams(ctx, auth.DefaultParams()) diff --git a/x/mint/abci_app.go b/x/mint/abci_app.go index 837069892e1c..0b47881400ee 100644 --- a/x/mint/abci_app.go +++ b/x/mint/abci_app.go @@ -20,6 +20,6 @@ func BeginBlocker(ctx sdk.Context, k Keeper) { // mint coins, add to collected fees, update supply mintedCoin := minter.BlockProvision(params) k.fck.AddCollectedFees(ctx, sdk.Coins{mintedCoin}) - k.bk.InflateSupply(ctx, sdk.Coins{mintedCoin}) + k.supplyKeeper.InflateSupply(ctx, sdk.Coins{mintedCoin}) k.sk.InflateNotBondedTokenSupply(ctx, mintedCoin.Amount) // TODO: verify invariance with bank bond denom supply } diff --git a/x/mint/expected_keepers.go b/x/mint/expected_keepers.go index 4298f7dee7a5..30e95dfcc030 100644 --- a/x/mint/expected_keepers.go +++ b/x/mint/expected_keepers.go @@ -2,12 +2,12 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/supply" ) -// BankKeeper defines the expected bank keeper -type BankKeeper interface { - GetSupplier(ctx sdk.Context) bank.Supplier +// SupplyKeeper defines the expected supply keeper +type SupplyKeeper interface { + GetSupplier(ctx sdk.Context) supply.Supplier InflateSupply(ctx sdk.Context, amt sdk.Coins) } diff --git a/x/mint/keeper.go b/x/mint/keeper.go index b0e61ed9187e..5a9fa2857772 100644 --- a/x/mint/keeper.go +++ b/x/mint/keeper.go @@ -20,26 +20,27 @@ const ( QuerierRoute = StoreKey ) -// keeper of the staking store +// Keeper defines the keeper of the minting store type Keeper struct { - storeKey sdk.StoreKey - cdc *codec.Codec - paramSpace params.Subspace - bk BankKeeper - sk StakingKeeper - fck FeeCollectionKeeper + storeKey sdk.StoreKey + cdc *codec.Codec + paramSpace params.Subspace + supplyKeeper SupplyKeeper + sk StakingKeeper + fck FeeCollectionKeeper } +// NewKeeper creates a new mint Keeper instance func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, - paramSpace params.Subspace, bk BankKeeper, sk StakingKeeper, fck FeeCollectionKeeper) Keeper { + paramSpace params.Subspace, supplyKeeper SupplyKeeper, sk StakingKeeper, fck FeeCollectionKeeper) Keeper { keeper := Keeper{ - storeKey: key, - cdc: cdc, - paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), - bk: bk, - sk: sk, - fck: fck, + storeKey: key, + cdc: cdc, + paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), + supplyKeeper: supplyKeeper, + sk: sk, + fck: fck, } return keeper } @@ -54,7 +55,7 @@ var ( ParamStoreKeyParams = []byte("params") ) -// ParamTable for staking module +// ParamKeyTable for minting module func ParamKeyTable() params.KeyTable { return params.NewKeyTable( ParamStoreKeyParams, Params{}, diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index e1acf9495699..9b5c442f1201 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -117,8 +117,6 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context ) ck := bank.NewBaseKeeper( - cdc, - sdk.NewKVStoreKey(bank.StoreKey), accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, diff --git a/x/supply/alias.go b/x/supply/alias.go new file mode 100644 index 000000000000..038c5ceb3473 --- /dev/null +++ b/x/supply/alias.go @@ -0,0 +1,37 @@ +package supply + +import ( + "github.com/cosmos/cosmos-sdk/x/supply/keeper" + "github.com/cosmos/cosmos-sdk/x/supply/types" +) + +// nolint +type ( + Keeper = keeper.Keeper + Supplier = types.Supplier + TokenHolder = types.TokenHolder +) + +// nolint +var ( + NewKeeper = keeper.NewKeeper + + GetTokenHolderKey = keeper.GetTokenHolderKey + GetSupplier = keeper.GetSupplier + SetSupplier = keeper.SetSupplier + InflateSupply = keeper.InflateSupply + GetTokenHolders = keeper.GetTokenHolders + GetTokenHolder = keeper.GetTokenHolder + AddTokenHolder = keeper.AddTokenHolder + GetTokenHolder = keeper.GetTokenHolder + AddTokenHolder = keeper.AddTokenHolder + SetTokenHolder = keeper.SetTokenHolder + RequestTokens = keeper.RequestTokens + RelinquishTokens = keeper.RelinquishTokens +) + +// nolint +const ( + StoreKey = keeper.StoreKey + QuerierRoute = keeper.QuerierRoute +) diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 13845d3fb89b..6a1e9b31f52b 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/supply/types" ) -// Keeper defines the k of the supply store +// Keeper defines the keeper of the supply store type Keeper struct { cdc *codec.Codec storeKey sdk.StoreKey From 575e484120c7fc72e1ad592f77a7de6b8f401925 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 16 Apr 2019 16:51:34 +0200 Subject: [PATCH 15/46] errors and more cleanup --- cmd/gaia/app/genesis.go | 2 +- x/bank/keeper.go | 10 ++-------- x/supply/genesis.go | 11 +++++++++-- x/supply/types/supplier.go | 16 ++++++++++++---- x/supply/types/token_holder.go | 15 ++++++++++++++- 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index b285cbc5efde..9dbb9009d397 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -43,7 +43,7 @@ type GenesisState struct { GovData gov.GenesisState `json:"gov"` CrisisData crisis.GenesisState `json:"crisis"` SlashingData slashing.GenesisState `json:"slashing"` - SupplyData supply.GenesisState `json:"slashing"` + SupplyData supply.GenesisState `json:"supply"` GenTxs []json.RawMessage `json:"gentxs"` } diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 38d262fb132a..a500d1841505 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -209,14 +209,8 @@ type BaseViewKeeper struct { } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper( - ak auth.AccountKeeper, - codespace sdk.CodespaceType, -) BaseViewKeeper { - return BaseViewKeeper{ - ak: ak, - codespace: codespace, - } +func NewBaseViewKeeper(ak auth.AccountKeeper, codespace sdk.CodespaceType) BaseViewKeeper { + return BaseViewKeeper{ak: ak, codespace: codespace} } // GetCoins returns the coins at the addr. diff --git a/x/supply/genesis.go b/x/supply/genesis.go index 5cca26d2dd16..2ab210a7a108 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -47,6 +47,13 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) GenesisState { // ValidateGenesis performs basic validation of bank genesis data returning an // error for any failed validation criteria. func ValidateGenesis(data GenesisState) error { - err := data.Supplier.ValidateBasic().Error() - return fmt.Errorf(err) + if err := data.Supplier.ValidateBasic(); err != nil { + return fmt.Errorf(err.Error()) + } + for _, holder := range data.ModulesHoldings { + if err := holder.ValidateBasic(); err != nil { + return fmt.Errorf(err.Error()) + } + } + } diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 5f23134ce4e0..168a72a99198 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -52,16 +52,24 @@ func (supplier Supplier) TotalAmountOf(denom string) sdk.Int { // ValidateBasic validates the Supply coins and returns error if invalid func (supplier Supplier) ValidateBasic() sdk.Error { if !supplier.CirculatingSupply.IsValid() { - return sdk.ErrInvalidCoins(supplier.CirculatingSupply.String()) + return sdk.ErrInvalidCoins( + fmt.Sprintf("invalid circulating supply: %s", supplier.CirculatingSupply.String()), + ) } if !supplier.VestingSupply.IsValid() { - return sdk.ErrInvalidCoins(supplier.VestingSupply.String()) + return sdk.ErrInvalidCoins( + fmt.Sprintf("invalid vesting supply: %s", supplier.VestingSupply.String()), + ) } if !supplier.HoldersSupply.IsValid() { - return sdk.ErrInvalidCoins(supplier.HoldersSupply.String()) + return sdk.ErrInvalidCoins( + fmt.Sprintf("invalid token holders supply: %s", supplier.HoldersSupply.String()), + ) } if !supplier.TotalSupply.IsValid() { - return sdk.ErrInvalidCoins(supplier.TotalSupply.String()) + return sdk.ErrInvalidCoins( + fmt.Sprintf("invalid total supply: %s", supplier.TotalSupply.String()), + ) } return nil } diff --git a/x/supply/types/token_holder.go b/x/supply/types/token_holder.go index 60fef2b101aa..864ef324a862 100644 --- a/x/supply/types/token_holder.go +++ b/x/supply/types/token_holder.go @@ -1,6 +1,8 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -15,8 +17,9 @@ type TokenHolder interface { GetHoldings() sdk.Coins SetHoldings(sdk.Coins) - GetHoldingsOf(string) sdk.Int + + ValidateBasic() sdk.Error } //----------------------------------------------------------------------------- @@ -57,3 +60,13 @@ func (bth *BaseTokenHolder) SetHoldings(amount sdk.Coins) { func (bth BaseTokenHolder) GetHoldingsOf(denom string) sdk.Int { return bth.Holdings.AmountOf(denom) } + +// ValidateBasic validates the held coins from a token holder +func (bth BaseTokenHolder) ValidateBasic() sdk.Error { + if !bth.Holdings.IsValid() { + return sdk.ErrInvalidCoins( + fmt.Sprintf("invalid token holder %s coins: %s", bth.Module, bth.Holdings.String()), + ) + } + return nil +} From 053bb86b7f792df12538a29b9677ce329ff13b11 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 16 Apr 2019 17:23:40 +0200 Subject: [PATCH 16/46] genesis stuff --- cmd/gaia/app/app.go | 15 +++++++++------ cmd/gaia/app/app_test.go | 2 ++ cmd/gaia/app/export.go | 1 + x/bank/keeper_test.go | 3 +-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 38a7008e4f36..b366b8f01cd9 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -64,6 +64,7 @@ type GaiaApp struct { bankKeeper bank.Keeper stakingKeeper staking.Keeper slashingKeeper slashing.Keeper + supplyKeeper supply.Keeper mintKeeper mint.Keeper distrKeeper distr.Keeper govKeeper gov.Keeper @@ -114,11 +115,10 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, ) - // app.supplyKeeper = supply.NewKeeper( - // app.accountKeeper, - // app.paramsKeeper.Subspace(bank.DefaultParamspace), - // bank.DefaultCodespace, - // ) + app.supplyKeeper = supply.NewKeeper( + app.cdc, + app.keySupply, + ) app.feeCollectionKeeper = auth.NewFeeCollectionKeeper( app.cdc, app.keyFeeCollection, @@ -146,6 +146,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, &stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), slashing.DefaultCodespace, ) + // TODO: add holder account for gov module app.govKeeper = gov.NewKeeper( app.cdc, app.keyGov, @@ -171,7 +172,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, distr.RegisterInvariants(&app.crisisKeeper, app.distrKeeper, app.stakingKeeper) staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper) - // register message routes + // register transaction messages routes app.Router(). AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)). AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)). @@ -180,6 +181,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper)). AddRoute(crisis.RouterKey, crisis.NewHandler(app.crisisKeeper)) + // register query routes app.QueryRouter(). AddRoute(auth.QuerierRoute, auth.NewQuerier(app.accountKeeper)). AddRoute(distr.QuerierRoute, distr.NewQuerier(app.distrKeeper)). @@ -287,6 +289,7 @@ func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisSt gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData) crisis.InitGenesis(ctx, app.crisisKeeper, genesisState.CrisisData) mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData) + supply.InitGenesis(ctx, app.supplyKeeper, genesisState.SupplyData) // validate genesis state if err := GaiaValidateGenesisState(genesisState); err != nil { diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index ec38f06a671b..d6a3c2525f90 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -18,6 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/supply" abci "github.com/tendermint/tendermint/abci/types" ) @@ -38,6 +39,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error { gov.DefaultGenesisState(), crisis.DefaultGenesisState(), slashing.DefaultGenesisState(), + supply.DefaultGenesisState(), ) stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState) diff --git a/cmd/gaia/app/export.go b/cmd/gaia/app/export.go index 5174c1498a92..5902265cf1fa 100644 --- a/cmd/gaia/app/export.go +++ b/cmd/gaia/app/export.go @@ -49,6 +49,7 @@ func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteLis gov.ExportGenesis(ctx, app.govKeeper), crisis.ExportGenesis(ctx, app.crisisKeeper), slashing.ExportGenesis(ctx, app.slashingKeeper), + supply.ExportGenesis(ctx, app.supplyKeeper), ) appState, err = codec.MarshalJSONIndent(app.cdc, genState) if err != nil { diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index f9be27907e99..28db4a3dcc52 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -20,7 +20,6 @@ import ( type testInput struct { cdc *codec.Codec ctx sdk.Context - key sdk.StoreKey ak auth.AccountKeeper pk params.Keeper } @@ -51,7 +50,7 @@ func setupTestInput() testInput { ak.SetParams(ctx, auth.DefaultParams()) - return testInput{ctx: ctx, ak: ak, pk: pk} + return testInput{cdc: cdc, ctx: ctx, ak: ak, pk: pk} } func TestKeeper(t *testing.T) { From b62f9b24698798d8737b2fa9268855987f5be32f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 16 Apr 2019 17:46:01 +0200 Subject: [PATCH 17/46] fixes; now it builds --- cmd/gaia/app/app.go | 4 ++-- cmd/gaia/app/export.go | 1 + types/staking.go | 1 - x/gov/genesis.go | 2 +- x/mint/test_common.go | 6 +++++- x/supply/alias.go | 14 +------------- x/supply/genesis.go | 2 +- x/supply/keeper/keeper.go | 8 +++++--- x/supply/types/errors.go | 11 ++++++++++- 9 files changed, 26 insertions(+), 23 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index b366b8f01cd9..75c47c51a708 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -146,11 +146,11 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, &stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), slashing.DefaultCodespace, ) - // TODO: add holder account for gov module app.govKeeper = gov.NewKeeper( app.cdc, app.keyGov, - app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakingKeeper, + app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), + app.bankKeeper, app.supplyKeeper, &stakingKeeper, gov.DefaultCodespace, ) app.crisisKeeper = crisis.NewKeeper( diff --git a/cmd/gaia/app/export.go b/cmd/gaia/app/export.go index 5902265cf1fa..63da3152e836 100644 --- a/cmd/gaia/app/export.go +++ b/cmd/gaia/app/export.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/supply" ) // export the state of gaia for a genesis file diff --git a/types/staking.go b/types/staking.go index fadf57f91355..303a3a7275f1 100644 --- a/types/staking.go +++ b/types/staking.go @@ -104,7 +104,6 @@ type ValidatorSet interface { Validator(Context, ValAddress) Validator // get a particular validator by operator address ValidatorByConsAddr(Context, ConsAddress) Validator // get a particular validator by consensus address TotalBondedTokens(Context) Int // total bonded tokens within the validator set - TotalTokens(Context) Int // total token supply // slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction Slash(Context, ConsAddress, int64, int64, Dec) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 4ba9c4388d4e..e089b1382e7a 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -108,7 +108,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { panic(err) } - _, err = k.ck.AddTokenHolder(ctx, ModuleName) + _, err = k.sk.AddTokenHolder(ctx, ModuleName) if err != nil { panic(err) } diff --git a/x/mint/test_common.go b/x/mint/test_common.go index f2bec9515704..edd561d97d04 100644 --- a/x/mint/test_common.go +++ b/x/mint/test_common.go @@ -19,6 +19,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/supply" ) type testInput struct { @@ -43,6 +44,7 @@ func newTestInput(t *testing.T) testInput { keyParams := sdk.NewKVStoreKey(params.StoreKey) tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) keyFeeCollection := sdk.NewKVStoreKey(auth.FeeStoreKey) + keySupply := sdk.NewKVStoreKey(supply.StoreKey) keyMint := sdk.NewKVStoreKey(StoreKey) ms := store.NewCommitMultiStore(db) @@ -63,8 +65,10 @@ func newTestInput(t *testing.T) testInput { stakingKeeper := staking.NewKeeper( cdc, keyStaking, tkeyStaking, bankKeeper, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace, ) + supplyKeeper := supply.NewKeeper(cdc, keySupply) + mintKeeper := NewKeeper( - cdc, keyMint, paramsKeeper.Subspace(DefaultParamspace), &stakingKeeper, feeCollectionKeeper, + cdc, keyMint, paramsKeeper.Subspace(DefaultParamspace), supplyKeeper, &stakingKeeper, feeCollectionKeeper, ) ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout)) diff --git a/x/supply/alias.go b/x/supply/alias.go index 038c5ceb3473..e2e2fdec99e1 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -14,20 +14,8 @@ type ( // nolint var ( - NewKeeper = keeper.NewKeeper - + NewKeeper = keeper.NewKeeper GetTokenHolderKey = keeper.GetTokenHolderKey - GetSupplier = keeper.GetSupplier - SetSupplier = keeper.SetSupplier - InflateSupply = keeper.InflateSupply - GetTokenHolders = keeper.GetTokenHolders - GetTokenHolder = keeper.GetTokenHolder - AddTokenHolder = keeper.AddTokenHolder - GetTokenHolder = keeper.GetTokenHolder - AddTokenHolder = keeper.AddTokenHolder - SetTokenHolder = keeper.SetTokenHolder - RequestTokens = keeper.RequestTokens - RelinquishTokens = keeper.RelinquishTokens ) // nolint diff --git a/x/supply/genesis.go b/x/supply/genesis.go index 2ab210a7a108..a8b969b0f1e0 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -55,5 +55,5 @@ func ValidateGenesis(data GenesisState) error { return fmt.Errorf(err.Error()) } } - + return nil } diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 6a1e9b31f52b..1ac39f71f31e 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -80,10 +80,12 @@ func (k Keeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( // AddTokenHolder creates and sets a token holder instance to store func (k Keeper) AddTokenHolder(ctx sdk.Context, moduleName string) ( - tokenHolder types.TokenHolder, err error) { + tokenHolder types.TokenHolder, err sdk.Error) { store := ctx.KVStore(k.storeKey) if store.Has(GetTokenHolderKey(moduleName)) { - err = fmt.Errorf("token holder with module %s already exist", moduleName) + err = types.ErrInvalidTokenHolder(types.DefaultCodespace, + fmt.Sprintf("token holder with module %s already exist", moduleName), + ) return } @@ -130,7 +132,7 @@ func (k Keeper) RequestTokens( // RelinquishTokens hands over a portion of the module's holdings func (k Keeper) RelinquishTokens( ctx sdk.Context, moduleName string, amount sdk.Coins, -) error { +) sdk.Error { if !amount.IsValid() { return sdk.ErrInvalidCoins("invalid provided relenquished amount") } diff --git a/x/supply/types/errors.go b/x/supply/types/errors.go index df8e9c3bee3f..256fd9496e44 100644 --- a/x/supply/types/errors.go +++ b/x/supply/types/errors.go @@ -11,9 +11,18 @@ type CodeType = sdk.CodeType const ( DefaultCodespace sdk.CodespaceType = "supply" - CodeUnknownTokenHolder CodeType = 550 + CodeInvalidTokenHolder CodeType = 550 + CodeUnknownTokenHolder CodeType = 551 ) +// ErrInvalidTokenHolder is an error +func ErrInvalidTokenHolder(codespace sdk.CodespaceType, msg string) sdk.Error { + if msg != "" { + return sdk.NewError(codespace, CodeInvalidTokenHolder, msg) + } + return sdk.NewError(codespace, CodeInvalidTokenHolder, "invalid token holder") +} + // ErrUnknownTokenHolder is an error func ErrUnknownTokenHolder(codespace sdk.CodespaceType, msg string) sdk.Error { if msg != "" { From 4e0d389691fb1da52372b3fa6fd878fcbdc75fbe Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 16 Apr 2019 19:34:35 +0200 Subject: [PATCH 18/46] fix total supply --- x/gov/endblocker_test.go | 4 --- x/supply/keeper/keeper.go | 9 +++++ x/supply/keeper/keeper_test.go | 63 ++++++++++++++++++++++++++++++++++ x/supply/types/codec.go | 2 +- x/supply/types/supplier.go | 38 ++++++++++++++++++++ 5 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 x/supply/keeper/keeper_test.go diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 86e9a4ef2f7e..c1c6d866adbb 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -18,7 +18,6 @@ func TestTickExpiredDepositPeriod(t *testing.T) { mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) ctx := mapp.BaseApp.NewContext(false, abci.Header{}) - keeper.ck.SetSendEnabled(ctx, true) govHandler := NewHandler(keeper) inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) @@ -64,7 +63,6 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) ctx := mapp.BaseApp.NewContext(false, abci.Header{}) - keeper.ck.SetSendEnabled(ctx, true) govHandler := NewHandler(keeper) inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) @@ -124,7 +122,6 @@ func TestTickPassedDepositPeriod(t *testing.T) { mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) ctx := mapp.BaseApp.NewContext(false, abci.Header{}) - keeper.ck.SetSendEnabled(ctx, true) govHandler := NewHandler(keeper) inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) @@ -170,7 +167,6 @@ func TestTickPassedVotingPeriod(t *testing.T) { mapp.BeginBlock(abci.RequestBeginBlock{Header: header}) ctx := mapp.BaseApp.NewContext(false, abci.Header{}) - keeper.ck.SetSendEnabled(ctx, true) govHandler := NewHandler(keeper) inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 1ac39f71f31e..1d21e13b9fad 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -44,6 +44,7 @@ func (k Keeper) SetSupplier(ctx sdk.Context, supplier types.Supplier) { func (k Keeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { supplier := k.GetSupplier(ctx) supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) + supplier.TotalSupply = supplier.TotalSupply.Add(amount) k.SetSupplier(ctx, supplier) } @@ -121,6 +122,7 @@ func (k Keeper) RequestTokens( // update global supply held by token holders supplier := k.GetSupplier(ctx) supplier.HoldersSupply = supplier.HoldersSupply.Add(amount) + supplier.TotalSupply = supplier.TotalSupply.Add(amount) holder.SetHoldings(holder.GetHoldings().Add(amount)) @@ -156,6 +158,13 @@ func (k Keeper) RelinquishTokens( if !ok { panic("total holders supply should be greater than relinquished amount") } + + newTotalSupply, ok := supplier.TotalSupply.SafeSub(amount) + if !ok { + panic("total holders supply should be greater than relinquished amount") + } + + supplier.TotalSupply = newTotalSupply supplier.HoldersSupply = newHoldersSupply holder.SetHoldings(newHoldings) diff --git a/x/supply/keeper/keeper_test.go b/x/supply/keeper/keeper_test.go new file mode 100644 index 000000000000..309abe516d21 --- /dev/null +++ b/x/supply/keeper/keeper_test.go @@ -0,0 +1,63 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/supply/types" +) + +func TestSupplier(t *testing.T) { + ctx, keeper := CreateTestInput(t, false) + oneUatom := sdk.NewCoins(sdk.NewCoin("uatom", sdk.OneInt())) + + require.Panics(t, func() { keeper.GetSupplier(ctx) }, "should panic when supplier is not set") + + expectedSupplier := types.DefaultSupplier() + expectedSupplier.TotalSupply = expectedSupplier.CirculatingSupply.Add(oneUatom) + + keeper.SetSupplier(ctx, expectedSupplier) + + expectedSupplier.CirculatingSupply = expectedSupplier.CirculatingSupply.Add(oneUatom) + + keeper.InflateSupply(ctx, oneUatom) + + supplier := keeper.GetSupplier(ctx) + require.Equal(t, expectedSupplier, supplier) +} + +func CreateTestInput(t *testing.T, isCheckTx bool) (sdk.Context, Keeper) { + + keySupply := sdk.NewKVStoreKey(StoreKey) + + db := dbm.NewMemDB() + ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) + err := ms.LoadLatestVersion() + require.Nil(t, err) + + ctx := sdk.NewContext(ms, abci.Header{ChainID: "supplyChain"}, isCheckTx, log.NewNopLogger()) + ctx = ctx.WithConsensusParams( + &abci.ConsensusParams{ + Validator: &abci.ValidatorParams{ + PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}, + }, + }, + ) + + cdc := codec.New() + types.RegisterCodec(cdc) + + keeper := NewKeeper(cdc, keySupply) + + return ctx, keeper +} diff --git a/x/supply/types/codec.go b/x/supply/types/codec.go index 9f32934c34b2..ab27c39890dc 100644 --- a/x/supply/types/codec.go +++ b/x/supply/types/codec.go @@ -7,7 +7,7 @@ import ( // RegisterCodec registers concrete types on codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*TokenHolder)(nil), nil) - cdc.RegisterConcrete(&BaseTokenHolder{}, "bank/BaseTokenHolder", nil) + cdc.RegisterConcrete(&BaseTokenHolder{}, "supply/BaseTokenHolder", nil) } var msgCdc = codec.New() diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 168a72a99198..574e9888e1e2 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -6,6 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// define consts for inflatoin +const ( + InflateCirculating = "circulating" + InflateVesting = "vesting" + InflateHolders = "holders" +) + // Supplier represents the keeps track of the total supply amounts in the network type Supplier struct { CirculatingSupply sdk.Coins `json:"circulating_supply"` // supply held by accounts that's not vesting @@ -29,6 +36,25 @@ func DefaultSupplier() Supplier { return NewSupplier(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) } +// Inflate returns the circulating supply of a coin denomination +func (supplier *Supplier) Inflate(inflationType string, amt sdk.Coins) error { + switch inflationType { + case InflateCirculating: + supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amt) + break + case InflateHolders: + supplier.HoldersSupply = supplier.HoldersSupply.Add(amt) + break + case InflateVesting: + supplier.VestingSupply = supplier.VestingSupply.Add(amt) + break + default: + return fmt.Errorf("invalid type %s", inflationType) + } + supplier.TotalSupply = supplier.TotalSupply.Add(amt) + return nil +} + // CirculatingAmountOf returns the circulating supply of a coin denomination func (supplier Supplier) CirculatingAmountOf(denom string) sdk.Int { return supplier.CirculatingSupply.AmountOf(denom) @@ -71,6 +97,18 @@ func (supplier Supplier) ValidateBasic() sdk.Error { fmt.Sprintf("invalid total supply: %s", supplier.TotalSupply.String()), ) } + + calculatedTotalSupply := + supplier.CirculatingSupply.Add(supplier.VestingSupply).Add(supplier.HoldersSupply) + + if !supplier.TotalSupply.IsEqual(calculatedTotalSupply) { + return sdk.ErrInvalidCoins( + fmt.Sprintf("total supply ≠ calculated total supply: %s ≠ %s", + supplier.TotalSupply.String(), calculatedTotalSupply, + ), + ) + } + return nil } From 390d0bf0cf71aaba2179dd3cb47f8c113c212129 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 18 Apr 2019 14:28:31 +0200 Subject: [PATCH 19/46] delete token holders --- x/supply/alias.go | 20 ++--- x/supply/genesis.go | 28 ++----- x/supply/keeper/keeper.go | 135 +-------------------------------- x/supply/keeper/keeper_test.go | 2 +- x/supply/keeper/key.go | 10 +-- x/supply/types/codec.go | 17 ----- x/supply/types/errors.go | 32 -------- x/supply/types/supplier.go | 102 +++++++++++++++++-------- x/supply/types/token_holder.go | 72 ------------------ 9 files changed, 93 insertions(+), 325 deletions(-) delete mode 100644 x/supply/types/codec.go delete mode 100644 x/supply/types/errors.go delete mode 100644 x/supply/types/token_holder.go diff --git a/x/supply/alias.go b/x/supply/alias.go index e2e2fdec99e1..699c01266b41 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -1,3 +1,4 @@ +// nolint package supply import ( @@ -5,21 +6,20 @@ import ( "github.com/cosmos/cosmos-sdk/x/supply/types" ) -// nolint type ( - Keeper = keeper.Keeper - Supplier = types.Supplier - TokenHolder = types.TokenHolder + Keeper = keeper.Keeper + Supplier = types.Supplier ) -// nolint var ( - NewKeeper = keeper.NewKeeper - GetTokenHolderKey = keeper.GetTokenHolderKey + NewKeeper = keeper.NewKeeper ) -// nolint const ( - StoreKey = keeper.StoreKey - QuerierRoute = keeper.QuerierRoute + StoreKey = keeper.StoreKey + // QuerierRoute = keeper.QuerierRoute + + TypeCirculating = types.TypeCirculating + TypeVesting = types.TypeVesting + TypeModules = types.TypeModules ) diff --git a/x/supply/genesis.go b/x/supply/genesis.go index a8b969b0f1e0..ed288cb73dd8 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -10,38 +10,27 @@ import ( // GenesisState is the supply state that must be provided at genesis. type GenesisState struct { - Supplier types.Supplier `json:"supplier"` - ModulesHoldings []types.TokenHolder `json:"modules_holdings"` + Supplier types.Supplier `json:"supplier"` } // NewGenesisState creates a new genesis state. -func NewGenesisState(supplier types.Supplier, holdings []types.TokenHolder, -) GenesisState { - return GenesisState{ - Supplier: supplier, - ModulesHoldings: holdings, - } +func NewGenesisState(supplier types.Supplier) GenesisState { + return GenesisState{Supplier: supplier} } // DefaultGenesisState returns a default genesis state func DefaultGenesisState() GenesisState { - return NewGenesisState(types.DefaultSupplier(), []types.TokenHolder{}) + return NewGenesisState(types.DefaultSupplier()) } -// InitGenesis sets distribution information for genesis. +// InitGenesis sets supply information for genesis. func InitGenesis(ctx sdk.Context, k keeper.Keeper, data GenesisState) { k.SetSupplier(ctx, data.Supplier) - for _, holder := range data.ModulesHoldings { - k.SetTokenHolder(ctx, holder) - } } // ExportGenesis returns a GenesisState for a given context and keeper. func ExportGenesis(ctx sdk.Context, k keeper.Keeper) GenesisState { - return NewGenesisState( - k.GetSupplier(ctx), - k.GetTokenHolders(ctx), - ) + return NewGenesisState(k.GetSupplier(ctx)) } // ValidateGenesis performs basic validation of bank genesis data returning an @@ -50,10 +39,5 @@ func ValidateGenesis(data GenesisState) error { if err := data.Supplier.ValidateBasic(); err != nil { return fmt.Errorf(err.Error()) } - for _, holder := range data.ModulesHoldings { - if err := holder.ValidateBasic(); err != nil { - return fmt.Errorf(err.Error()) - } - } return nil } diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 1d21e13b9fad..3b6aa4f290f8 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -1,8 +1,6 @@ package keeper import ( - "fmt" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/supply/types" @@ -15,7 +13,7 @@ type Keeper struct { } // NewKeeper creates a new supply Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ak AccountKeeper) Keeper { return Keeper{ cdc: cdc, storeKey: key, @@ -41,135 +39,8 @@ func (k Keeper) SetSupplier(ctx sdk.Context, supplier types.Supplier) { } // InflateSupply adds tokens to the circulating supply -func (k Keeper) InflateSupply(ctx sdk.Context, amount sdk.Coins) { - supplier := k.GetSupplier(ctx) - supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) - supplier.TotalSupply = supplier.TotalSupply.Add(amount) - k.SetSupplier(ctx, supplier) -} - -// GetTokenHolders returns all the token holders -func (k Keeper) GetTokenHolders(ctx sdk.Context) ( - tokenHolders []types.TokenHolder) { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, holderKeyPrefix) - defer iterator.Close() - - var tokenHolder types.TokenHolder - for ; iterator.Valid(); iterator.Next() { - err := k.cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenHolder) - if err != nil { - panic(err) - } - tokenHolders = append(tokenHolders, tokenHolder) - } - return -} - -// GetTokenHolder returns a token holder instance -func (k Keeper) GetTokenHolder(ctx sdk.Context, moduleName string) ( - tokenHolder types.TokenHolder, err error) { - store := ctx.KVStore(k.storeKey) - b := store.Get(GetTokenHolderKey(moduleName)) - if b == nil { - err = fmt.Errorf("token holder with module %s doesn't exist", moduleName) - return - } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, tokenHolder) - return -} - -// AddTokenHolder creates and sets a token holder instance to store -func (k Keeper) AddTokenHolder(ctx sdk.Context, moduleName string) ( - tokenHolder types.TokenHolder, err sdk.Error) { - store := ctx.KVStore(k.storeKey) - if store.Has(GetTokenHolderKey(moduleName)) { - err = types.ErrInvalidTokenHolder(types.DefaultCodespace, - fmt.Sprintf("token holder with module %s already exist", moduleName), - ) - return - } - - tokenHolder = types.NewBaseTokenHolder(moduleName, sdk.Coins{}) - k.SetTokenHolder(ctx, tokenHolder) - return -} - -// SetTokenHolder sets a holder to store -func (k Keeper) SetTokenHolder(ctx sdk.Context, tokenHolder types.TokenHolder) { - store := ctx.KVStore(k.storeKey) - holderKey := GetTokenHolderKey(tokenHolder.GetModuleName()) - b := k.cdc.MustMarshalBinaryLengthPrefixed(tokenHolder) - store.Set(holderKey, b) -} - -// RequestTokens adds requested tokens to the module's holdings -func (k Keeper) RequestTokens( - ctx sdk.Context, moduleName string, amount sdk.Coins, -) sdk.Error { - if !amount.IsValid() { - return sdk.ErrInvalidCoins("invalid requested amount") - } - - holder, err := k.GetTokenHolder(ctx, moduleName) - if err != nil { - return types.ErrUnknownTokenHolder( - types.DefaultCodespace, - fmt.Sprintf("token holder %s doesn't exist", moduleName), - ) - } - - // update global supply held by token holders - supplier := k.GetSupplier(ctx) - supplier.HoldersSupply = supplier.HoldersSupply.Add(amount) - supplier.TotalSupply = supplier.TotalSupply.Add(amount) - - holder.SetHoldings(holder.GetHoldings().Add(amount)) - - k.SetTokenHolder(ctx, holder) - k.SetSupplier(ctx, supplier) - return nil -} - -// RelinquishTokens hands over a portion of the module's holdings -func (k Keeper) RelinquishTokens( - ctx sdk.Context, moduleName string, amount sdk.Coins, -) sdk.Error { - if !amount.IsValid() { - return sdk.ErrInvalidCoins("invalid provided relenquished amount") - } - - holder, err := k.GetTokenHolder(ctx, moduleName) - if err != nil { - return types.ErrUnknownTokenHolder( - types.DefaultCodespace, - fmt.Sprintf("token holder %s doesn't exist", moduleName), - ) - } - - newHoldings, ok := holder.GetHoldings().SafeSub(amount) - if !ok { - return sdk.ErrInsufficientCoins("insufficient token holdings") - } - - // update global supply held by token holders +func (k Keeper) InflateSupply(ctx sdk.Context, inflationType string, amount sdk.Coins) { supplier := k.GetSupplier(ctx) - newHoldersSupply, ok := supplier.HoldersSupply.SafeSub(amount) - if !ok { - panic("total holders supply should be greater than relinquished amount") - } - - newTotalSupply, ok := supplier.TotalSupply.SafeSub(amount) - if !ok { - panic("total holders supply should be greater than relinquished amount") - } - - supplier.TotalSupply = newTotalSupply - supplier.HoldersSupply = newHoldersSupply - - holder.SetHoldings(newHoldings) - - k.SetTokenHolder(ctx, holder) + supplier.Inflate(inflationType, amount) k.SetSupplier(ctx, supplier) - return nil } diff --git a/x/supply/keeper/keeper_test.go b/x/supply/keeper/keeper_test.go index 309abe516d21..4cd3aff57ddd 100644 --- a/x/supply/keeper/keeper_test.go +++ b/x/supply/keeper/keeper_test.go @@ -45,7 +45,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool) (sdk.Context, Keeper) { err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "supplyChain"}, isCheckTx, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "supply-chain"}, isCheckTx, log.NewNopLogger()) ctx = ctx.WithConsensusParams( &abci.ConsensusParams{ Validator: &abci.ValidatorParams{ diff --git a/x/supply/keeper/key.go b/x/supply/keeper/key.go index 46f3a13dfc7b..b9cb25fac0fe 100644 --- a/x/supply/keeper/key.go +++ b/x/supply/keeper/key.go @@ -11,12 +11,4 @@ const ( QuerierRoute = StoreKey ) -var ( - supplierKey = []byte{0x00} - holderKeyPrefix = []byte{0x01} -) - -// GetTokenHolderKey returns the store key of the given module -func GetTokenHolderKey(moduleName string) []byte { - return append(holderKeyPrefix, []byte(moduleName)...) -} +var supplierKey = []byte{0x0} \ No newline at end of file diff --git a/x/supply/types/codec.go b/x/supply/types/codec.go deleted file mode 100644 index ab27c39890dc..000000000000 --- a/x/supply/types/codec.go +++ /dev/null @@ -1,17 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// RegisterCodec registers concrete types on codec -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterInterface((*TokenHolder)(nil), nil) - cdc.RegisterConcrete(&BaseTokenHolder{}, "supply/BaseTokenHolder", nil) -} - -var msgCdc = codec.New() - -func init() { - RegisterCodec(msgCdc) -} diff --git a/x/supply/types/errors.go b/x/supply/types/errors.go deleted file mode 100644 index 256fd9496e44..000000000000 --- a/x/supply/types/errors.go +++ /dev/null @@ -1,32 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// CodeType definition -type CodeType = sdk.CodeType - -// Supply errors reserve 550 - 599 -const ( - DefaultCodespace sdk.CodespaceType = "supply" - - CodeInvalidTokenHolder CodeType = 550 - CodeUnknownTokenHolder CodeType = 551 -) - -// ErrInvalidTokenHolder is an error -func ErrInvalidTokenHolder(codespace sdk.CodespaceType, msg string) sdk.Error { - if msg != "" { - return sdk.NewError(codespace, CodeInvalidTokenHolder, msg) - } - return sdk.NewError(codespace, CodeInvalidTokenHolder, "invalid token holder") -} - -// ErrUnknownTokenHolder is an error -func ErrUnknownTokenHolder(codespace sdk.CodespaceType, msg string) sdk.Error { - if msg != "" { - return sdk.NewError(codespace, CodeUnknownTokenHolder, msg) - } - return sdk.NewError(codespace, CodeUnknownTokenHolder, "unknown token holder") -} diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 574e9888e1e2..a98bdc6b8080 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -6,27 +6,27 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// define consts for inflatoin +// define consts for inflation const ( - InflateCirculating = "circulating" - InflateVesting = "vesting" - InflateHolders = "holders" + TypeCirculating = "circulating" + TypeVesting = "vesting" + TypeModules = "modules" ) -// Supplier represents the keeps track of the total supply amounts in the network +// Supplier represents a struct that passively keeps track of the total supply amounts in the network type Supplier struct { CirculatingSupply sdk.Coins `json:"circulating_supply"` // supply held by accounts that's not vesting VestingSupply sdk.Coins `json:"vesting_supply"` // locked supply held by vesting accounts - HoldersSupply sdk.Coins `json:"holders_supply"` // supply held by non acccount token holders (e.g modules) + ModulesSupply sdk.Coins `json:"modules_supply"` // supply held by modules acccounts TotalSupply sdk.Coins `json:"total_supply"` // total supply of the network } // NewSupplier creates a new Supplier instance -func NewSupplier(circulating, vesting, holders, total sdk.Coins) Supplier { +func NewSupplier(circulating, vesting, modules, total sdk.Coins) Supplier { return Supplier{ CirculatingSupply: circulating, VestingSupply: vesting, - HoldersSupply: holders, + ModulesSupply: modules, TotalSupply: total, } } @@ -36,22 +36,64 @@ func DefaultSupplier() Supplier { return NewSupplier(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) } -// Inflate returns the circulating supply of a coin denomination -func (supplier *Supplier) Inflate(inflationType string, amt sdk.Coins) error { - switch inflationType { - case InflateCirculating: - supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amt) - break - case InflateHolders: - supplier.HoldersSupply = supplier.HoldersSupply.Add(amt) - break - case InflateVesting: - supplier.VestingSupply = supplier.VestingSupply.Add(amt) - break +// Inflate adds coins to a given supply type and updates the total supply +func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) error { + switch supplyType { + case TypeCirculating: + supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) + case TypeVesting: + supplier.VestingSupply = supplier.VestingSupply.Add(amount) + case TypeModules: + supplier.ModulesSupply = supplier.ModulesSupply.Add(amount) default: - return fmt.Errorf("invalid type %s", inflationType) + return fmt.Errorf("invalid type %s", supplyType) } - supplier.TotalSupply = supplier.TotalSupply.Add(amt) + supplier.TotalSupply = supplier.TotalSupply.Add(amount) + return nil +} + +// Deflate safe substracts coins for a given supply and updates the total supply +func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) error { + switch supplyType { + case TypeCirculating: + newSupply, ok := supplier.CirculatingSupply.SafeSub(amount) + if !ok { + panic(fmt.Sprintf( + "circulating supply should be greater than given amount: %s < %s", + supplier.CirculatingSupply.String(), amount.String(), + )) + } + supplier.CirculatingSupply = newSupply + case TypeVesting: + newSupply, ok := supplier.VestingSupply.SafeSub(amount) + if !ok { + panic(fmt.Sprintf( + "vesting supply should be greater than given amount: %s < %s", + supplier.VestingSupply.String(), amount.String(), + )) + } + supplier.VestingSupply = newSupply + case TypeModules: + newSupply, ok := supplier.ModulesSupply.SafeSub(amount) + if !ok { + panic(fmt.Sprintf( + "modules supply should be greater than given amount: %s < %s", + supplier.ModulesSupply.String(), amount.String(), + )) + } + supplier.ModulesSupply = newSupply + default: + return fmt.Errorf("invalid type %s", supplyType) + } + + newSupply, ok := supplier.TotalSupply.SafeSub(amount) + if !ok { + panic(fmt.Sprintf( + "total supply should be greater than given amount: %s < %s", + supplier.TotalSupply.String(), amount.String(), + )) + } + supplier.TotalSupply = newSupply return nil } @@ -65,9 +107,9 @@ func (supplier Supplier) VestingAmountOf(denom string) sdk.Int { return supplier.VestingSupply.AmountOf(denom) } -// HoldersAmountOf returns the total token holders' supply of a coin denomination -func (supplier Supplier) HoldersAmountOf(denom string) sdk.Int { - return supplier.HoldersSupply.AmountOf(denom) +// ModulesAmountOf returns the total token holders' supply of a coin denomination +func (supplier Supplier) ModulesAmountOf(denom string) sdk.Int { + return supplier.ModulesSupply.AmountOf(denom) } // TotalAmountOf returns the total supply of a coin denomination @@ -87,9 +129,9 @@ func (supplier Supplier) ValidateBasic() sdk.Error { fmt.Sprintf("invalid vesting supply: %s", supplier.VestingSupply.String()), ) } - if !supplier.HoldersSupply.IsValid() { + if !supplier.ModulesSupply.IsValid() { return sdk.ErrInvalidCoins( - fmt.Sprintf("invalid token holders supply: %s", supplier.HoldersSupply.String()), + fmt.Sprintf("invalid token holders supply: %s", supplier.ModulesSupply.String()), ) } if !supplier.TotalSupply.IsValid() { @@ -99,7 +141,7 @@ func (supplier Supplier) ValidateBasic() sdk.Error { } calculatedTotalSupply := - supplier.CirculatingSupply.Add(supplier.VestingSupply).Add(supplier.HoldersSupply) + supplier.CirculatingSupply.Add(supplier.VestingSupply).Add(supplier.ModulesSupply) if !supplier.TotalSupply.IsEqual(calculatedTotalSupply) { return sdk.ErrInvalidCoins( @@ -117,10 +159,10 @@ func (supplier Supplier) String() string { return fmt.Sprintf(`Supplier: Circulating Supply: %s Vesting Supply: %s - Holders Supply: %s + Modules Supply: %s Total Supply: %s`, supplier.CirculatingSupply.String(), supplier.VestingSupply.String(), - supplier.HoldersSupply.String(), + supplier.ModulesSupply.String(), supplier.TotalSupply.String()) } diff --git a/x/supply/types/token_holder.go b/x/supply/types/token_holder.go deleted file mode 100644 index 864ef324a862..000000000000 --- a/x/supply/types/token_holder.go +++ /dev/null @@ -1,72 +0,0 @@ -package types - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// TokenHolder defines the interface used for modules that are allowed to hold -// tokens. This is designed to prevent held tokens to be kept in regular Accounts, -// as those are only ment for user accounts -// -// The bank module keeps track of each of the module's holdings and uses it to -// calculate the total supply -type TokenHolder interface { - GetModuleName() string - - GetHoldings() sdk.Coins - SetHoldings(sdk.Coins) - GetHoldingsOf(string) sdk.Int - - ValidateBasic() sdk.Error -} - -//----------------------------------------------------------------------------- -// BaseTokenHolder - -var _ TokenHolder = (*BaseTokenHolder)(nil) - -// BaseTokenHolder defines an instance of a module that holds tokens -type BaseTokenHolder struct { - Module string `json:"module"` - Holdings sdk.Coins `json:"holdings"` // holdings from free available supply (not held by modules or accounts) -} - -// NewBaseTokenHolder creates a new BaseTokenHolder instance -func NewBaseTokenHolder(moduleName string, initialHoldings sdk.Coins) TokenHolder { - return &BaseTokenHolder{ - Module: moduleName, - Holdings: initialHoldings, - } -} - -// GetModuleName returns the the name of the holder's module -func (bth BaseTokenHolder) GetModuleName() string { - return bth.Module -} - -// GetHoldings returns the a total coin denom holdings retained by a module -func (bth BaseTokenHolder) GetHoldings() sdk.Coins { - return bth.Holdings -} - -// SetHoldings updates the holdings to the provided amount -func (bth *BaseTokenHolder) SetHoldings(amount sdk.Coins) { - bth.Holdings = amount -} - -// GetHoldingsOf returns the a total coin denom holdings retained by a module -func (bth BaseTokenHolder) GetHoldingsOf(denom string) sdk.Int { - return bth.Holdings.AmountOf(denom) -} - -// ValidateBasic validates the held coins from a token holder -func (bth BaseTokenHolder) ValidateBasic() sdk.Error { - if !bth.Holdings.IsValid() { - return sdk.ErrInvalidCoins( - fmt.Sprintf("invalid token holder %s coins: %s", bth.Module, bth.Holdings.String()), - ) - } - return nil -} From 62d81618d185a20b94f01acb12e0c3900bd02a18 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 18 Apr 2019 15:44:47 +0200 Subject: [PATCH 20/46] implement module accounts --- cmd/gaia/app/genesis.go | 6 ++++ x/auth/account.go | 50 ++++++++++++++++++++++++++ x/gov/expected_keepers.go | 12 +++++-- x/gov/genesis.go | 10 +++--- x/gov/keeper.go | 62 ++++++++------------------------ x/gov/keeper_test.go | 3 +- x/gov/{keeper_keys.go => key.go} | 39 ++++++++++++++++++++ x/supply/keeper/keeper.go | 7 ++-- x/supply/keeper/keeper_test.go | 3 +- x/supply/keeper/key.go | 2 +- x/supply/types/supplier.go | 9 +++-- 11 files changed, 135 insertions(+), 68 deletions(-) rename x/gov/{keeper_keys.go => key.go} (70%) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 9dbb9009d397..a4ca840149a7 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -198,10 +198,16 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js circulatingSupply, vestingSupply, notBondedSupply, bondedSupply := supplyFromGenAccounts(genesisState.Accounts, genesisState.StakingData.Params.BondDenom) + + // update supply genesisState.SupplyData.Supplier.CirculatingSupply = circulatingSupply genesisState.SupplyData.Supplier.VestingSupply = vestingSupply + genesisState.SupplyData.Supplier.TotalSupply = + genesisState.SupplyData.Supplier.TotalSupply.Add(circulatingSupply).Add(vestingSupply) + genesisState.StakingData.Pool.NotBondedTokens = notBondedSupply genesisState.StakingData.Pool.BondedTokens = bondedSupply + genesisState.GenTxs = appGenTxs return genesisState, nil diff --git a/x/auth/account.go b/x/auth/account.go index 0c0e71a48c40..9e5dabd21566 100644 --- a/x/auth/account.go +++ b/x/auth/account.go @@ -60,6 +60,13 @@ type VestingAccount interface { GetDelegatedVesting() sdk.Coins } +// ModuleAccount defines an account type for modules that hold tokens +type ModuleAccount interface { + Account + + GetModuleName() string +} + // AccountDecoder unmarshals account bytes // TODO: Think about removing type AccountDecoder func(accountBytes []byte) (Account, error) @@ -511,3 +518,46 @@ func (dva *DelayedVestingAccount) GetStartTime() int64 { func (dva *DelayedVestingAccount) GetEndTime() int64 { return dva.EndTime } + +//----------------------------------------------------------------------------- +// Module Holder Account + +var _ ModuleAccount = (*ModuleHolderAccount)(nil) + +// ModuleHolderAccount defines an account for modules that held coins on a pool +type ModuleHolderAccount struct { + *BaseAccount + + Module string `json:"module"` // name of the module +} + +// NewModuleHolderAccount creates a new BaseTokenHolder instance +func NewModuleHolderAccount(baseAcc *BaseAccount, moduleName string) *ModuleHolderAccount { + return &ModuleHolderAccount{ + BaseAccount: baseAcc, + Module: moduleName, + } +} + +// GetModuleName returns the the name of the holder's module +func (mha ModuleHolderAccount) GetModuleName() string { + return mha.Module +} + +//----------------------------------------------------------------------------- +// Module Minter Account + +var _ ModuleAccount = (*ModuleMinterAccount)(nil) + +// ModuleMinterAccount defines an account for modules that held coins on a pool +type ModuleMinterAccount struct { + *ModuleHolderAccount +} + +// NewModuleMinterAccount creates a new BaseTokenHolder instance +func NewModuleMinterAccount(baseAcc *BaseAccount, moduleName string) *ModuleHolderAccount { + return &ModuleHolderAccount{ + BaseAccount: baseAcc, + Module: moduleName, + } +} diff --git a/x/gov/expected_keepers.go b/x/gov/expected_keepers.go index 3235c2524c40..50fcef253509 100644 --- a/x/gov/expected_keepers.go +++ b/x/gov/expected_keepers.go @@ -2,18 +2,24 @@ package gov import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/supply" ) +// AccountKeeper defines the expected account keeper +type AccountKeeper interface { + NewAccount() (ctx sdk.Context, acc auth.Account) auth.Account + SetAccount(ctx sdk.Context, acc Account) +} + // BankKeeper defines the expected bank keeper type BankKeeper interface { GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins AddCoins(tx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) + SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) } // SupplyKeeper defines the expected supply keeper type SupplyKeeper interface { - AddTokenHolder(ctx sdk.Context, moduleName string) (supply.TokenHolder, sdk.Error) - RequestTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) sdk.Error - RelinquishTokens(ctx sdk.Context, moduleName string, amount sdk.Coins) sdk.Error + InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) } diff --git a/x/gov/genesis.go b/x/gov/genesis.go index e089b1382e7a..9c49290bdfce 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -6,6 +6,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) const ( @@ -108,10 +109,11 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { panic(err) } - _, err = k.sk.AddTokenHolder(ctx, ModuleName) - if err != nil { - panic(err) - } + // create and set module account + baseAcc := auth.NewBaseAccountWithAddress(ModuleAddress) + mhAcc := auth.NewModuleHolderAccount(&baseAcc, ModuleName) + + k.ak.SetAccount(ctx, mhAcc) k.setDepositParams(ctx, data.DepositParams) k.setVotingParams(ctx, data.VotingParams) diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 3d4343553e53..ebe4f1d7d050 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -6,47 +6,8 @@ import ( codec "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" - - "github.com/tendermint/tendermint/crypto" -) - -const ( - // ModuleKey is the name of the module - ModuleName = "gov" - - // StoreKey is the store key string for gov - StoreKey = ModuleName - - // RouterKey is the message route for gov - RouterKey = ModuleName - - // QuerierRoute is the querier route for gov - QuerierRoute = ModuleName - - // Parameter store default namestore - DefaultParamspace = ModuleName ) -// Parameter store key -var ( - ParamStoreKeyDepositParams = []byte("depositparams") - ParamStoreKeyVotingParams = []byte("votingparams") - ParamStoreKeyTallyParams = []byte("tallyparams") - - // TODO: Find another way to implement this without using accounts, or find a cleaner way to implement it using accounts. - DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins"))) - BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins"))) -) - -// Key declaration for parameters -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - ParamStoreKeyDepositParams, DepositParams{}, - ParamStoreKeyVotingParams, VotingParams{}, - ParamStoreKeyTallyParams, TallyParams{}, - ) -} - // Governance Keeper type Keeper struct { // The reference to the Param Keeper to get and set Global Params @@ -58,8 +19,8 @@ type Keeper struct { // The reference to the BankKeeper to modify balances ck BankKeeper - // The reference to the SupplyKeeper to hold deposits - sk SupplyKeeper + // The reference to the AccountKeeper to create a module account + ak AccountKeeper // The ValidatorSet to get information about validators vs sdk.ValidatorSet @@ -85,13 +46,13 @@ type Keeper struct { // CONTRACT: Token Holder needs to be added into the bank keeper before calling // this function func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, - paramSpace params.Subspace, bk BankKeeper, sk SupplyKeeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { + paramSpace params.Subspace, bk BankKeeper, ak AccountKeeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { return Keeper{ storeKey: key, paramsKeeper: paramsKeeper, paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), ck: bk, - sk: sk, + ak: ak, ds: ds, vs: ds.GetValidatorSet(), cdc: cdc, @@ -385,8 +346,10 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false } - // request coins for the governance token holder - err := keeper.sk.RequestTokens(ctx, ModuleName, depositAmount) + // update the governance module account coin pool + moduleAddress, _ := sdk.AccAddressFromBech32(ModuleName) + + err := keeper.ck.AddCoins(ctx, moduleAddress, depositAmount) if err != nil { return err, false } @@ -424,13 +387,15 @@ func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID uint64) sdk.Iterato // RefundDeposits Refunds and deletes all the deposits on a specific proposal func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { store := ctx.KVStore(keeper.storeKey) + moduleAddress, _ := sdk.AccAddressFromBech32(ModuleName) depositsIterator := keeper.GetDeposits(ctx, proposalID) defer depositsIterator.Close() for ; depositsIterator.Valid(); depositsIterator.Next() { deposit := &Deposit{} keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) - err := keeper.sk.RelinquishTokens(ctx, ModuleName, deposit.Amount) + // update the governance module account coin pool + _, err := keeper.ck.SubtractCoins(ctx, moduleAddress, deposit.Amount) if err != nil { panic(err) } @@ -447,14 +412,15 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { // DeleteDeposits Deletes all the deposits on a specific proposal without refunding them func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { store := ctx.KVStore(keeper.storeKey) + moduleAddress, _ := sdk.AccAddressFromBech32(ModuleName) depositsIterator := keeper.GetDeposits(ctx, proposalID) defer depositsIterator.Close() for ; depositsIterator.Valid(); depositsIterator.Next() { deposit := &Deposit{} keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) - // Burn deposits; TODO: consider sending to community pool - err := keeper.sk.RelinquishTokens(ctx, ModuleName, deposit.Amount) + // update the governance module account coin pool + _, err := keeper.ck.SubtractCoins(ctx, moduleAddress, deposit.Amount) if err != nil { panic(err) } diff --git a/x/gov/keeper_test.go b/x/gov/keeper_test.go index 67905fd2da82..12aee4651948 100644 --- a/x/gov/keeper_test.go +++ b/x/gov/keeper_test.go @@ -6,9 +6,8 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" ) func TestGetSetProposal(t *testing.T) { diff --git a/x/gov/keeper_keys.go b/x/gov/key.go similarity index 70% rename from x/gov/keeper_keys.go rename to x/gov/key.go index 690379566b1d..81b0e488cdb8 100644 --- a/x/gov/keeper_keys.go +++ b/x/gov/key.go @@ -5,7 +5,34 @@ import ( "fmt" "time" + "github.com/tendermint/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params" +) + +const ( + // ModuleKey is the name of the module + ModuleName = "gov" + + // StoreKey is the store key string for gov + StoreKey = ModuleName + + // RouterKey is the message route for gov + RouterKey = ModuleName + + // QuerierRoute is the querier route for gov + QuerierRoute = ModuleName + + // Parameter store default namestore + DefaultParamspace = ModuleName +) + +// Parameter store key +var ( + ParamStoreKeyDepositParams = []byte("depositparams") + ParamStoreKeyVotingParams = []byte("votingparams") + ParamStoreKeyTallyParams = []byte("tallyparams") ) // Key for getting a the next available proposalID from the store @@ -17,6 +44,9 @@ var ( PrefixInactiveProposalQueue = []byte("inactiveProposalQueue") ) +// Module account address +var ModuleAddress = sdk.AccAddress(crypto.AddressHash([]byte(ModuleName))) + // Key for getting a specific proposal from the store func KeyProposal(proposalID uint64) []byte { return []byte(fmt.Sprintf("proposals:%d", proposalID)) @@ -75,3 +105,12 @@ func KeyInactiveProposalQueueProposal(endTime time.Time, proposalID uint64) []by sdk.Uint64ToBigEndian(proposalID), }, KeyDelimiter) } + +// Key declaration for parameters +func ParamKeyTable() params.KeyTable { + return params.NewKeyTable( + ParamStoreKeyDepositParams, DepositParams{}, + ParamStoreKeyVotingParams, VotingParams{}, + ParamStoreKeyTallyParams, TallyParams{}, + ) +} diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 3b6aa4f290f8..a3e0710c72b1 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -13,7 +13,7 @@ type Keeper struct { } // NewKeeper creates a new supply Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ak AccountKeeper) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper { return Keeper{ cdc: cdc, storeKey: key, @@ -39,8 +39,9 @@ func (k Keeper) SetSupplier(ctx sdk.Context, supplier types.Supplier) { } // InflateSupply adds tokens to the circulating supply -func (k Keeper) InflateSupply(ctx sdk.Context, inflationType string, amount sdk.Coins) { +func (k Keeper) InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) { supplier := k.GetSupplier(ctx) - supplier.Inflate(inflationType, amount) + supplier.Inflate(supplyType, amount) + k.SetSupplier(ctx, supplier) } diff --git a/x/supply/keeper/keeper_test.go b/x/supply/keeper/keeper_test.go index 4cd3aff57ddd..e3ad055c43ef 100644 --- a/x/supply/keeper/keeper_test.go +++ b/x/supply/keeper/keeper_test.go @@ -29,7 +29,7 @@ func TestSupplier(t *testing.T) { expectedSupplier.CirculatingSupply = expectedSupplier.CirculatingSupply.Add(oneUatom) - keeper.InflateSupply(ctx, oneUatom) + keeper.InflateSupply(ctx, types.TypeCirculating, oneUatom) supplier := keeper.GetSupplier(ctx) require.Equal(t, expectedSupplier, supplier) @@ -55,7 +55,6 @@ func CreateTestInput(t *testing.T, isCheckTx bool) (sdk.Context, Keeper) { ) cdc := codec.New() - types.RegisterCodec(cdc) keeper := NewKeeper(cdc, keySupply) diff --git a/x/supply/keeper/key.go b/x/supply/keeper/key.go index b9cb25fac0fe..c88f2dd6ef66 100644 --- a/x/supply/keeper/key.go +++ b/x/supply/keeper/key.go @@ -11,4 +11,4 @@ const ( QuerierRoute = StoreKey ) -var supplierKey = []byte{0x0} \ No newline at end of file +var supplierKey = []byte{0x0} diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index a98bdc6b8080..e2f6e59f165a 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -46,14 +46,14 @@ func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) error { case TypeModules: supplier.ModulesSupply = supplier.ModulesSupply.Add(amount) default: - return fmt.Errorf("invalid type %s", supplyType) + panic(fmt.Errorf("invalid type %s", supplyType)) } supplier.TotalSupply = supplier.TotalSupply.Add(amount) return nil } -// Deflate safe substracts coins for a given supply and updates the total supply -func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) error { +// Deflate safe subtracts coins for a given supply and updates the total supply +func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { switch supplyType { case TypeCirculating: newSupply, ok := supplier.CirculatingSupply.SafeSub(amount) @@ -83,7 +83,7 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) error { } supplier.ModulesSupply = newSupply default: - return fmt.Errorf("invalid type %s", supplyType) + panic(fmt.Errorf("invalid type %s", supplyType)) } newSupply, ok := supplier.TotalSupply.SafeSub(amount) @@ -94,7 +94,6 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) error { )) } supplier.TotalSupply = newSupply - return nil } // CirculatingAmountOf returns the circulating supply of a coin denomination From 044a0c69b5ede2a507d901ded7ab49227b5f273f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 18 Apr 2019 17:26:06 +0200 Subject: [PATCH 21/46] check for module acc on genesis --- cmd/gaia/app/genesis.go | 62 +++++++++++++++++++++++++------------- x/auth/account.go | 49 +++++++++++++++++------------- x/supply/types/supplier.go | 3 +- 3 files changed, 70 insertions(+), 44 deletions(-) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index a4ca840149a7..e9aa3957d3e2 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -98,8 +98,13 @@ type GenesisAccount struct { DelegatedVesting sdk.Coins `json:"delegated_vesting"` // delegated vesting coins at time of delegation StartTime int64 `json:"start_time"` // vesting start time (UNIX Epoch time) EndTime int64 `json:"end_time"` // vesting end time (UNIX Epoch time) + + // module account fields + Module string `json:"module"` // name of the module + AllowMint bool `json:"allow_mint"` // checks for module account type } +// NewGenesisAccount creates a GenesisAccount instance from a BaseAccount func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { return GenesisAccount{ Address: acc.Address, @@ -109,6 +114,7 @@ func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { } } +// NewGenesisAccountI creates a GenesisAccount instance from an Account interface func NewGenesisAccountI(acc auth.Account) GenesisAccount { gacc := GenesisAccount{ Address: acc.GetAddress(), @@ -126,10 +132,20 @@ func NewGenesisAccountI(acc auth.Account) GenesisAccount { gacc.EndTime = vacc.GetEndTime() } + macc, ok := acc.(auth.ModuleAccount) + if ok { + gacc.Module = macc.GetModuleName() + if err := macc.SetCoins(macc.GetCoins()); err == nil { + gacc.AllowMint = true + } else { + gacc.AllowMint = false + } + } + return gacc } -// convert GenesisAccount to auth.BaseAccount +// ToAccount converts a GenesisAccount to an Account interface func (ga *GenesisAccount) ToAccount() auth.Account { bacc := &auth.BaseAccount{ Address: ga.Address, @@ -138,6 +154,7 @@ func (ga *GenesisAccount) ToAccount() auth.Account { Sequence: ga.Sequence, } + // vesting accounts if !ga.OriginalVesting.IsZero() { baseVestingAcc := &auth.BaseVestingAccount{ BaseAccount: bacc, @@ -161,10 +178,18 @@ func (ga *GenesisAccount) ToAccount() auth.Account { } } + // module accounts + if ga.Module != "" { + if ga.AllowMint { + return auth.NewModuleMinterAccount(ga.Module) + } + return auth.NewModuleHolderAccount(ga.Module) + } + return bacc } -// Create the core parameters for genesis initialization for gaia +// GaiaAppGenState creates the core parameters for genesis initialization for gaia // note that the pubkey input is this machines pubkey func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) ( genesisState GenesisState, err error) { @@ -196,14 +221,8 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } } - circulatingSupply, vestingSupply, notBondedSupply, bondedSupply := - supplyFromGenAccounts(genesisState.Accounts, genesisState.StakingData.Params.BondDenom) - - // update supply - genesisState.SupplyData.Supplier.CirculatingSupply = circulatingSupply - genesisState.SupplyData.Supplier.VestingSupply = vestingSupply - genesisState.SupplyData.Supplier.TotalSupply = - genesisState.SupplyData.Supplier.TotalSupply.Add(circulatingSupply).Add(vestingSupply) + notBondedSupply, bondedSupply := + updateSupply(genesisState.Accounts, genesisState.StakingData.Params.BondDenom, &genesisState.SupplyData.Supplier) genesisState.StakingData.Pool.NotBondedTokens = notBondedSupply genesisState.StakingData.Pool.BondedTokens = bondedSupply @@ -417,21 +436,22 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm return appGenTxs, persistentPeers, nil } -// supplyFromGenAccounts calculates the circulating, vesting, and stakingToken -// (bonded and not bonded) total supply from the genesis accounts -func supplyFromGenAccounts(genAccounts []GenesisAccount, bondDenom string, -) ( - circulatingSupply, vestingSupply sdk.Coins, - notBondedTokens, bondedTokens sdk.Int, -) { +// updateSupply calculates the circulating, vesting, and staking (bonded and not bonded) +// total supply from the genesis accounts +func updateSupply(genAccounts []GenesisAccount, bondDenom string, supplier *supply.Supplier) (notBondedTokens, bondedTokens sdk.Int) { + for _, genAcc := range genAccounts { + // circulating amount not subject to vesting (i.e free) - circulatingSupply = circulatingSupply.Add(genAcc.Coins) + supplier.Inflate(supply.TypeCirculating, genAcc.OriginalVesting) // vesting and bonded supply from vesting accounts - if genAcc.DelegatedVesting.IsAllPositive() { - vestingSupply = vestingSupply.Add(genAcc.OriginalVesting) - bondedTokens = bondedTokens.Add(genAcc.DelegatedVesting.AmountOf(bondDenom)) + if genAcc.OriginalVesting.IsAllPositive() { + supplier.Inflate(supply.TypeVesting, genAcc.OriginalVesting) + + if genAcc.DelegatedVesting.IsAllPositive() { + bondedTokens = bondedTokens.Add(genAcc.DelegatedVesting.AmountOf(bondDenom)) + } } // staking pool's not bonded supply diff --git a/x/auth/account.go b/x/auth/account.go index 9e5dabd21566..a2fd71a04c1e 100644 --- a/x/auth/account.go +++ b/x/auth/account.go @@ -520,44 +520,51 @@ func (dva *DelayedVestingAccount) GetEndTime() int64 { } //----------------------------------------------------------------------------- -// Module Holder Account +// Module Minter Account -var _ ModuleAccount = (*ModuleHolderAccount)(nil) +var _ ModuleAccount = (*ModuleMinterAccount)(nil) -// ModuleHolderAccount defines an account for modules that held coins on a pool -type ModuleHolderAccount struct { +// ModuleMinterAccount defines an account for modules that held coins on a pool +type ModuleMinterAccount struct { *BaseAccount Module string `json:"module"` // name of the module } -// NewModuleHolderAccount creates a new BaseTokenHolder instance -func NewModuleHolderAccount(baseAcc *BaseAccount, moduleName string) *ModuleHolderAccount { - return &ModuleHolderAccount{ - BaseAccount: baseAcc, +// NewModuleMinterAccount creates a new BaseTokenHolder instance +func NewModuleMinterAccount(moduleName string) *ModuleMinterAccount { + moduleAddress := sdk.AccAddress(crypto.AddressHash([]byte(moduleName))) + + baseAcc := NewBaseAccountWithAddress(moduleAddress) + return &ModuleMinterAccount{ + BaseAccount: &baseAcc, Module: moduleName, } } // GetModuleName returns the the name of the holder's module -func (mha ModuleHolderAccount) GetModuleName() string { - return mha.Module +func (mma ModuleMinterAccount) GetModuleName() string { + return mma.Module } //----------------------------------------------------------------------------- -// Module Minter Account +// Module Holder Account -var _ ModuleAccount = (*ModuleMinterAccount)(nil) +var _ ModuleAccount = (*ModuleHolderAccount)(nil) -// ModuleMinterAccount defines an account for modules that held coins on a pool -type ModuleMinterAccount struct { - *ModuleHolderAccount +// ModuleHolderAccount defines an account for modules that held coins on a pool +type ModuleHolderAccount struct { + *ModuleMinterAccount } -// NewModuleMinterAccount creates a new BaseTokenHolder instance -func NewModuleMinterAccount(baseAcc *BaseAccount, moduleName string) *ModuleHolderAccount { - return &ModuleHolderAccount{ - BaseAccount: baseAcc, - Module: moduleName, - } +// NewModuleHolderAccount creates a new BaseTokenHolder instance +func NewModuleHolderAccount(moduleName string) *ModuleHolderAccount { + moduleMinterAcc := NewModuleMinterAccount(moduleName) + + return &ModuleHolderAccount{ModuleMinterAccount: moduleMinterAcc} +} + +// SetCoins not supported for ModuleHolderAccount +func (mha ModuleHolderAccount) SetCoins(coins sdk.Coins) error { + return fmt.Errorf("module holders account don't support setting coins") } diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index e2f6e59f165a..1e2b62fbe5c8 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -37,7 +37,7 @@ func DefaultSupplier() Supplier { } // Inflate adds coins to a given supply type and updates the total supply -func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) error { +func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { switch supplyType { case TypeCirculating: supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) @@ -49,7 +49,6 @@ func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) error { panic(fmt.Errorf("invalid type %s", supplyType)) } supplier.TotalSupply = supplier.TotalSupply.Add(amount) - return nil } // Deflate safe subtracts coins for a given supply and updates the total supply From 913793cb1def78773c1195b282991746e5dff37b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 18 Apr 2019 18:40:50 +0200 Subject: [PATCH 22/46] update vesting and circulating supply --- x/bank/expected_keepers.go | 6 ++++++ x/bank/keeper.go | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/x/bank/expected_keepers.go b/x/bank/expected_keepers.go index 7e66dbd6f440..d2084568c3b8 100644 --- a/x/bank/expected_keepers.go +++ b/x/bank/expected_keepers.go @@ -8,3 +8,9 @@ import ( type CrisisKeeper interface { RegisterRoute(moduleName, route string, invar sdk.Invariant) } + +// SupplyKeeper expected supply keeper +type SupplyKeeper interface { + InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) + DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) +} diff --git a/x/bank/keeper.go b/x/bank/keeper.go index a500d1841505..c4432cf8f5c8 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank/tags" "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/supply" ) var _ Keeper = (*BaseKeeper)(nil) @@ -34,12 +35,14 @@ type BaseKeeper struct { BaseSendKeeper ak auth.AccountKeeper + sk SupplyKeeper paramSpace params.Subspace } // NewBaseKeeper returns a new BaseKeeper func NewBaseKeeper( ak auth.AccountKeeper, + sk SupplyKeeper, paramSpace params.Subspace, codespace sdk.CodespaceType) BaseKeeper { @@ -47,6 +50,7 @@ func NewBaseKeeper( return BaseKeeper{ BaseSendKeeper: NewBaseSendKeeper(ak, ps, codespace), ak: ak, + sk: sk, paramSpace: ps, } } @@ -105,7 +109,7 @@ func (keeper BaseKeeper) DelegateCoins( if !amt.IsValid() { return nil, sdk.ErrInvalidCoins(amt.String()) } - return delegateCoins(ctx, keeper.ak, addr, amt) + return delegateCoins(ctx, keeper.ak, keeper.sk, addr, amt) } // UndelegateCoins performs undelegation by crediting amt coins to an account with @@ -119,7 +123,7 @@ func (keeper BaseKeeper) UndelegateCoins( if !amt.IsValid() { return nil, sdk.ErrInvalidCoins(amt.String()) } - return undelegateCoins(ctx, keeper.ak, addr, amt) + return undelegateCoins(ctx, keeper.ak, keeper.sk, addr, amt) } //------------------------------------------------------- @@ -382,7 +386,7 @@ func inputOutputCoins(ctx sdk.Context, am auth.AccountKeeper, inputs []Input, ou // staking func delegateCoins( - ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins, + ctx sdk.Context, ak auth.AccountKeeper, sk SupplyKeeper, addr sdk.AccAddress, amt sdk.Coins, ) (sdk.Tags, sdk.Error) { if !amt.IsValid() { @@ -403,12 +407,23 @@ func delegateCoins( ) } + var updateSupplyAmt sdk.Coins + vacc, isVestingAccount := acc.(auth.VestingAccount) + if isVestingAccount && vacc.GetDelegatedVesting().IsAllPositive() && ctx.BlockHeader().Time.Unix() >= vacc.GetEndTime() { + updateSupplyAmt = vacc.GetOriginalVesting() + } + if err := trackDelegation(acc, ctx.BlockHeader().Time, amt); err != nil { return nil, sdk.ErrInternal(fmt.Sprintf("failed to track delegation: %v", err)) } setAccount(ctx, ak, acc) + if isVestingAccount { + sk.DeflateSupply(ctx, supply.TypeVesting, updateSupplyAmt) + sk.InflateSupply(ctx, supply.TypeCirculating, updateSupplyAmt) + } + return sdk.NewTags( sdk.TagAction, tags.ActionDelegateCoins, sdk.TagDelegator, addr.String(), @@ -416,7 +431,7 @@ func delegateCoins( } func undelegateCoins( - ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins, + ctx sdk.Context, ak auth.AccountKeeper, sk SupplyKeeper, addr sdk.AccAddress, amt sdk.Coins, ) (sdk.Tags, sdk.Error) { if !amt.IsValid() { @@ -428,12 +443,23 @@ func undelegateCoins( return nil, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr)) } + var updateSupplyAmt sdk.Coins + vacc, isVestingAccount := acc.(auth.VestingAccount) + if isVestingAccount && vacc.GetDelegatedVesting().IsAllPositive() && ctx.BlockHeader().Time.Unix() >= vacc.GetEndTime() { + updateSupplyAmt = vacc.GetOriginalVesting() + } + if err := trackUndelegation(acc, amt); err != nil { return nil, sdk.ErrInternal(fmt.Sprintf("failed to track undelegation: %v", err)) } setAccount(ctx, ak, acc) + if isVestingAccount { + sk.DeflateSupply(ctx, supply.TypeVesting, updateSupplyAmt) + sk.InflateSupply(ctx, supply.TypeCirculating, updateSupplyAmt) + } + return sdk.NewTags( sdk.TagAction, tags.ActionUndelegateCoins, sdk.TagDelegator, addr.String(), From c2b30cec3ca89cc900281bd163a4568a07a89830 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 23 Apr 2019 16:41:28 +0200 Subject: [PATCH 23/46] move invariants out of staking --- x/staking/keeper/invariants.go | 65 +------------- x/supply/keeper/expected_keepers.go | 19 ++++ x/supply/keeper/invariants.go | 135 ++++++++++++++++++++++++++++ x/supply/keeper/keeper.go | 15 +++- x/supply/types/supplier.go | 68 +++++++------- 5 files changed, 201 insertions(+), 101 deletions(-) create mode 100644 x/supply/keeper/expected_keepers.go create mode 100644 x/supply/keeper/invariants.go diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go index f9a495a4f6eb..9e67a56075cc 100644 --- a/x/staking/keeper/invariants.go +++ b/x/staking/keeper/invariants.go @@ -13,8 +13,6 @@ import ( func RegisterInvariants(c types.CrisisKeeper, k Keeper, f types.FeeCollectionKeeper, d types.DistributionKeeper, am auth.AccountKeeper) { - c.RegisterRoute(types.ModuleName, "supply", - SupplyInvariants(k, f, d, am)) c.RegisterRoute(types.ModuleName, "nonnegative-power", NonNegativePowerInvariant(k)) c.RegisterRoute(types.ModuleName, "positive-delegation", @@ -28,12 +26,8 @@ func AllInvariants(k Keeper, f types.FeeCollectionKeeper, d types.DistributionKeeper, am auth.AccountKeeper) sdk.Invariant { return func(ctx sdk.Context) error { - err := SupplyInvariants(k, f, d, am)(ctx) - if err != nil { - return err - } - err = NonNegativePowerInvariant(k)(ctx) + err := NonNegativePowerInvariant(k)(ctx) if err != nil { return err } @@ -52,63 +46,6 @@ func AllInvariants(k Keeper, f types.FeeCollectionKeeper, } } -// SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations -// nolint: unparam -func SupplyInvariants(k Keeper, f types.FeeCollectionKeeper, - d types.DistributionKeeper, am auth.AccountKeeper) sdk.Invariant { - - return func(ctx sdk.Context) error { - pool := k.GetPool(ctx) - - loose := sdk.ZeroDec() - bonded := sdk.ZeroDec() - am.IterateAccounts(ctx, func(acc auth.Account) bool { - loose = loose.Add(acc.GetCoins().AmountOf(k.BondDenom(ctx)).ToDec()) - return false - }) - k.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) bool { - for _, entry := range ubd.Entries { - loose = loose.Add(entry.Balance.ToDec()) - } - return false - }) - k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool { - switch validator.GetStatus() { - case sdk.Bonded: - bonded = bonded.Add(validator.GetBondedTokens().ToDec()) - case sdk.Unbonding, sdk.Unbonded: - loose = loose.Add(validator.GetTokens().ToDec()) - } - // add yet-to-be-withdrawn - loose = loose.Add(d.GetValidatorOutstandingRewardsCoins(ctx, validator.GetOperator()).AmountOf(k.BondDenom(ctx))) - return false - }) - - // add outstanding fees - loose = loose.Add(f.GetCollectedFees(ctx).AmountOf(k.BondDenom(ctx)).ToDec()) - - // add community pool - loose = loose.Add(d.GetFeePoolCommunityCoins(ctx).AmountOf(k.BondDenom(ctx))) - - // Not-bonded tokens should equal coin supply plus unbonding delegations - // plus tokens on unbonded validators - if !pool.NotBondedTokens.ToDec().Equal(loose) { - return fmt.Errorf("loose token invariance:\n"+ - "\tpool.NotBondedTokens: %v\n"+ - "\tsum of account tokens: %v", pool.NotBondedTokens, loose) - } - - // Bonded tokens should equal sum of tokens with bonded validators - if !pool.BondedTokens.ToDec().Equal(bonded) { - return fmt.Errorf("bonded token invariance:\n"+ - "\tpool.BondedTokens: %v\n"+ - "\tsum of account tokens: %v", pool.BondedTokens, bonded) - } - - return nil - } -} - // NonNegativePowerInvariant checks that all stored validators have >= 0 power. func NonNegativePowerInvariant(k Keeper) sdk.Invariant { return func(ctx sdk.Context) error { diff --git a/x/supply/keeper/expected_keepers.go b/x/supply/keeper/expected_keepers.go new file mode 100644 index 000000000000..e04e9c39c91c --- /dev/null +++ b/x/supply/keeper/expected_keepers.go @@ -0,0 +1,19 @@ +package keeper + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// CrisisKeeper defunes the expected crisis keeper +type CrisisKeeper interface { + RegisterRoute(moduleName, route string, invar sdk.Invariant) +} + +// // FeeCollectionKeeper defines the expected fee collection keeper +// type FeeCollectionKeeper interface { +// AddCollectedFees(sdk.Context, sdk.Coins) sdk.Coins +// } + +// StakingKeeper defines the expected staking keeper +type StakingKeeper interface { + BondDenom(ctx sdk.Context) string + TotalBondedTokens(ctx sdk.Context) sdk.Int +} diff --git a/x/supply/keeper/invariants.go b/x/supply/keeper/invariants.go new file mode 100644 index 000000000000..1581cd0f2cd3 --- /dev/null +++ b/x/supply/keeper/invariants.go @@ -0,0 +1,135 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// RegisterInvariants registers all supply invariants +func RegisterInvariants(ck CrisisKeeper, k Keeper, ak auth.AccountKeeper) { + ck.RegisterRoute(ModuleName, "supply", SupplyInvariants(k, ak)) +} + +// AllInvariants runs all invariants of the staking module. +func AllInvariants(k Keeper, fck types.FeeCollectionKeeper, + dk types.DistributionKeeper, ak auth.AccountKeeper) sdk.Invariant { + + return func(ctx sdk.Context) error { + err := SupplyInvariants(k, ak)(ctx) + if err != nil { + return err + } + + return nil + } +} + +// SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations +// nolint: unparam +func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { + + return func(ctx sdk.Context) error { + supplier := k.GetSupplier(ctx) + + var circulatingAmount sdk.Coins + var vestingAmount sdk.Coins + var modulesAmount sdk.Coins + + ak.IterateAccounts(ctx, func(acc auth.Account) bool { + vacc, isVestingAccount := acc.(auth.VestingAccount) + if isVestingAccount && vacc.GetDelegatedVesting().IsAllPositive() && ctx.BlockHeader().Time.Unix() >= vacc.GetEndTime() { + + vestingAmount = vestingAmount.Add(vacc.GetOriginalVesting()) + circulatingAmount = circulatingAmount.Add(vacc.GetCoins()) + } + + macc, isModuleAccount := acc.(auth.ModuleAccount) + if isModuleAccount { + modulesAmount = modulesAmount.Add(macc.GetCoins()) + } + + return false + }) + + if !supplier.CirculatingSupply.IsEqual(circulatingAmount) { + return fmt.Errorf("circulating supply invariance:\n"+ + "\tsupplier.CirculatingSupply: %v\n"+ + "\tsum of circulating tokens: %v", supplier.CirculatingSupply, circulatingAmount) + } + + if !supplier.VestingSupply.IsEqual(vestingAmount) { + return fmt.Errorf("vesting supply invariance:\n"+ + "\tsupplier.VestingSupply: %v\n"+ + "\tsum of vesting tokens: %v", supplier.VestingSupply, vestingAmount) + } + + if !supplier.ModulesSupply.IsEqual(modulesAmount) { + return fmt.Errorf("modules holdings supply invariance:\n"+ + "\tsupplier.ModulesSupply: %v\n"+ + "\tsum of modules accounts tokens: %v", supplier.ModulesSupply, modulesAmount) + } + + return nil + } +} + +// // SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations +// // nolint: unparam +// func SupplyInvariants( +// k Keeper, f FeeCollectionKeeper, +// d DistributionKeeper, am auth.AccountKeeper) sdk.Invariant { + +// return func(ctx sdk.Context) error { +// pool := k.GetPool(ctx) + +// loose := sdk.ZeroDec() +// bonded := sdk.ZeroDec() +// am.IterateAccounts(ctx, func(acc auth.Account) bool { +// loose = loose.Add(acc.GetCoins().AmountOf(k.BondDenom(ctx)).ToDec()) +// return false +// }) +// k.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) bool { +// for _, entry := range ubd.Entries { +// loose = loose.Add(entry.Balance.ToDec()) +// } +// return false +// }) +// k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool { +// switch validator.GetStatus() { +// case sdk.Bonded: +// bonded = bonded.Add(validator.GetBondedTokens().ToDec()) +// case sdk.Unbonding, sdk.Unbonded: +// loose = loose.Add(validator.GetTokens().ToDec()) +// } +// // add yet-to-be-withdrawn +// loose = loose.Add(d.GetValidatorOutstandingRewardsCoins(ctx, validator.GetOperator()).AmountOf(k.BondDenom(ctx))) +// return false +// }) + +// // add outstanding fees +// loose = loose.Add(f.GetCollectedFees(ctx).AmountOf(k.BondDenom(ctx)).ToDec()) + +// // add community pool +// loose = loose.Add(d.GetFeePoolCommunityCoins(ctx).AmountOf(k.BondDenom(ctx))) + +// // Not-bonded tokens should equal coin supply plus unbonding delegations +// // plus tokens on unbonded validators +// if !pool.NotBondedTokens.ToDec().Equal(loose) { +// return fmt.Errorf("loose token invariance:\n"+ +// "\tpool.NotBondedTokens: %v\n"+ +// "\tsum of account tokens: %v", pool.NotBondedTokens, loose) +// } + +// // Bonded tokens should equal sum of tokens with bonded validators +// if !pool.BondedTokens.ToDec().Equal(bonded) { +// return fmt.Errorf("bonded token invariance:\n"+ +// "\tpool.BondedTokens: %v\n"+ +// "\tsum of account tokens: %v", pool.BondedTokens, bonded) +// } + +// return nil +// } +// } diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index a3e0710c72b1..f2aaec9ac1b9 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -10,13 +10,16 @@ import ( type Keeper struct { cdc *codec.Codec storeKey sdk.StoreKey + + sk StakingKeeper } // NewKeeper creates a new supply Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk StakingKeeper) Keeper { return Keeper{ cdc: cdc, storeKey: key, + sk: sk, } } @@ -45,3 +48,13 @@ func (k Keeper) InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coi k.SetSupplier(ctx, supplier) } + +// TotalSupply returns the total supply of the network +// +// TODO: add unbonded +func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { + supplier := k.GetSupplier(ctx) + bondedSupply := sdk.NewCoins(sdk.NewCoin(k.sk.BondDenom(ctx), k.sk.TotalBondedTokens(ctx))) + supplierTotal := supplier.Total() + return supplierTotal.Add(bondedSupply) +} diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 1e2b62fbe5c8..ff96f13402ed 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -18,42 +18,47 @@ type Supplier struct { CirculatingSupply sdk.Coins `json:"circulating_supply"` // supply held by accounts that's not vesting VestingSupply sdk.Coins `json:"vesting_supply"` // locked supply held by vesting accounts ModulesSupply sdk.Coins `json:"modules_supply"` // supply held by modules acccounts - TotalSupply sdk.Coins `json:"total_supply"` // total supply of the network } // NewSupplier creates a new Supplier instance -func NewSupplier(circulating, vesting, modules, total sdk.Coins) Supplier { +func NewSupplier(circulating, vesting, modules sdk.Coins) Supplier { + return Supplier{ CirculatingSupply: circulating, VestingSupply: vesting, ModulesSupply: modules, - TotalSupply: total, } } // DefaultSupplier creates an empty Supplier func DefaultSupplier() Supplier { - return NewSupplier(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) + + return NewSupplier(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) } // Inflate adds coins to a given supply type and updates the total supply func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { switch supplyType { + case TypeCirculating: supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) + case TypeVesting: supplier.VestingSupply = supplier.VestingSupply.Add(amount) + case TypeModules: supplier.ModulesSupply = supplier.ModulesSupply.Add(amount) + default: panic(fmt.Errorf("invalid type %s", supplyType)) } - supplier.TotalSupply = supplier.TotalSupply.Add(amount) } // Deflate safe subtracts coins for a given supply and updates the total supply func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { + switch supplyType { + case TypeCirculating: newSupply, ok := supplier.CirculatingSupply.SafeSub(amount) if !ok { @@ -63,6 +68,7 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { )) } supplier.CirculatingSupply = newSupply + case TypeVesting: newSupply, ok := supplier.VestingSupply.SafeSub(amount) if !ok { @@ -72,6 +78,7 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { )) } supplier.VestingSupply = newSupply + case TypeModules: newSupply, ok := supplier.ModulesSupply.SafeSub(amount) if !ok { @@ -81,42 +88,49 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { )) } supplier.ModulesSupply = newSupply + default: panic(fmt.Errorf("invalid type %s", supplyType)) } - - newSupply, ok := supplier.TotalSupply.SafeSub(amount) - if !ok { - panic(fmt.Sprintf( - "total supply should be greater than given amount: %s < %s", - supplier.TotalSupply.String(), amount.String(), - )) - } - supplier.TotalSupply = newSupply } // CirculatingAmountOf returns the circulating supply of a coin denomination func (supplier Supplier) CirculatingAmountOf(denom string) sdk.Int { + return supplier.CirculatingSupply.AmountOf(denom) } // VestingAmountOf returns the vesting supply of a coin denomination func (supplier Supplier) VestingAmountOf(denom string) sdk.Int { + return supplier.VestingSupply.AmountOf(denom) } // ModulesAmountOf returns the total token holders' supply of a coin denomination func (supplier Supplier) ModulesAmountOf(denom string) sdk.Int { + return supplier.ModulesSupply.AmountOf(denom) } -// TotalAmountOf returns the total supply of a coin denomination +// Total returns the sum of circulating, vesting and modules supply +func (supplier Supplier) Total() sdk.Coins { + + return supplier.CirculatingSupply. + Add(supplier.VestingSupply). + Add(supplier.ModulesSupply) +} + +// TotalAmountOf returns the sum of circulating, vesting and modules supply for a specific coin denomination func (supplier Supplier) TotalAmountOf(denom string) sdk.Int { - return supplier.TotalSupply.AmountOf(denom) + + return supplier.ModulesAmountOf(denom). + Add(supplier.VestingAmountOf(denom)). + Add(supplier.ModulesAmountOf(denom)) } // ValidateBasic validates the Supply coins and returns error if invalid func (supplier Supplier) ValidateBasic() sdk.Error { + if !supplier.CirculatingSupply.IsValid() { return sdk.ErrInvalidCoins( fmt.Sprintf("invalid circulating supply: %s", supplier.CirculatingSupply.String()), @@ -132,22 +146,6 @@ func (supplier Supplier) ValidateBasic() sdk.Error { fmt.Sprintf("invalid token holders supply: %s", supplier.ModulesSupply.String()), ) } - if !supplier.TotalSupply.IsValid() { - return sdk.ErrInvalidCoins( - fmt.Sprintf("invalid total supply: %s", supplier.TotalSupply.String()), - ) - } - - calculatedTotalSupply := - supplier.CirculatingSupply.Add(supplier.VestingSupply).Add(supplier.ModulesSupply) - - if !supplier.TotalSupply.IsEqual(calculatedTotalSupply) { - return sdk.ErrInvalidCoins( - fmt.Sprintf("total supply ≠ calculated total supply: %s ≠ %s", - supplier.TotalSupply.String(), calculatedTotalSupply, - ), - ) - } return nil } @@ -157,10 +155,8 @@ func (supplier Supplier) String() string { return fmt.Sprintf(`Supplier: Circulating Supply: %s Vesting Supply: %s - Modules Supply: %s - Total Supply: %s`, + Modules Supply: %s`, supplier.CirculatingSupply.String(), supplier.VestingSupply.String(), - supplier.ModulesSupply.String(), - supplier.TotalSupply.String()) + supplier.ModulesSupply.String()) } From 4fcf036db2671230c31ba1b86ff43dfa5748b315 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 23 Apr 2019 16:41:42 +0200 Subject: [PATCH 24/46] update gov genesis --- x/gov/expected_keepers.go | 5 ++--- x/gov/genesis.go | 11 ++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x/gov/expected_keepers.go b/x/gov/expected_keepers.go index 50fcef253509..a0103cf8cdee 100644 --- a/x/gov/expected_keepers.go +++ b/x/gov/expected_keepers.go @@ -3,13 +3,12 @@ package gov import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/supply" ) // AccountKeeper defines the expected account keeper type AccountKeeper interface { - NewAccount() (ctx sdk.Context, acc auth.Account) auth.Account - SetAccount(ctx sdk.Context, acc Account) + GetAccount(ctx sdk.Context, addr sdk.AccAddress) auth.Account + SetAccount(ctx sdk.Context, acc auth.Account) } // BankKeeper defines the expected bank keeper diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 9c49290bdfce..5580d14dea0c 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -109,11 +109,12 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { panic(err) } - // create and set module account - baseAcc := auth.NewBaseAccountWithAddress(ModuleAddress) - mhAcc := auth.NewModuleHolderAccount(&baseAcc, ModuleName) - - k.ak.SetAccount(ctx, mhAcc) + // check if the module account exists and create it if not + moduleAcc := k.ak.GetAccount(ctx, ModuleAddress) + if moduleAcc == nil { + moduleAcc = auth.NewModuleHolderAccount(ModuleName) + k.ak.SetAccount(ctx, moduleAcc) + } k.setDepositParams(ctx, data.DepositParams) k.setVotingParams(ctx, data.VotingParams) From 34a658a1e8e08e6bee9b2b92959d5f184ceaf095 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 23 Apr 2019 21:04:23 +0200 Subject: [PATCH 25/46] update invariants --- x/staking/keeper/invariants.go | 44 ++++++++++++++--- x/supply/keeper/expected_keepers.go | 8 ++-- x/supply/keeper/invariants.go | 74 ++++++----------------------- x/supply/keeper/keeper.go | 16 ++++--- 4 files changed, 66 insertions(+), 76 deletions(-) diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go index 9e67a56075cc..632ba0b9d657 100644 --- a/x/staking/keeper/invariants.go +++ b/x/staking/keeper/invariants.go @@ -5,14 +5,14 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// register all staking invariants -func RegisterInvariants(c types.CrisisKeeper, k Keeper, f types.FeeCollectionKeeper, - d types.DistributionKeeper, am auth.AccountKeeper) { +// RegisterInvariants registers all staking invariants +func RegisterInvariants(c types.CrisisKeeper, k Keeper) { + c.RegisterRoute(types.ModuleName, "bonded-tokens", + BondedTokensInvariant(k)) c.RegisterRoute(types.ModuleName, "nonnegative-power", NonNegativePowerInvariant(k)) c.RegisterRoute(types.ModuleName, "positive-delegation", @@ -22,12 +22,16 @@ func RegisterInvariants(c types.CrisisKeeper, k Keeper, f types.FeeCollectionKee } // AllInvariants runs all invariants of the staking module. -func AllInvariants(k Keeper, f types.FeeCollectionKeeper, - d types.DistributionKeeper, am auth.AccountKeeper) sdk.Invariant { +func AllInvariants(k Keeper) sdk.Invariant { return func(ctx sdk.Context) error { - err := NonNegativePowerInvariant(k)(ctx) + err := BondedTokensInvariant(k)(ctx) + if err != nil { + return err + } + + err = NonNegativePowerInvariant(k)(ctx) if err != nil { return err } @@ -46,6 +50,32 @@ func AllInvariants(k Keeper, f types.FeeCollectionKeeper, } } +// BondedTokensInvariant checks that the total bonded tokens reflects all bonded tokens in delegations +func BondedTokensInvariant(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) error { + pool := k.GetPool(ctx) + + bonded := sdk.ZeroDec() + k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool { + switch validator.GetStatus() { + case sdk.Bonded: + bonded = bonded.Add(validator.GetBondedTokens().ToDec()) + } + + return false + }) + + // Bonded tokens should equal sum of tokens with bonded validators + if !pool.BondedTokens.ToDec().Equal(bonded) { + return fmt.Errorf("bonded token invariance:\n"+ + "\tpool.BondedTokens: %v\n"+ + "\tsum of account tokens: %v", pool.BondedTokens, bonded) + } + + return nil + } +} + // NonNegativePowerInvariant checks that all stored validators have >= 0 power. func NonNegativePowerInvariant(k Keeper) sdk.Invariant { return func(ctx sdk.Context) error { diff --git a/x/supply/keeper/expected_keepers.go b/x/supply/keeper/expected_keepers.go index e04e9c39c91c..7666c4b10f3c 100644 --- a/x/supply/keeper/expected_keepers.go +++ b/x/supply/keeper/expected_keepers.go @@ -7,10 +7,10 @@ type CrisisKeeper interface { RegisterRoute(moduleName, route string, invar sdk.Invariant) } -// // FeeCollectionKeeper defines the expected fee collection keeper -// type FeeCollectionKeeper interface { -// AddCollectedFees(sdk.Context, sdk.Coins) sdk.Coins -// } +// FeeCollectionKeeper defines the expected fee collection keeper +type FeeCollectionKeeper interface { + GetCollectedFees(ctx sdk.Context) sdk.Coins +} // StakingKeeper defines the expected staking keeper type StakingKeeper interface { diff --git a/x/supply/keeper/invariants.go b/x/supply/keeper/invariants.go index 1581cd0f2cd3..958795576d30 100644 --- a/x/supply/keeper/invariants.go +++ b/x/supply/keeper/invariants.go @@ -28,7 +28,6 @@ func AllInvariants(k Keeper, fck types.FeeCollectionKeeper, } // SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations -// nolint: unparam func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { return func(ctx sdk.Context) error { @@ -72,64 +71,21 @@ func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { "\tsum of modules accounts tokens: %v", supplier.ModulesSupply, modulesAmount) } + collectedFees := k.fck.GetCollectedFees(ctx) + + expectedTotalSupply := circulatingAmount. + Add(vestingAmount). + Add(modulesAmount). + Add(collectedFees) + + realTotalSupply := k.TotalSupply(ctx) + + if !realTotalSupply.IsEqual(expectedTotalSupply) { + return fmt.Errorf("total supply invariance:\n"+ + "\texpected total supply: %v\n"+ + "\treal total supply: %v", expectedTotalSupply, realTotalSupply) + } + return nil } } - -// // SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations -// // nolint: unparam -// func SupplyInvariants( -// k Keeper, f FeeCollectionKeeper, -// d DistributionKeeper, am auth.AccountKeeper) sdk.Invariant { - -// return func(ctx sdk.Context) error { -// pool := k.GetPool(ctx) - -// loose := sdk.ZeroDec() -// bonded := sdk.ZeroDec() -// am.IterateAccounts(ctx, func(acc auth.Account) bool { -// loose = loose.Add(acc.GetCoins().AmountOf(k.BondDenom(ctx)).ToDec()) -// return false -// }) -// k.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) bool { -// for _, entry := range ubd.Entries { -// loose = loose.Add(entry.Balance.ToDec()) -// } -// return false -// }) -// k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool { -// switch validator.GetStatus() { -// case sdk.Bonded: -// bonded = bonded.Add(validator.GetBondedTokens().ToDec()) -// case sdk.Unbonding, sdk.Unbonded: -// loose = loose.Add(validator.GetTokens().ToDec()) -// } -// // add yet-to-be-withdrawn -// loose = loose.Add(d.GetValidatorOutstandingRewardsCoins(ctx, validator.GetOperator()).AmountOf(k.BondDenom(ctx))) -// return false -// }) - -// // add outstanding fees -// loose = loose.Add(f.GetCollectedFees(ctx).AmountOf(k.BondDenom(ctx)).ToDec()) - -// // add community pool -// loose = loose.Add(d.GetFeePoolCommunityCoins(ctx).AmountOf(k.BondDenom(ctx))) - -// // Not-bonded tokens should equal coin supply plus unbonding delegations -// // plus tokens on unbonded validators -// if !pool.NotBondedTokens.ToDec().Equal(loose) { -// return fmt.Errorf("loose token invariance:\n"+ -// "\tpool.NotBondedTokens: %v\n"+ -// "\tsum of account tokens: %v", pool.NotBondedTokens, loose) -// } - -// // Bonded tokens should equal sum of tokens with bonded validators -// if !pool.BondedTokens.ToDec().Equal(bonded) { -// return fmt.Errorf("bonded token invariance:\n"+ -// "\tpool.BondedTokens: %v\n"+ -// "\tsum of account tokens: %v", pool.BondedTokens, bonded) -// } - -// return nil -// } -// } diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index f2aaec9ac1b9..9d9c0851d6ce 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -11,15 +11,17 @@ type Keeper struct { cdc *codec.Codec storeKey sdk.StoreKey - sk StakingKeeper + sk StakingKeeper + fck FeeCollectionKeeper } // NewKeeper creates a new supply Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk StakingKeeper) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk StakingKeeper, fck FeeCollectionKeeper) Keeper { return Keeper{ cdc: cdc, storeKey: key, sk: sk, + fck: fck, } } @@ -50,11 +52,13 @@ func (k Keeper) InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coi } // TotalSupply returns the total supply of the network -// -// TODO: add unbonded +// total = circulating + vesting + modules + bonded supply + collected fees + rewards func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { supplier := k.GetSupplier(ctx) + supplierTotal := supplier.Total() // circulating + vesting + modules + bondedSupply := sdk.NewCoins(sdk.NewCoin(k.sk.BondDenom(ctx), k.sk.TotalBondedTokens(ctx))) - supplierTotal := supplier.Total() - return supplierTotal.Add(bondedSupply) + collectedFees := k.fck.GetCollectedFees(ctx) + + return supplierTotal.Add(bondedSupply).Add(collectedFees) } From d2c271e6ad0fb7c16607a67cb7ba8ab4b0b93b54 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 23 Apr 2019 21:32:32 +0200 Subject: [PATCH 26/46] more invariance and total supply --- x/staking/types/expected_keepers.go | 2 +- x/supply/keeper/expected_keepers.go | 7 ++++++- x/supply/keeper/invariants.go | 4 +++- x/supply/keeper/keeper.go | 14 +++++++++----- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index 2a2aff06046b..5b2fdcbfc0ec 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -2,7 +2,7 @@ package types import sdk "github.com/cosmos/cosmos-sdk/types" -// expected coin keeper +// DistributionKeeper defines the expected distribution keeper type DistributionKeeper interface { GetFeePoolCommunityCoins(ctx sdk.Context) sdk.DecCoins GetValidatorOutstandingRewardsCoins(ctx sdk.Context, val sdk.ValAddress) sdk.DecCoins diff --git a/x/supply/keeper/expected_keepers.go b/x/supply/keeper/expected_keepers.go index 7666c4b10f3c..8abbfc13bd64 100644 --- a/x/supply/keeper/expected_keepers.go +++ b/x/supply/keeper/expected_keepers.go @@ -2,11 +2,16 @@ package keeper import sdk "github.com/cosmos/cosmos-sdk/types" -// CrisisKeeper defunes the expected crisis keeper +// CrisisKeeper defines the expected crisis keeper type CrisisKeeper interface { RegisterRoute(moduleName, route string, invar sdk.Invariant) } +// DistributionKeeper defines the expected distribution keeper +type DistributionKeeper interface { + GetFeePoolCommunityCoins(ctx sdk.Context) sdk.DecCoins +} + // FeeCollectionKeeper defines the expected fee collection keeper type FeeCollectionKeeper interface { GetCollectedFees(ctx sdk.Context) sdk.Coins diff --git a/x/supply/keeper/invariants.go b/x/supply/keeper/invariants.go index 958795576d30..6d3ce107153b 100644 --- a/x/supply/keeper/invariants.go +++ b/x/supply/keeper/invariants.go @@ -72,11 +72,13 @@ func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { } collectedFees := k.fck.GetCollectedFees(ctx) + communityPool, _ := k.dk.GetFeePoolCommunityCoins(ctx).TruncateDecimal() expectedTotalSupply := circulatingAmount. Add(vestingAmount). Add(modulesAmount). - Add(collectedFees) + Add(collectedFees). + Add(communityPool) realTotalSupply := k.TotalSupply(ctx) diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 9d9c0851d6ce..3f16fd275d40 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -11,17 +11,20 @@ type Keeper struct { cdc *codec.Codec storeKey sdk.StoreKey - sk StakingKeeper + dk DistributionKeeper fck FeeCollectionKeeper + sk StakingKeeper } // NewKeeper creates a new supply Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk StakingKeeper, fck FeeCollectionKeeper) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, + dk DistributionKeeper, fck FeeCollectionKeeper, sk StakingKeeper) Keeper { return Keeper{ cdc: cdc, storeKey: key, - sk: sk, + dk: dk, fck: fck, + sk: sk, } } @@ -52,13 +55,14 @@ func (k Keeper) InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coi } // TotalSupply returns the total supply of the network -// total = circulating + vesting + modules + bonded supply + collected fees + rewards +// total = circulating + vesting + modules + bonded supply + collected fees + community pool func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { supplier := k.GetSupplier(ctx) supplierTotal := supplier.Total() // circulating + vesting + modules bondedSupply := sdk.NewCoins(sdk.NewCoin(k.sk.BondDenom(ctx), k.sk.TotalBondedTokens(ctx))) collectedFees := k.fck.GetCollectedFees(ctx) + communityPool, _ := k.dk.GetFeePoolCommunityCoins(ctx).TruncateDecimal() - return supplierTotal.Add(bondedSupply).Add(collectedFees) + return supplierTotal.Add(bondedSupply).Add(collectedFees).Add(communityPool) } From a22bccac4ea6c4b8dbf57208cade06767728c983 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 23 Apr 2019 22:41:14 +0200 Subject: [PATCH 27/46] add rewards to total supply --- x/distribution/keeper/keeper.go | 11 +++++++++++ x/supply/keeper/expected_keepers.go | 1 + x/supply/keeper/keeper.go | 7 ++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 2d1439dca0f8..2e31a2970d45 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -96,3 +96,14 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr return nil } + +// GetTotalRewards returns the total amount of fee distribution rewards held in the store +func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) { + k.IterateValidatorOutstandingRewards(ctx, + func(valAddr sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { + totalRewards = totalRewards.Add(rewards) + return false + }, + ) + return totalRewards +} diff --git a/x/supply/keeper/expected_keepers.go b/x/supply/keeper/expected_keepers.go index 8abbfc13bd64..f4cfc5276c21 100644 --- a/x/supply/keeper/expected_keepers.go +++ b/x/supply/keeper/expected_keepers.go @@ -10,6 +10,7 @@ type CrisisKeeper interface { // DistributionKeeper defines the expected distribution keeper type DistributionKeeper interface { GetFeePoolCommunityCoins(ctx sdk.Context) sdk.DecCoins + GetTotalRewards(ctx sdk.Context) sdk.DecCoins } // FeeCollectionKeeper defines the expected fee collection keeper diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 3f16fd275d40..7011d642612c 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -63,6 +63,11 @@ func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { bondedSupply := sdk.NewCoins(sdk.NewCoin(k.sk.BondDenom(ctx), k.sk.TotalBondedTokens(ctx))) collectedFees := k.fck.GetCollectedFees(ctx) communityPool, _ := k.dk.GetFeePoolCommunityCoins(ctx).TruncateDecimal() + totalRewards, _ := k.dk.GetTotalRewards(ctx).TruncateDecimal() - return supplierTotal.Add(bondedSupply).Add(collectedFees).Add(communityPool) + return supplierTotal. + Add(bondedSupply). + Add(collectedFees). + Add(communityPool). + Add(totalRewards) } From b93fc11d94a35b9a490f56cbc1ee247a8f69f103 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 23 Apr 2019 22:44:29 +0200 Subject: [PATCH 28/46] add remaining --- x/supply/keeper/keeper.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 7011d642612c..68c96135f81c 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -62,12 +62,14 @@ func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { bondedSupply := sdk.NewCoins(sdk.NewCoin(k.sk.BondDenom(ctx), k.sk.TotalBondedTokens(ctx))) collectedFees := k.fck.GetCollectedFees(ctx) - communityPool, _ := k.dk.GetFeePoolCommunityCoins(ctx).TruncateDecimal() - totalRewards, _ := k.dk.GetTotalRewards(ctx).TruncateDecimal() + communityPool, remainingCommunityPool := k.dk.GetFeePoolCommunityCoins(ctx).TruncateDecimal() + totalRewards, remainingRewards := k.dk.GetTotalRewards(ctx).TruncateDecimal() + remaining, _ := remainingCommunityPool.Add(remainingRewards).TruncateDecimal() return supplierTotal. Add(bondedSupply). Add(collectedFees). Add(communityPool). - Add(totalRewards) + Add(totalRewards). + Add(remaining) } From 021e6c9e589cc851a186ce4a741a8900caeb945f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 24 Apr 2019 11:08:35 +0200 Subject: [PATCH 29/46] total supply invariant --- x/supply/keeper/invariants.go | 15 +++------------ x/supply/keeper/keeper.go | 19 ++++++++++++++----- x/supply/types/supplier.go | 35 ++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/x/supply/keeper/invariants.go b/x/supply/keeper/invariants.go index 6d3ce107153b..b2fdba07c1f1 100644 --- a/x/supply/keeper/invariants.go +++ b/x/supply/keeper/invariants.go @@ -71,21 +71,12 @@ func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { "\tsum of modules accounts tokens: %v", supplier.ModulesSupply, modulesAmount) } - collectedFees := k.fck.GetCollectedFees(ctx) - communityPool, _ := k.dk.GetFeePoolCommunityCoins(ctx).TruncateDecimal() + expectedTotalSupply := k.TotalSupply(ctx) - expectedTotalSupply := circulatingAmount. - Add(vestingAmount). - Add(modulesAmount). - Add(collectedFees). - Add(communityPool) - - realTotalSupply := k.TotalSupply(ctx) - - if !realTotalSupply.IsEqual(expectedTotalSupply) { + if !supplier.TotalSupply.IsEqual(expectedTotalSupply) { return fmt.Errorf("total supply invariance:\n"+ "\texpected total supply: %v\n"+ - "\treal total supply: %v", expectedTotalSupply, realTotalSupply) + "\treal total supply: %v", expectedTotalSupply, supplier.TotalSupply) } return nil diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 68c96135f81c..29e9d9752264 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -46,7 +46,7 @@ func (k Keeper) SetSupplier(ctx sdk.Context, supplier types.Supplier) { store.Set(supplierKey, b) } -// InflateSupply adds tokens to the circulating supply +// InflateSupply adds tokens to the supplier func (k Keeper) InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) { supplier := k.GetSupplier(ctx) supplier.Inflate(supplyType, amount) @@ -54,11 +54,18 @@ func (k Keeper) InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coi k.SetSupplier(ctx, supplier) } -// TotalSupply returns the total supply of the network -// total = circulating + vesting + modules + bonded supply + collected fees + community pool +// DeflateSupply subtracts tokens to the suplier +func (k Keeper) DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) { + supplier := k.GetSupplier(ctx) + supplier.Deflate(supplyType, amount) + + k.SetSupplier(ctx, supplier) +} + +// TotalSupply returns the total supply of the network. Used only for invariance +// total supply = circulating + vesting + modules + bonded supply + collected fees + community pool func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { supplier := k.GetSupplier(ctx) - supplierTotal := supplier.Total() // circulating + vesting + modules bondedSupply := sdk.NewCoins(sdk.NewCoin(k.sk.BondDenom(ctx), k.sk.TotalBondedTokens(ctx))) collectedFees := k.fck.GetCollectedFees(ctx) @@ -66,7 +73,9 @@ func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { totalRewards, remainingRewards := k.dk.GetTotalRewards(ctx).TruncateDecimal() remaining, _ := remainingCommunityPool.Add(remainingRewards).TruncateDecimal() - return supplierTotal. + return supplier.CirculatingSupply. + Add(supplier.VestingSupply). + Add(supplier.ModulesSupply). Add(bondedSupply). Add(collectedFees). Add(communityPool). diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index ff96f13402ed..4959bc729fc3 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -18,22 +18,24 @@ type Supplier struct { CirculatingSupply sdk.Coins `json:"circulating_supply"` // supply held by accounts that's not vesting VestingSupply sdk.Coins `json:"vesting_supply"` // locked supply held by vesting accounts ModulesSupply sdk.Coins `json:"modules_supply"` // supply held by modules acccounts + TotalSupply sdk.Coins `json:"total_supply"` // supply held by modules acccounts } // NewSupplier creates a new Supplier instance -func NewSupplier(circulating, vesting, modules sdk.Coins) Supplier { +func NewSupplier(circulating, vesting, modules, total sdk.Coins) Supplier { return Supplier{ CirculatingSupply: circulating, VestingSupply: vesting, ModulesSupply: modules, + TotalSupply: total, } } // DefaultSupplier creates an empty Supplier func DefaultSupplier() Supplier { - return NewSupplier(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) + return NewSupplier(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) } // Inflate adds coins to a given supply type and updates the total supply @@ -52,6 +54,8 @@ func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { default: panic(fmt.Errorf("invalid type %s", supplyType)) } + + supplier.TotalSupply = supplier.TotalSupply.Add(amount) } // Deflate safe subtracts coins for a given supply and updates the total supply @@ -92,6 +96,15 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { default: panic(fmt.Errorf("invalid type %s", supplyType)) } + + newSupply, ok := supplier.TotalSupply.SafeSub(amount) + if !ok { + panic(fmt.Sprintf( + "total supply should be greater than given amount: %s < %s", + supplier.TotalSupply.String(), amount.String(), + )) + } + supplier.TotalSupply = newSupply } // CirculatingAmountOf returns the circulating supply of a coin denomination @@ -112,20 +125,10 @@ func (supplier Supplier) ModulesAmountOf(denom string) sdk.Int { return supplier.ModulesSupply.AmountOf(denom) } -// Total returns the sum of circulating, vesting and modules supply -func (supplier Supplier) Total() sdk.Coins { - - return supplier.CirculatingSupply. - Add(supplier.VestingSupply). - Add(supplier.ModulesSupply) -} - // TotalAmountOf returns the sum of circulating, vesting and modules supply for a specific coin denomination func (supplier Supplier) TotalAmountOf(denom string) sdk.Int { - return supplier.ModulesAmountOf(denom). - Add(supplier.VestingAmountOf(denom)). - Add(supplier.ModulesAmountOf(denom)) + return supplier.TotalSupply.AmountOf(denom) } // ValidateBasic validates the Supply coins and returns error if invalid @@ -155,8 +158,10 @@ func (supplier Supplier) String() string { return fmt.Sprintf(`Supplier: Circulating Supply: %s Vesting Supply: %s - Modules Supply: %s`, + Modules Supply: %s + Total Supply: %s`, supplier.CirculatingSupply.String(), supplier.VestingSupply.String(), - supplier.ModulesSupply.String()) + supplier.ModulesSupply.String(), + supplier.TotalSupply.String()) } From 669160a5406233810699b97141ff1d4d9ff01ca6 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 24 Apr 2019 11:49:11 +0200 Subject: [PATCH 30/46] clean up mint --- x/mint/abci_app.go | 3 +- x/mint/genesis.go | 54 +++----------- x/mint/keeper.go | 97 ------------------------- x/mint/{ => keeper}/expected_keepers.go | 2 +- x/mint/keeper/keeper.go | 52 +++++++++++++ x/mint/keeper/key.go | 23 ++++++ x/mint/keeper/params.go | 26 +++++++ x/mint/{ => keeper}/querier.go | 2 +- x/mint/{ => keeper}/querier_test.go | 5 +- x/mint/{ => keeper}/test_common.go | 2 +- x/mint/types/genesis.go | 37 ++++++++++ x/mint/{ => types}/minter.go | 2 +- x/mint/{ => types}/minter_test.go | 2 +- x/mint/{ => types}/params.go | 2 +- 14 files changed, 159 insertions(+), 150 deletions(-) delete mode 100644 x/mint/keeper.go rename x/mint/{ => keeper}/expected_keepers.go (97%) create mode 100644 x/mint/keeper/keeper.go create mode 100644 x/mint/keeper/key.go create mode 100644 x/mint/keeper/params.go rename x/mint/{ => keeper}/querier.go (99%) rename x/mint/{ => keeper}/querier_test.go (95%) rename x/mint/{ => keeper}/test_common.go (99%) create mode 100644 x/mint/types/genesis.go rename x/mint/{ => types}/minter.go (99%) rename x/mint/{ => types}/minter_test.go (99%) rename x/mint/{ => types}/params.go (99%) diff --git a/x/mint/abci_app.go b/x/mint/abci_app.go index 0b47881400ee..09873dab8a83 100644 --- a/x/mint/abci_app.go +++ b/x/mint/abci_app.go @@ -2,10 +2,11 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/mint/keeper" ) // BeginBlocker inflates every block and updates inflation parameters once per hour -func BeginBlocker(ctx sdk.Context, k Keeper) { +func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { // fetch stored minter & params minter := k.GetMinter(ctx) diff --git a/x/mint/genesis.go b/x/mint/genesis.go index 11f96c6f90bb..e137ffae8176 100644 --- a/x/mint/genesis.go +++ b/x/mint/genesis.go @@ -2,54 +2,20 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/mint/keeper" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) -// GenesisState - minter state -type GenesisState struct { - Minter Minter `json:"minter"` // minter object - Params Params `json:"params"` // inflation params -} - -// NewGenesisState creates a new GenesisState object -func NewGenesisState(minter Minter, params Params) GenesisState { - return GenesisState{ - Minter: minter, - Params: params, - } -} - -// DefaultGenesisState creates a default GenesisState object -func DefaultGenesisState() GenesisState { - return GenesisState{ - Minter: DefaultInitialMinter(), - Params: DefaultParams(), - } -} - -// new mint genesis -func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { - keeper.SetMinter(ctx, data.Minter) - keeper.SetParams(ctx, data.Params) +// InitGenesis new mint genesis +func InitGenesis(ctx sdk.Context, k keeper.Keeper, data types.GenesisState) { + k.SetMinter(ctx, data.Minter) + k.SetParams(ctx, data.Params) } // ExportGenesis returns a GenesisState for a given context and keeper. -func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { - - minter := keeper.GetMinter(ctx) - params := keeper.GetParams(ctx) - return NewGenesisState(minter, params) -} +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { -// ValidateGenesis validates the provided genesis state to ensure the -// expected invariants holds. -func ValidateGenesis(data GenesisState) error { - err := validateParams(data.Params) - if err != nil { - return err - } - err = validateMinter(data.Minter) - if err != nil { - return err - } - return nil + minter := k.GetMinter(ctx) + params := k.GetParams(ctx) + return types.NewGenesisState(minter, params) } diff --git a/x/mint/keeper.go b/x/mint/keeper.go deleted file mode 100644 index 5a9fa2857772..000000000000 --- a/x/mint/keeper.go +++ /dev/null @@ -1,97 +0,0 @@ -package mint - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" -) - -const ( - // ModuleName is the name of the module - ModuleName = "minting" - - // default paramspace for params keeper - DefaultParamspace = "mint" - - // StoreKey is the default store key for mint - StoreKey = "mint" - - // QuerierRoute is the querier route for the minting store. - QuerierRoute = StoreKey -) - -// Keeper defines the keeper of the minting store -type Keeper struct { - storeKey sdk.StoreKey - cdc *codec.Codec - paramSpace params.Subspace - supplyKeeper SupplyKeeper - sk StakingKeeper - fck FeeCollectionKeeper -} - -// NewKeeper creates a new mint Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, - paramSpace params.Subspace, supplyKeeper SupplyKeeper, sk StakingKeeper, fck FeeCollectionKeeper) Keeper { - - keeper := Keeper{ - storeKey: key, - cdc: cdc, - paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), - supplyKeeper: supplyKeeper, - sk: sk, - fck: fck, - } - return keeper -} - -//____________________________________________________________________ -// Keys - -var ( - minterKey = []byte{0x00} // the one key to use for the keeper store - - // params store for inflation params - ParamStoreKeyParams = []byte("params") -) - -// ParamKeyTable for minting module -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - ParamStoreKeyParams, Params{}, - ) -} - -//______________________________________________________________________ - -// get the minter -func (k Keeper) GetMinter(ctx sdk.Context) (minter Minter) { - store := ctx.KVStore(k.storeKey) - b := store.Get(minterKey) - if b == nil { - panic("Stored minter should not have been nil") - } - k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &minter) - return -} - -// set the minter -func (k Keeper) SetMinter(ctx sdk.Context, minter Minter) { - store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinaryLengthPrefixed(minter) - store.Set(minterKey, b) -} - -//______________________________________________________________________ - -// get inflation params from the global param store -func (k Keeper) GetParams(ctx sdk.Context) Params { - var params Params - k.paramSpace.Get(ctx, ParamStoreKeyParams, ¶ms) - return params -} - -// set inflation params from the global param store -func (k Keeper) SetParams(ctx sdk.Context, params Params) { - k.paramSpace.Set(ctx, ParamStoreKeyParams, ¶ms) -} diff --git a/x/mint/expected_keepers.go b/x/mint/keeper/expected_keepers.go similarity index 97% rename from x/mint/expected_keepers.go rename to x/mint/keeper/expected_keepers.go index 30e95dfcc030..81554f830936 100644 --- a/x/mint/expected_keepers.go +++ b/x/mint/keeper/expected_keepers.go @@ -1,4 +1,4 @@ -package mint +package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go new file mode 100644 index 000000000000..52c2d7949862 --- /dev/null +++ b/x/mint/keeper/keeper.go @@ -0,0 +1,52 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/params" +) + +// Keeper defines the keeper of the minting store +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + paramSpace params.Subspace + supplyKeeper SupplyKeeper + sk StakingKeeper + fck FeeCollectionKeeper +} + +// NewKeeper creates a new mint Keeper instance +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, + paramSpace params.Subspace, supplyKeeper SupplyKeeper, sk StakingKeeper, fck FeeCollectionKeeper) Keeper { + + keeper := Keeper{ + storeKey: key, + cdc: cdc, + paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), + supplyKeeper: supplyKeeper, + sk: sk, + fck: fck, + } + return keeper +} + +// get the minter +func (k Keeper) GetMinter(ctx sdk.Context) (minter types.Minter) { + store := ctx.KVStore(k.storeKey) + b := store.Get(minterKey) + if b == nil { + panic("Stored minter should not have been nil") + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &minter) + return +} + +// set the minter +func (k Keeper) SetMinter(ctx sdk.Context, minter types.Minter) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshalBinaryLengthPrefixed(minter) + store.Set(minterKey, b) +} diff --git a/x/mint/keeper/key.go b/x/mint/keeper/key.go new file mode 100644 index 000000000000..6bdf187e5d48 --- /dev/null +++ b/x/mint/keeper/key.go @@ -0,0 +1,23 @@ +// nolint +package keeper + +const ( + // ModuleName is the name of the module + ModuleName = "minting" + + // default paramspace for params keeper + DefaultParamspace = "mint" + + // StoreKey is the default store key for mint + StoreKey = "mint" + + // QuerierRoute is the querier route for the minting store. + QuerierRoute = StoreKey +) + +var ( + minterKey = []byte{0x00} // the one key to use for the keeper store + + // params store for inflation params + ParamStoreKeyParams = []byte("params") +) diff --git a/x/mint/keeper/params.go b/x/mint/keeper/params.go new file mode 100644 index 000000000000..1159f87951e1 --- /dev/null +++ b/x/mint/keeper/params.go @@ -0,0 +1,26 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/params" +) + +// ParamKeyTable for minting module +func ParamKeyTable() params.KeyTable { + return params.NewKeyTable( + ParamStoreKeyParams, types.Params{}, + ) +} + +// get inflation params from the global param store +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramSpace.Get(ctx, ParamStoreKeyParams, ¶ms) + return params +} + +// set inflation params from the global param store +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.Set(ctx, ParamStoreKeyParams, ¶ms) +} diff --git a/x/mint/querier.go b/x/mint/keeper/querier.go similarity index 99% rename from x/mint/querier.go rename to x/mint/keeper/querier.go index 4de3fdeeb526..b3265db839a6 100644 --- a/x/mint/querier.go +++ b/x/mint/keeper/querier.go @@ -1,4 +1,4 @@ -package mint +package keeper import ( "fmt" diff --git a/x/mint/querier_test.go b/x/mint/keeper/querier_test.go similarity index 95% rename from x/mint/querier_test.go rename to x/mint/keeper/querier_test.go index 7a73853d0a6d..469d773c15ee 100644 --- a/x/mint/querier_test.go +++ b/x/mint/keeper/querier_test.go @@ -1,4 +1,4 @@ -package mint +package keeper import ( "testing" @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" abci "github.com/tendermint/tendermint/abci/types" ) @@ -35,7 +36,7 @@ func TestNewQuerier(t *testing.T) { func TestQueryParams(t *testing.T) { input := newTestInput(t) - var params Params + var params types.Params res, sdkErr := queryParams(input.ctx, input.mintKeeper) require.NoError(t, sdkErr) diff --git a/x/mint/test_common.go b/x/mint/keeper/test_common.go similarity index 99% rename from x/mint/test_common.go rename to x/mint/keeper/test_common.go index edd561d97d04..f6b49c6cb93b 100644 --- a/x/mint/test_common.go +++ b/x/mint/keeper/test_common.go @@ -1,4 +1,4 @@ -package mint +package keeper import ( "os" diff --git a/x/mint/types/genesis.go b/x/mint/types/genesis.go new file mode 100644 index 000000000000..d2fb3af5ecb2 --- /dev/null +++ b/x/mint/types/genesis.go @@ -0,0 +1,37 @@ +package types + +// GenesisState - minter state +type GenesisState struct { + Minter Minter `json:"minter"` // minter object + Params Params `json:"params"` // inflation params +} + +// NewGenesisState creates a new GenesisState object +func NewGenesisState(minter Minter, params Params) GenesisState { + return GenesisState{ + Minter: minter, + Params: params, + } +} + +// DefaultGenesisState creates a default GenesisState object +func DefaultGenesisState() GenesisState { + return GenesisState{ + Minter: DefaultInitialMinter(), + Params: DefaultParams(), + } +} + +// ValidateGenesis validates the provided genesis state to ensure the +// expected invariants holds. +func ValidateGenesis(data GenesisState) error { + err := validateParams(data.Params) + if err != nil { + return err + } + err = validateMinter(data.Minter) + if err != nil { + return err + } + return nil +} diff --git a/x/mint/minter.go b/x/mint/types/minter.go similarity index 99% rename from x/mint/minter.go rename to x/mint/types/minter.go index eff30785faf1..c733cfdfd676 100644 --- a/x/mint/minter.go +++ b/x/mint/types/minter.go @@ -1,4 +1,4 @@ -package mint +package types import ( "fmt" diff --git a/x/mint/minter_test.go b/x/mint/types/minter_test.go similarity index 99% rename from x/mint/minter_test.go rename to x/mint/types/minter_test.go index 0245c71972fb..8760a66f4466 100644 --- a/x/mint/minter_test.go +++ b/x/mint/types/minter_test.go @@ -1,4 +1,4 @@ -package mint +package types import ( "math/rand" diff --git a/x/mint/params.go b/x/mint/types/params.go similarity index 99% rename from x/mint/params.go rename to x/mint/types/params.go index f1bd7e37d944..32a32fcb1ac2 100644 --- a/x/mint/params.go +++ b/x/mint/types/params.go @@ -1,4 +1,4 @@ -package mint +package types import ( "fmt" From 895ce15d37bf857508e052d0711e811c9e87c2b1 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 24 Apr 2019 11:51:46 +0200 Subject: [PATCH 31/46] update module client --- x/mint/client/cli/query.go | 11 ++++++----- x/mint/client/module_client.go | 6 +++--- x/mint/client/rest/query.go | 8 ++++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/x/mint/client/cli/query.go b/x/mint/client/cli/query.go index 65bde6adeb32..40aad8f628d0 100644 --- a/x/mint/client/cli/query.go +++ b/x/mint/client/cli/query.go @@ -8,7 +8,8 @@ import ( "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/x/mint" + "github.com/cosmos/cosmos-sdk/x/mint/keeper" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // GetCmdQueryParams implements a command to return the current minting @@ -21,13 +22,13 @@ func GetCmdQueryParams(cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - route := fmt.Sprintf("custom/%s/%s", mint.QuerierRoute, mint.QueryParameters) + route := fmt.Sprintf("custom/%s/%s", keeper.QuerierRoute, keeper.QueryParameters) res, err := cliCtx.QueryWithData(route, nil) if err != nil { return err } - var params mint.Params + var params types.Params if err := cdc.UnmarshalJSON(res, ¶ms); err != nil { return err } @@ -47,7 +48,7 @@ func GetCmdQueryInflation(cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - route := fmt.Sprintf("custom/%s/%s", mint.QuerierRoute, mint.QueryInflation) + route := fmt.Sprintf("custom/%s/%s", keeper.QuerierRoute, keeper.QueryInflation) res, err := cliCtx.QueryWithData(route, nil) if err != nil { return err @@ -73,7 +74,7 @@ func GetCmdQueryAnnualProvisions(cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - route := fmt.Sprintf("custom/%s/%s", mint.QuerierRoute, mint.QueryAnnualProvisions) + route := fmt.Sprintf("custom/%s/%s", keeper.QuerierRoute, keeper.QueryAnnualProvisions) res, err := cliCtx.QueryWithData(route, nil) if err != nil { return err diff --git a/x/mint/client/module_client.go b/x/mint/client/module_client.go index 54ccea835105..d1db4fa478be 100644 --- a/x/mint/client/module_client.go +++ b/x/mint/client/module_client.go @@ -5,8 +5,8 @@ import ( amino "github.com/tendermint/go-amino" sdkclient "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/mint/client/cli" + "github.com/cosmos/cosmos-sdk/x/mint/keeper" ) // ModuleClient exports all CLI client functionality from the minting module. @@ -22,7 +22,7 @@ func NewModuleClient(storeKey string, cdc *amino.Codec) ModuleClient { // GetQueryCmd returns the cli query commands for the minting module. func (mc ModuleClient) GetQueryCmd() *cobra.Command { mintingQueryCmd := &cobra.Command{ - Use: mint.ModuleName, + Use: keeper.ModuleName, Short: "Querying commands for the minting module", } @@ -40,7 +40,7 @@ func (mc ModuleClient) GetQueryCmd() *cobra.Command { // GetTxCmd returns the transaction commands for the minting module. func (mc ModuleClient) GetTxCmd() *cobra.Command { mintTxCmd := &cobra.Command{ - Use: mint.ModuleName, + Use: keeper.ModuleName, Short: "Minting transaction subcommands", } diff --git a/x/mint/client/rest/query.go b/x/mint/client/rest/query.go index 2d3cd4a0fea0..e516f2155aa9 100644 --- a/x/mint/client/rest/query.go +++ b/x/mint/client/rest/query.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/mint/keeper" ) func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) { @@ -31,7 +31,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co func queryParamsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - route := fmt.Sprintf("custom/%s/%s", mint.QuerierRoute, mint.QueryParameters) + route := fmt.Sprintf("custom/%s/%s", keeper.QuerierRoute, keeper.QueryParameters) res, err := cliCtx.QueryWithData(route, nil) if err != nil { @@ -45,7 +45,7 @@ func queryParamsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Hand func queryInflationHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - route := fmt.Sprintf("custom/%s/%s", mint.QuerierRoute, mint.QueryInflation) + route := fmt.Sprintf("custom/%s/%s", keeper.QuerierRoute, keeper.QueryInflation) res, err := cliCtx.QueryWithData(route, nil) if err != nil { @@ -59,7 +59,7 @@ func queryInflationHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.H func queryAnnualProvisionsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - route := fmt.Sprintf("custom/%s/%s", mint.QuerierRoute, mint.QueryAnnualProvisions) + route := fmt.Sprintf("custom/%s/%s", keeper.QuerierRoute, keeper.QueryAnnualProvisions) res, err := cliCtx.QueryWithData(route, nil) if err != nil { From 365f9dfe429515327eef845b06d4568a8781f975 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 24 Apr 2019 13:16:34 +0200 Subject: [PATCH 32/46] update supply on withdrawal --- x/distribution/keeper/delegation.go | 5 ++++- x/distribution/keeper/expected_keepers.go | 10 +++++++++ x/distribution/keeper/keeper.go | 8 +++++-- x/mint/abci_app.go | 11 +++++---- x/supply/alias.go | 1 + x/supply/keeper/keeper.go | 6 ++--- x/supply/types/supplier.go | 27 +++++++++++++---------- 7 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 x/distribution/keeper/expected_keepers.go diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 20321e870a63..14f512e7c255 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/supply" ) // initialize starting info for a new delegation @@ -115,7 +116,7 @@ func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val sdk.Validator, d return rewards } -func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val sdk.Validator, del sdk.Delegation) sdk.Error { +func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val sdk.Validator, del sdk.Delegation) (err sdk.Error) { // check existence of delegator starting info if !k.HasDelegatorStartingInfo(ctx, del.GetValidatorAddr(), del.GetDelegatorAddr()) { @@ -156,6 +157,8 @@ func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val sdk.Validator, de if _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, coins); err != nil { return err } + + k.supplyKeeper.InflateSupply(ctx, supply.TypeCirculating, coins) } // remove delegator starting info diff --git a/x/distribution/keeper/expected_keepers.go b/x/distribution/keeper/expected_keepers.go new file mode 100644 index 000000000000..6d978ba92616 --- /dev/null +++ b/x/distribution/keeper/expected_keepers.go @@ -0,0 +1,10 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// SupplyKeeper expected supply keeper +type SupplyKeeper interface { + InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) +} diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 58646e04b026..36f9776e323f 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/supply" "github.com/tendermint/tendermint/libs/log" ) @@ -17,6 +18,7 @@ type Keeper struct { bankKeeper types.BankKeeper stakingKeeper types.StakingKeeper feeCollectionKeeper types.FeeCollectionKeeper + supplyKeeper SupplyKeeper // codespace codespace sdk.CodespaceType @@ -24,7 +26,7 @@ type Keeper struct { // create a new keeper func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, ck types.BankKeeper, - sk types.StakingKeeper, fck types.FeeCollectionKeeper, codespace sdk.CodespaceType) Keeper { + sk types.StakingKeeper, fck types.FeeCollectionKeeper, supplyKeeper SupplyKeeper, codespace sdk.CodespaceType) Keeper { keeper := Keeper{ storeKey: key, cdc: cdc, @@ -32,6 +34,7 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, c bankKeeper: ck, stakingKeeper: sk, feeCollectionKeeper: fck, + supplyKeeper: supplyKeeper, codespace: codespace, } return keeper @@ -70,7 +73,6 @@ func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddres // reinitialize the delegation k.initializeDelegation(ctx, valAddr, delAddr) - return nil } @@ -97,6 +99,8 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr if _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, coins); err != nil { return err } + + k.supplyKeeper.InflateSupply(ctx, supply.TypeCirculating, coins) } return nil diff --git a/x/mint/abci_app.go b/x/mint/abci_app.go index 09873dab8a83..b915c3812bc2 100644 --- a/x/mint/abci_app.go +++ b/x/mint/abci_app.go @@ -3,6 +3,7 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/mint/keeper" + "github.com/cosmos/cosmos-sdk/x/supply" ) // BeginBlocker inflates every block and updates inflation parameters once per hour @@ -18,9 +19,11 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { minter.AnnualProvisions = minter.NextAnnualProvisions(params, k.sk.StakingTokenSupply(ctx)) k.SetMinter(ctx, minter) - // mint coins, add to collected fees, update supply + // mint coins, add to collected fees, update supply by adding it to the fee collector mintedCoin := minter.BlockProvision(params) - k.fck.AddCollectedFees(ctx, sdk.Coins{mintedCoin}) - k.supplyKeeper.InflateSupply(ctx, sdk.Coins{mintedCoin}) - k.sk.InflateNotBondedTokenSupply(ctx, mintedCoin.Amount) // TODO: verify invariance with bank bond denom supply + k.fck.AddCollectedFees(ctx, sdk.NewCoins(mintedCoin)) + + // // passively keep track of the total and the not bonded supply + k.supplyKeeper.InflateSupply(ctx, supply.TypeTotal, sdk.NewCoins(mintedCoin)) + k.sk.InflateNotBondedTokenSupply(ctx, mintedCoin.Amount) } diff --git a/x/supply/alias.go b/x/supply/alias.go index 699c01266b41..cf9cdaf4e068 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -22,4 +22,5 @@ const ( TypeCirculating = types.TypeCirculating TypeVesting = types.TypeVesting TypeModules = types.TypeModules + TypeTotal = types.TypeTotal ) diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 29e9d9752264..8039ceb9d89c 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -63,11 +63,12 @@ func (k Keeper) DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coi } // TotalSupply returns the total supply of the network. Used only for invariance -// total supply = circulating + vesting + modules + bonded supply + collected fees + community pool +// total supply = circulating + vesting + modules + collected fees + community pool +// +// NOTE: the staking pool's bonded supply is already considered as it's added to the collected fees on minting func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { supplier := k.GetSupplier(ctx) - bondedSupply := sdk.NewCoins(sdk.NewCoin(k.sk.BondDenom(ctx), k.sk.TotalBondedTokens(ctx))) collectedFees := k.fck.GetCollectedFees(ctx) communityPool, remainingCommunityPool := k.dk.GetFeePoolCommunityCoins(ctx).TruncateDecimal() totalRewards, remainingRewards := k.dk.GetTotalRewards(ctx).TruncateDecimal() @@ -76,7 +77,6 @@ func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { return supplier.CirculatingSupply. Add(supplier.VestingSupply). Add(supplier.ModulesSupply). - Add(bondedSupply). Add(collectedFees). Add(communityPool). Add(totalRewards). diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 4959bc729fc3..7ea0194fdb40 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -6,11 +6,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// define consts for inflation +// define constants for inflation const ( TypeCirculating = "circulating" TypeVesting = "vesting" TypeModules = "modules" + TypeTotal = "total" ) // Supplier represents a struct that passively keeps track of the total supply amounts in the network @@ -51,11 +52,12 @@ func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { case TypeModules: supplier.ModulesSupply = supplier.ModulesSupply.Add(amount) + case TypeTotal: + supplier.TotalSupply = supplier.TotalSupply.Add(amount) + default: panic(fmt.Errorf("invalid type %s", supplyType)) } - - supplier.TotalSupply = supplier.TotalSupply.Add(amount) } // Deflate safe subtracts coins for a given supply and updates the total supply @@ -93,18 +95,19 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { } supplier.ModulesSupply = newSupply + case TypeTotal: + newSupply, ok := supplier.TotalSupply.SafeSub(amount) + if !ok { + panic(fmt.Sprintf( + "total supply should be greater than given amount: %s < %s", + supplier.TotalSupply.String(), amount.String(), + )) + } + supplier.TotalSupply = newSupply + default: panic(fmt.Errorf("invalid type %s", supplyType)) } - - newSupply, ok := supplier.TotalSupply.SafeSub(amount) - if !ok { - panic(fmt.Sprintf( - "total supply should be greater than given amount: %s < %s", - supplier.TotalSupply.String(), amount.String(), - )) - } - supplier.TotalSupply = newSupply } // CirculatingAmountOf returns the circulating supply of a coin denomination From 896b295d50e0d1df5cb914adf4a5ae617c526d4b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 24 Apr 2019 13:16:58 +0200 Subject: [PATCH 33/46] update supply on deposits --- x/gov/expected_keepers.go | 3 ++- x/gov/keeper.go | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/x/gov/expected_keepers.go b/x/gov/expected_keepers.go index a0103cf8cdee..4009d8e34a69 100644 --- a/x/gov/expected_keepers.go +++ b/x/gov/expected_keepers.go @@ -14,11 +14,12 @@ type AccountKeeper interface { // BankKeeper defines the expected bank keeper type BankKeeper interface { GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - AddCoins(tx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) + AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) } // SupplyKeeper defines the expected supply keeper type SupplyKeeper interface { InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) + DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) } diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 0cf17ae4ea1b..c43febc1cf73 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -1,11 +1,13 @@ package gov import ( + "log" "time" codec "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/supply" ) // Governance Keeper @@ -22,6 +24,9 @@ type Keeper struct { // The reference to the AccountKeeper to create a module account ak AccountKeeper + // The reference to the SupplyKeeper to update module and circulating supply + supplyKeeper SupplyKeeper + // The ValidatorSet to get information about validators vs sdk.ValidatorSet @@ -46,13 +51,15 @@ type Keeper struct { // CONTRACT: Token Holder needs to be added into the bank keeper before calling // this function func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, - paramSpace params.Subspace, bk BankKeeper, ak AccountKeeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { + paramSpace params.Subspace, bk BankKeeper, ak AccountKeeper, + supplyKeeper SupplyKeeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { return Keeper{ storeKey: key, paramsKeeper: paramsKeeper, paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), ck: bk, ak: ak, + supplyKeeper: supplyKeeper, ds: ds, vs: ds.GetValidatorSet(), cdc: cdc, @@ -357,6 +364,10 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd return err, false } + // update the supply + keeper.supplyKeeper.InflateSupply(ctx, supply.TypeModules, depositAmount) + keeper.supplyKeeper.DeflateSupply(ctx, supply.TypeCirculating, depositAmount) + // Update proposal proposal.TotalDeposit = proposal.TotalDeposit.Add(depositAmount) keeper.SetProposal(ctx, proposal) @@ -408,6 +419,10 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { panic(err) } + // update the supply + keeper.supplyKeeper.InflateSupply(ctx, supply.TypeCirculating, deposit.Amount) + keeper.supplyKeeper.DeflateSupply(ctx, supply.TypeModules, deposit.Amount) + store.Delete(depositsIterator.Key()) } } @@ -428,6 +443,10 @@ func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { panic(err) } + // update the supply + keeper.supplyKeeper.DeflateSupply(ctx, supply.TypeModules, deposit.Amount) + keeper.supplyKeeper.DeflateSupply(ctx, supply.TypeTotal, deposit.Amount) + store.Delete(depositsIterator.Key()) } } From bcdc20ab3d9beb351da029b22b54fc69d79177fd Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 24 Apr 2019 17:39:01 +0200 Subject: [PATCH 34/46] change vesting supply to initial vesting --- cmd/gaia/app/genesis.go | 30 ++++++++++++++++++-------- x/bank/keeper.go | 23 -------------------- x/supply/keeper/invariants.go | 17 ++++----------- x/supply/keeper/keeper.go | 3 +-- x/supply/types/supplier.go | 40 +++++++++++++---------------------- 5 files changed, 41 insertions(+), 72 deletions(-) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index e9aa3957d3e2..735f20cdc3cc 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -222,7 +222,7 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } notBondedSupply, bondedSupply := - updateSupply(genesisState.Accounts, genesisState.StakingData.Params.BondDenom, &genesisState.SupplyData.Supplier) + updateSupply(genesisState.Accounts, genDoc.GenesisTime, genesisState.StakingData.Params.BondDenom, &genesisState.SupplyData.Supplier) genesisState.StakingData.Pool.NotBondedTokens = notBondedSupply genesisState.StakingData.Pool.BondedTokens = bondedSupply @@ -436,25 +436,37 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm return appGenTxs, persistentPeers, nil } -// updateSupply calculates the circulating, vesting, and staking (bonded and not bonded) -// total supply from the genesis accounts -func updateSupply(genAccounts []GenesisAccount, bondDenom string, supplier *supply.Supplier) (notBondedTokens, bondedTokens sdk.Int) { +// updateSupply updates the total, circulating, vesting, modules and staking (bonded and not bonded) +// supplies from the info provided on genesis accounts +func updateSupply(genAccounts []GenesisAccount, genesisTime time.Time, + bondDenom string, supplier *supply.Supplier) (notBondedTokens, bondedTokens sdk.Int) { for _, genAcc := range genAccounts { - // circulating amount not subject to vesting (i.e free) - supplier.Inflate(supply.TypeCirculating, genAcc.OriginalVesting) + supplier.Inflate(supply.TypeTotal, genAcc.Coins) - // vesting and bonded supply from vesting accounts + // update initial vesting, circulating and bonded supplies from vesting accounts if genAcc.OriginalVesting.IsAllPositive() { - supplier.Inflate(supply.TypeVesting, genAcc.OriginalVesting) + if genAcc.EndTime < genesisTime.Unix() { + supplier.Inflate(supply.TypeVesting, genAcc.OriginalVesting) + supplier.Inflate(supply.TypeCirculating, genAcc.OriginalVesting) + supplier.Inflate(supply.TypeTotal, genAcc.OriginalVesting) + } if genAcc.DelegatedVesting.IsAllPositive() { bondedTokens = bondedTokens.Add(genAcc.DelegatedVesting.AmountOf(bondDenom)) } } - // staking pool's not bonded supply + // update modules accounts supply + if genAcc.Module != "" { + supplier.Inflate(supply.TypeModules, genAcc.Coins) + } else { + // update circulating supply from basic and vested accounts + supplier.Inflate(supply.TypeCirculating, genAcc.Coins) + } + + // update staking pool's not bonded supply notBondedAmount := genAcc.Coins.AmountOf(bondDenom) if notBondedAmount.GT(sdk.ZeroInt()) { notBondedTokens = notBondedTokens.Add(notBondedAmount) diff --git a/x/bank/keeper.go b/x/bank/keeper.go index c4432cf8f5c8..5ecff54b0e1b 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -8,7 +8,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank/tags" "github.com/cosmos/cosmos-sdk/x/params" - "github.com/cosmos/cosmos-sdk/x/supply" ) var _ Keeper = (*BaseKeeper)(nil) @@ -407,23 +406,12 @@ func delegateCoins( ) } - var updateSupplyAmt sdk.Coins - vacc, isVestingAccount := acc.(auth.VestingAccount) - if isVestingAccount && vacc.GetDelegatedVesting().IsAllPositive() && ctx.BlockHeader().Time.Unix() >= vacc.GetEndTime() { - updateSupplyAmt = vacc.GetOriginalVesting() - } - if err := trackDelegation(acc, ctx.BlockHeader().Time, amt); err != nil { return nil, sdk.ErrInternal(fmt.Sprintf("failed to track delegation: %v", err)) } setAccount(ctx, ak, acc) - if isVestingAccount { - sk.DeflateSupply(ctx, supply.TypeVesting, updateSupplyAmt) - sk.InflateSupply(ctx, supply.TypeCirculating, updateSupplyAmt) - } - return sdk.NewTags( sdk.TagAction, tags.ActionDelegateCoins, sdk.TagDelegator, addr.String(), @@ -443,23 +431,12 @@ func undelegateCoins( return nil, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr)) } - var updateSupplyAmt sdk.Coins - vacc, isVestingAccount := acc.(auth.VestingAccount) - if isVestingAccount && vacc.GetDelegatedVesting().IsAllPositive() && ctx.BlockHeader().Time.Unix() >= vacc.GetEndTime() { - updateSupplyAmt = vacc.GetOriginalVesting() - } - if err := trackUndelegation(acc, amt); err != nil { return nil, sdk.ErrInternal(fmt.Sprintf("failed to track undelegation: %v", err)) } setAccount(ctx, ak, acc) - if isVestingAccount { - sk.DeflateSupply(ctx, supply.TypeVesting, updateSupplyAmt) - sk.InflateSupply(ctx, supply.TypeCirculating, updateSupplyAmt) - } - return sdk.NewTags( sdk.TagAction, tags.ActionUndelegateCoins, sdk.TagDelegator, addr.String(), diff --git a/x/supply/keeper/invariants.go b/x/supply/keeper/invariants.go index b2fdba07c1f1..9c2e7adadd34 100644 --- a/x/supply/keeper/invariants.go +++ b/x/supply/keeper/invariants.go @@ -34,20 +34,17 @@ func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { supplier := k.GetSupplier(ctx) var circulatingAmount sdk.Coins - var vestingAmount sdk.Coins var modulesAmount sdk.Coins ak.IterateAccounts(ctx, func(acc auth.Account) bool { - vacc, isVestingAccount := acc.(auth.VestingAccount) - if isVestingAccount && vacc.GetDelegatedVesting().IsAllPositive() && ctx.BlockHeader().Time.Unix() >= vacc.GetEndTime() { - - vestingAmount = vestingAmount.Add(vacc.GetOriginalVesting()) - circulatingAmount = circulatingAmount.Add(vacc.GetCoins()) - } macc, isModuleAccount := acc.(auth.ModuleAccount) if isModuleAccount { modulesAmount = modulesAmount.Add(macc.GetCoins()) + } else { + // basic or vesting accounts + // TODO: keep track of vesting amount instead of original vesting + circulatingAmount = circulatingAmount.Add(acc.GetCoins()) } return false @@ -59,12 +56,6 @@ func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { "\tsum of circulating tokens: %v", supplier.CirculatingSupply, circulatingAmount) } - if !supplier.VestingSupply.IsEqual(vestingAmount) { - return fmt.Errorf("vesting supply invariance:\n"+ - "\tsupplier.VestingSupply: %v\n"+ - "\tsum of vesting tokens: %v", supplier.VestingSupply, vestingAmount) - } - if !supplier.ModulesSupply.IsEqual(modulesAmount) { return fmt.Errorf("modules holdings supply invariance:\n"+ "\tsupplier.ModulesSupply: %v\n"+ diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 8039ceb9d89c..ec5af1781383 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -63,7 +63,7 @@ func (k Keeper) DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coi } // TotalSupply returns the total supply of the network. Used only for invariance -// total supply = circulating + vesting + modules + collected fees + community pool +// total supply = circulating + modules + collected fees + community pool // // NOTE: the staking pool's bonded supply is already considered as it's added to the collected fees on minting func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { @@ -75,7 +75,6 @@ func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { remaining, _ := remainingCommunityPool.Add(remainingRewards).TruncateDecimal() return supplier.CirculatingSupply. - Add(supplier.VestingSupply). Add(supplier.ModulesSupply). Add(collectedFees). Add(communityPool). diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 7ea0194fdb40..506215421e2e 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -16,20 +16,20 @@ const ( // Supplier represents a struct that passively keeps track of the total supply amounts in the network type Supplier struct { - CirculatingSupply sdk.Coins `json:"circulating_supply"` // supply held by accounts that's not vesting - VestingSupply sdk.Coins `json:"vesting_supply"` // locked supply held by vesting accounts - ModulesSupply sdk.Coins `json:"modules_supply"` // supply held by modules acccounts - TotalSupply sdk.Coins `json:"total_supply"` // supply held by modules acccounts + CirculatingSupply sdk.Coins `json:"circulating_supply"` // supply held by accounts that's not vesting + InitialVestingSupply sdk.Coins `json:"initial_vesting_supply"` // initial locked supply held by vesting accounts + ModulesSupply sdk.Coins `json:"modules_supply"` // supply held by modules acccounts + TotalSupply sdk.Coins `json:"total_supply"` // supply held by modules acccounts } // NewSupplier creates a new Supplier instance func NewSupplier(circulating, vesting, modules, total sdk.Coins) Supplier { return Supplier{ - CirculatingSupply: circulating, - VestingSupply: vesting, - ModulesSupply: modules, - TotalSupply: total, + CirculatingSupply: circulating, + InitialVestingSupply: vesting, + ModulesSupply: modules, + TotalSupply: total, } } @@ -47,7 +47,7 @@ func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { supplier.CirculatingSupply = supplier.CirculatingSupply.Add(amount) case TypeVesting: - supplier.VestingSupply = supplier.VestingSupply.Add(amount) + supplier.InitialVestingSupply = supplier.InitialVestingSupply.Add(amount) case TypeModules: supplier.ModulesSupply = supplier.ModulesSupply.Add(amount) @@ -75,16 +75,6 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { } supplier.CirculatingSupply = newSupply - case TypeVesting: - newSupply, ok := supplier.VestingSupply.SafeSub(amount) - if !ok { - panic(fmt.Sprintf( - "vesting supply should be greater than given amount: %s < %s", - supplier.VestingSupply.String(), amount.String(), - )) - } - supplier.VestingSupply = newSupply - case TypeModules: newSupply, ok := supplier.ModulesSupply.SafeSub(amount) if !ok { @@ -117,9 +107,9 @@ func (supplier Supplier) CirculatingAmountOf(denom string) sdk.Int { } // VestingAmountOf returns the vesting supply of a coin denomination -func (supplier Supplier) VestingAmountOf(denom string) sdk.Int { +func (supplier Supplier) InitalVestingAmountOf(denom string) sdk.Int { - return supplier.VestingSupply.AmountOf(denom) + return supplier.InitialVestingSupply.AmountOf(denom) } // ModulesAmountOf returns the total token holders' supply of a coin denomination @@ -142,9 +132,9 @@ func (supplier Supplier) ValidateBasic() sdk.Error { fmt.Sprintf("invalid circulating supply: %s", supplier.CirculatingSupply.String()), ) } - if !supplier.VestingSupply.IsValid() { + if !supplier.InitialVestingSupply.IsValid() { return sdk.ErrInvalidCoins( - fmt.Sprintf("invalid vesting supply: %s", supplier.VestingSupply.String()), + fmt.Sprintf("invalid initial vesting supply: %s", supplier.InitialVestingSupply.String()), ) } if !supplier.ModulesSupply.IsValid() { @@ -160,11 +150,11 @@ func (supplier Supplier) ValidateBasic() sdk.Error { func (supplier Supplier) String() string { return fmt.Sprintf(`Supplier: Circulating Supply: %s - Vesting Supply: %s + Initial Vesting Supply: %s Modules Supply: %s Total Supply: %s`, supplier.CirculatingSupply.String(), - supplier.VestingSupply.String(), + supplier.InitialVestingSupply.String(), supplier.ModulesSupply.String(), supplier.TotalSupply.String()) } From e7cbc40e85360fe594b4b91fd8ed27eff1dd474b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 24 Apr 2019 17:47:04 +0200 Subject: [PATCH 35/46] update references and aliases --- x/mint/abci_app.go | 20 ++------------------ x/mint/alias.go | 27 +++++++++++++++++++++++++++ x/mint/genesis.go | 16 ++++++++++++++++ x/mint/keeper/expected_keepers.go | 4 +--- x/mint/keeper/keeper.go | 26 ++++++++++++++++++++++++++ x/mint/types/genesis.go | 14 -------------- x/mint/types/minter.go | 3 ++- x/mint/types/params.go | 3 ++- x/supply/alias.go | 9 ++++++--- x/supply/genesis.go | 16 ---------------- x/supply/types/genesis.go | 16 ++++++++++++++++ 11 files changed, 98 insertions(+), 56 deletions(-) create mode 100644 x/mint/alias.go create mode 100644 x/supply/types/genesis.go diff --git a/x/mint/abci_app.go b/x/mint/abci_app.go index b915c3812bc2..0ce36bcf176c 100644 --- a/x/mint/abci_app.go +++ b/x/mint/abci_app.go @@ -3,27 +3,11 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/mint/keeper" - "github.com/cosmos/cosmos-sdk/x/supply" ) // BeginBlocker inflates every block and updates inflation parameters once per hour func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { - // fetch stored minter & params - minter := k.GetMinter(ctx) - params := k.GetParams(ctx) - - // recalculate inflation rate - bondedRatio := k.sk.BondedRatio(ctx) - minter.Inflation = minter.NextInflationRate(params, bondedRatio) - minter.AnnualProvisions = minter.NextAnnualProvisions(params, k.sk.StakingTokenSupply(ctx)) - k.SetMinter(ctx, minter) - - // mint coins, add to collected fees, update supply by adding it to the fee collector - mintedCoin := minter.BlockProvision(params) - k.fck.AddCollectedFees(ctx, sdk.NewCoins(mintedCoin)) - - // // passively keep track of the total and the not bonded supply - k.supplyKeeper.InflateSupply(ctx, supply.TypeTotal, sdk.NewCoins(mintedCoin)) - k.sk.InflateNotBondedTokenSupply(ctx, mintedCoin.Amount) + k.CalculateInflationRate(ctx) + k.Mint(ctx) } diff --git a/x/mint/alias.go b/x/mint/alias.go new file mode 100644 index 000000000000..99f17fa85e84 --- /dev/null +++ b/x/mint/alias.go @@ -0,0 +1,27 @@ +//nolint +package mint + +import ( + "github.com/cosmos/cosmos-sdk/x/mint/keeper" + "github.com/cosmos/cosmos-sdk/x/mint/types" +) + +type ( + Keeper = keeper.Keeper + Minter = types.Minter + Params = types.Params + GenesisState = types.GenesisState +) + +var ( + NewKeeper = keeper.NewKeeper + NewQuerier = keeper.NewQuerier + + NewGenesisState = types.NewGenesisState + DefaultGenesisState = types.DefaultGenesisState +) + +const ( + StoreKey = keeper.StoreKey + QuerierRoute = keeper.QuerierRoute +) diff --git a/x/mint/genesis.go b/x/mint/genesis.go index e137ffae8176..ae1104d20a9b 100644 --- a/x/mint/genesis.go +++ b/x/mint/genesis.go @@ -19,3 +19,19 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { params := k.GetParams(ctx) return types.NewGenesisState(minter, params) } + +// ValidateGenesis validates the provided genesis state to ensure the +// expected invariants holds. +func ValidateGenesis(data types.GenesisState) error { + err := types.ValidateParams(data.Params) + if err != nil { + return err + } + + err = types.ValidateMinter(data.Minter) + if err != nil { + return err + } + + return nil +} diff --git a/x/mint/keeper/expected_keepers.go b/x/mint/keeper/expected_keepers.go index 81554f830936..04252f5cf74f 100644 --- a/x/mint/keeper/expected_keepers.go +++ b/x/mint/keeper/expected_keepers.go @@ -2,13 +2,11 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/supply" ) // SupplyKeeper defines the expected supply keeper type SupplyKeeper interface { - GetSupplier(ctx sdk.Context) supply.Supplier - InflateSupply(ctx sdk.Context, amt sdk.Coins) + InflateSupply(ctx sdk.Context, supplyType string, amt sdk.Coins) } // StakingKeeper defines the expected staking keeper diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index 52c2d7949862..8b56c8d6cc0a 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/supply" ) // Keeper defines the keeper of the minting store @@ -50,3 +51,28 @@ func (k Keeper) SetMinter(ctx sdk.Context, minter types.Minter) { b := k.cdc.MustMarshalBinaryLengthPrefixed(minter) store.Set(minterKey, b) } + +// CalculateInflationRate recalculates the inflation rate and anual provisions for a new block +func (k Keeper) CalculateInflationRate(ctx sdk.Context) { + minter := k.GetMinter(ctx) + params := k.GetParams(ctx) + + bondedRatio := k.sk.BondedRatio(ctx) + minter.Inflation = minter.NextInflationRate(params, bondedRatio) + minter.AnnualProvisions = minter.NextAnnualProvisions(params, k.sk.StakingTokenSupply(ctx)) + k.SetMinter(ctx, minter) +} + +// Mint creates new coins based on the current block provision, which are added +// to the collected fee pool and then updates the total supply +func (k Keeper) Mint(ctx sdk.Context) { + minter := k.GetMinter(ctx) + params := k.GetParams(ctx) + + mintedCoin := minter.BlockProvision(params) + k.fck.AddCollectedFees(ctx, sdk.NewCoins(mintedCoin)) + + // // passively keep track of the total and the not bonded supply + k.supplyKeeper.InflateSupply(ctx, supply.TypeTotal, sdk.NewCoins(mintedCoin)) + k.sk.InflateNotBondedTokenSupply(ctx, mintedCoin.Amount) +} diff --git a/x/mint/types/genesis.go b/x/mint/types/genesis.go index d2fb3af5ecb2..642513abcae7 100644 --- a/x/mint/types/genesis.go +++ b/x/mint/types/genesis.go @@ -21,17 +21,3 @@ func DefaultGenesisState() GenesisState { Params: DefaultParams(), } } - -// ValidateGenesis validates the provided genesis state to ensure the -// expected invariants holds. -func ValidateGenesis(data GenesisState) error { - err := validateParams(data.Params) - if err != nil { - return err - } - err = validateMinter(data.Minter) - if err != nil { - return err - } - return nil -} diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index c733cfdfd676..d7fa9cef4fab 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -37,7 +37,8 @@ func DefaultInitialMinter() Minter { ) } -func validateMinter(minter Minter) error { +// ValidateMinter validates the minter inflation +func ValidateMinter(minter Minter) error { if minter.Inflation.LT(sdk.ZeroDec()) { return fmt.Errorf("mint parameter Inflation should be positive, is %s", minter.Inflation.String()) diff --git a/x/mint/types/params.go b/x/mint/types/params.go index 32a32fcb1ac2..d79fc6275e64 100644 --- a/x/mint/types/params.go +++ b/x/mint/types/params.go @@ -41,7 +41,8 @@ func DefaultParams() Params { } } -func validateParams(params Params) error { +// ValidateParams validate the minting module params +func ValidateParams(params Params) error { if params.GoalBonded.LT(sdk.ZeroDec()) { return fmt.Errorf("mint parameter GoalBonded should be positive, is %s ", params.GoalBonded.String()) } diff --git a/x/supply/alias.go b/x/supply/alias.go index cf9cdaf4e068..ed559e9d9589 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -7,12 +7,15 @@ import ( ) type ( - Keeper = keeper.Keeper - Supplier = types.Supplier + Keeper = keeper.Keeper + Supplier = types.Supplier + GenesisState = types.GenesisState ) var ( - NewKeeper = keeper.NewKeeper + NewKeeper = keeper.NewKeeper + NewGenesisState = types.NewGenesisState + DefaultGenesisState = types.DefaultGenesisState ) const ( diff --git a/x/supply/genesis.go b/x/supply/genesis.go index ed288cb73dd8..0eecb6e25611 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -5,24 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/supply/keeper" - "github.com/cosmos/cosmos-sdk/x/supply/types" ) -// GenesisState is the supply state that must be provided at genesis. -type GenesisState struct { - Supplier types.Supplier `json:"supplier"` -} - -// NewGenesisState creates a new genesis state. -func NewGenesisState(supplier types.Supplier) GenesisState { - return GenesisState{Supplier: supplier} -} - -// DefaultGenesisState returns a default genesis state -func DefaultGenesisState() GenesisState { - return NewGenesisState(types.DefaultSupplier()) -} - // InitGenesis sets supply information for genesis. func InitGenesis(ctx sdk.Context, k keeper.Keeper, data GenesisState) { k.SetSupplier(ctx, data.Supplier) diff --git a/x/supply/types/genesis.go b/x/supply/types/genesis.go new file mode 100644 index 000000000000..aa867edce12d --- /dev/null +++ b/x/supply/types/genesis.go @@ -0,0 +1,16 @@ +package types + +// GenesisState is the supply state that must be provided at genesis. +type GenesisState struct { + Supplier Supplier `json:"supplier"` +} + +// NewGenesisState creates a new genesis state. +func NewGenesisState(supplier Supplier) GenesisState { + return GenesisState{Supplier: supplier} +} + +// DefaultGenesisState returns a default genesis state +func DefaultGenesisState() GenesisState { + return NewGenesisState(DefaultSupplier()) +} From f83af2f43444d95316e43ca4c5d33aaa5c403ab3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 24 Apr 2019 19:10:30 +0200 Subject: [PATCH 36/46] calculate total supply on initialization --- x/supply/genesis.go | 1 + x/supply/keeper/keeper.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x/supply/genesis.go b/x/supply/genesis.go index 0eecb6e25611..73ae480a6833 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -9,6 +9,7 @@ import ( // InitGenesis sets supply information for genesis. func InitGenesis(ctx sdk.Context, k keeper.Keeper, data GenesisState) { + data.Supplier.TotalSupply = k.TotalSupply(ctx) k.SetSupplier(ctx, data.Supplier) } diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index ec5af1781383..b9d45099c2a2 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -62,7 +62,7 @@ func (k Keeper) DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coi k.SetSupplier(ctx, supplier) } -// TotalSupply returns the total supply of the network. Used only for invariance +// TotalSupply returns the total supply of the network. Used only for invariance and genesis initialization // total supply = circulating + modules + collected fees + community pool // // NOTE: the staking pool's bonded supply is already considered as it's added to the collected fees on minting From 006c1eb0c2a90b1c64e8a479db18db243cdf673b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 25 Apr 2019 13:50:46 +0200 Subject: [PATCH 37/46] fix build --- cmd/gaia/app/app.go | 28 ++++++++-------- cmd/gaia/app/genesis.go | 28 ++++++++-------- x/bank/expected_keepers.go | 6 ---- x/bank/keeper.go | 11 +++---- x/crisis/handler.go | 1 + x/crisis/keeper.go | 2 +- x/crisis/tags/tags.go | 3 ++ x/distribution/keeper/test_common.go | 6 +++- x/gov/keeper.go | 4 +-- x/gov/test_common.go | 8 +++-- x/mint/alias.go | 5 +-- x/mint/keeper/test_common.go | 6 ++-- x/staking/alias.go | 2 +- x/supply/alias.go | 4 ++- x/supply/genesis.go | 1 - x/supply/keeper/expected_keepers.go | 10 +++++- x/supply/keeper/invariants.go | 49 ++++++++++++++++++++++------ x/supply/keeper/keeper.go | 30 +---------------- 18 files changed, 109 insertions(+), 95 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 20e493946e43..6cdd6e9606b7 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -117,31 +117,31 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, ) - app.supplyKeeper = supply.NewKeeper( + stakingKeeper := staking.NewKeeper( app.cdc, - app.keySupply, + app.keyStaking, app.tkeyStaking, + app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace), + staking.DefaultCodespace, ) app.feeCollectionKeeper = auth.NewFeeCollectionKeeper( app.cdc, app.keyFeeCollection, ) - stakingKeeper := staking.NewKeeper( + app.supplyKeeper = supply.NewKeeper( app.cdc, - app.keyStaking, app.tkeyStaking, - app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace), - staking.DefaultCodespace, - ) - app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, - app.paramsKeeper.Subspace(mint.DefaultParamspace), - app.supplyKeeper, &stakingKeeper, app.feeCollectionKeeper, + app.keySupply, ) app.distrKeeper = distr.NewKeeper( app.cdc, app.keyDistr, app.paramsKeeper.Subspace(distr.DefaultParamspace), - app.bankKeeper, &stakingKeeper, app.feeCollectionKeeper, + app.bankKeeper, &stakingKeeper, app.feeCollectionKeeper, app.supplyKeeper, distr.DefaultCodespace, ) + app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, + app.paramsKeeper.Subspace(mint.DefaultParamspace), + app.supplyKeeper, &stakingKeeper, app.feeCollectionKeeper, + ) app.slashingKeeper = slashing.NewKeeper( app.cdc, app.keySlashing, @@ -152,7 +152,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b app.cdc, app.keyGov, app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), - app.bankKeeper, app.supplyKeeper, &stakingKeeper, + app.bankKeeper, app.accountKeeper, app.supplyKeeper, &stakingKeeper, gov.DefaultCodespace, ) app.crisisKeeper = crisis.NewKeeper( @@ -172,7 +172,9 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b // register the crisis routes bank.RegisterInvariants(&app.crisisKeeper, app.accountKeeper) distr.RegisterInvariants(&app.crisisKeeper, app.distrKeeper, app.stakingKeeper) - staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper) + staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper) + supply.RegisterInvariants(&app.crisisKeeper, app.supplyKeeper, app.accountKeeper, + app.distrKeeper, app.feeCollectionKeeper, app.stakingKeeper) // register transaction messages routes app.Router(). diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 735f20cdc3cc..af0602fdb628 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -222,7 +222,8 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } notBondedSupply, bondedSupply := - updateSupply(genesisState.Accounts, genDoc.GenesisTime, genesisState.StakingData.Params.BondDenom, &genesisState.SupplyData.Supplier) + updateSupplyFromGenAccounts(genesisState.Accounts, genDoc.GenesisTime, + genesisState.StakingData, &genesisState.SupplyData.Supplier) genesisState.StakingData.Pool.NotBondedTokens = notBondedSupply genesisState.StakingData.Pool.BondedTokens = bondedSupply @@ -436,25 +437,16 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm return appGenTxs, persistentPeers, nil } -// updateSupply updates the total, circulating, vesting, modules and staking (bonded and not bonded) +// updateSupplyFromGenAccounts updates the total, circulating, vesting, modules and staking (bonded and not bonded) // supplies from the info provided on genesis accounts -func updateSupply(genAccounts []GenesisAccount, genesisTime time.Time, - bondDenom string, supplier *supply.Supplier) (notBondedTokens, bondedTokens sdk.Int) { +func updateSupplyFromGenAccounts(genAccounts []GenesisAccount, genesisTime time.Time, + stakingData staking.GenesisState, supplier *supply.Supplier) (notBondedTokens, bondedTokens sdk.Int) { for _, genAcc := range genAccounts { - - supplier.Inflate(supply.TypeTotal, genAcc.Coins) - // update initial vesting, circulating and bonded supplies from vesting accounts if genAcc.OriginalVesting.IsAllPositive() { - if genAcc.EndTime < genesisTime.Unix() { + if genesisTime.Unix() < genAcc.EndTime { supplier.Inflate(supply.TypeVesting, genAcc.OriginalVesting) - supplier.Inflate(supply.TypeCirculating, genAcc.OriginalVesting) - supplier.Inflate(supply.TypeTotal, genAcc.OriginalVesting) - } - - if genAcc.DelegatedVesting.IsAllPositive() { - bondedTokens = bondedTokens.Add(genAcc.DelegatedVesting.AmountOf(bondDenom)) } } @@ -467,11 +459,17 @@ func updateSupply(genAccounts []GenesisAccount, genesisTime time.Time, } // update staking pool's not bonded supply - notBondedAmount := genAcc.Coins.AmountOf(bondDenom) + notBondedAmount := genAcc.Coins.AmountOf(stakingData.Params.BondDenom) if notBondedAmount.GT(sdk.ZeroInt()) { notBondedTokens = notBondedTokens.Add(notBondedAmount) } + + supplier.Inflate(supply.TypeTotal, genAcc.Coins) } + + // add bonded tokens to total supply + bondedSupply := sdk.NewCoins(sdk.NewCoin(stakingData.Params.BondDenom, stakingData.Pool.BondedTokens)) + supplier.Inflate(supply.TypeTotal, bondedSupply) return } diff --git a/x/bank/expected_keepers.go b/x/bank/expected_keepers.go index d2084568c3b8..7e66dbd6f440 100644 --- a/x/bank/expected_keepers.go +++ b/x/bank/expected_keepers.go @@ -8,9 +8,3 @@ import ( type CrisisKeeper interface { RegisterRoute(moduleName, route string, invar sdk.Invariant) } - -// SupplyKeeper expected supply keeper -type SupplyKeeper interface { - InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) - DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) -} diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 5ecff54b0e1b..a500d1841505 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -34,14 +34,12 @@ type BaseKeeper struct { BaseSendKeeper ak auth.AccountKeeper - sk SupplyKeeper paramSpace params.Subspace } // NewBaseKeeper returns a new BaseKeeper func NewBaseKeeper( ak auth.AccountKeeper, - sk SupplyKeeper, paramSpace params.Subspace, codespace sdk.CodespaceType) BaseKeeper { @@ -49,7 +47,6 @@ func NewBaseKeeper( return BaseKeeper{ BaseSendKeeper: NewBaseSendKeeper(ak, ps, codespace), ak: ak, - sk: sk, paramSpace: ps, } } @@ -108,7 +105,7 @@ func (keeper BaseKeeper) DelegateCoins( if !amt.IsValid() { return nil, sdk.ErrInvalidCoins(amt.String()) } - return delegateCoins(ctx, keeper.ak, keeper.sk, addr, amt) + return delegateCoins(ctx, keeper.ak, addr, amt) } // UndelegateCoins performs undelegation by crediting amt coins to an account with @@ -122,7 +119,7 @@ func (keeper BaseKeeper) UndelegateCoins( if !amt.IsValid() { return nil, sdk.ErrInvalidCoins(amt.String()) } - return undelegateCoins(ctx, keeper.ak, keeper.sk, addr, amt) + return undelegateCoins(ctx, keeper.ak, addr, amt) } //------------------------------------------------------- @@ -385,7 +382,7 @@ func inputOutputCoins(ctx sdk.Context, am auth.AccountKeeper, inputs []Input, ou // staking func delegateCoins( - ctx sdk.Context, ak auth.AccountKeeper, sk SupplyKeeper, addr sdk.AccAddress, amt sdk.Coins, + ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins, ) (sdk.Tags, sdk.Error) { if !amt.IsValid() { @@ -419,7 +416,7 @@ func delegateCoins( } func undelegateCoins( - ctx sdk.Context, ak auth.AccountKeeper, sk SupplyKeeper, addr sdk.AccAddress, amt sdk.Coins, + ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins, ) (sdk.Tags, sdk.Error) { if !amt.IsValid() { diff --git a/x/crisis/handler.go b/x/crisis/handler.go index da30d976aaa1..9ac13a163460 100644 --- a/x/crisis/handler.go +++ b/x/crisis/handler.go @@ -75,6 +75,7 @@ func handleMsgVerifyInvariant(ctx sdk.Context, msg MsgVerifyInvariant, k Keeper) } resTags := sdk.NewTags( + tags.Category, tags.TxCategory, tags.Sender, msg.Sender.String(), tags.Invariant, msg.InvariantRoute, ) diff --git a/x/crisis/keeper.go b/x/crisis/keeper.go index 95c7cf09c1a0..9fc11dadc9dc 100644 --- a/x/crisis/keeper.go +++ b/x/crisis/keeper.go @@ -29,7 +29,7 @@ func NewKeeper(paramSpace params.Subspace, } } -// register routes for the +// RegisterRoute register routes for the invant func (k *Keeper) RegisterRoute(moduleName, route string, invar sdk.Invariant) { invarRoute := NewInvarRoute(moduleName, route, invar) k.routes = append(k.routes, invarRoute) diff --git a/x/crisis/tags/tags.go b/x/crisis/tags/tags.go index da3c66793680..15b6222623c5 100644 --- a/x/crisis/tags/tags.go +++ b/x/crisis/tags/tags.go @@ -6,6 +6,9 @@ import ( // Crisis module tags var ( + TxCategory = "crisis" + Sender = sdk.TagSender + Category = sdk.TagCategory Invariant = "invariant" ) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index c21d6a8d2c6a..9c369eb4e6a5 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -18,6 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/distribution/types" ) @@ -93,6 +94,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) keyAcc := sdk.NewKVStoreKey(auth.StoreKey) keyFeeCollection := sdk.NewKVStoreKey(auth.FeeStoreKey) + keySupply := sdk.NewKVStoreKey(supply.StoreKey) keyParams := sdk.NewKVStoreKey(params.StoreKey) tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) @@ -104,6 +106,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyFeeCollection, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) @@ -119,6 +122,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, bankKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) sk.SetPool(ctx, staking.InitialPool()) sk.SetParams(ctx, staking.DefaultParams()) + supplyKeeper := supply.NewKeeper(cdc, keySupply) // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, addr := range TestAddrs { @@ -132,7 +136,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, } fck := DummyFeeCollectionKeeper{} - keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), bankKeeper, sk, fck, types.DefaultCodespace) + keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), bankKeeper, sk, fck, supplyKeeper, types.DefaultCodespace) // set the distribution hooks on staking sk.SetHooks(keeper.Hooks()) diff --git a/x/gov/keeper.go b/x/gov/keeper.go index c43febc1cf73..3f7337737449 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -1,13 +1,13 @@ package gov import ( - "log" "time" codec "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/tendermint/tendermint/libs/log" ) // Governance Keeper @@ -359,7 +359,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd // update the governance module account coin pool moduleAddress, _ := sdk.AccAddressFromBech32(ModuleName) - err := keeper.ck.AddCoins(ctx, moduleAddress, depositAmount) + _, err := keeper.ck.AddCoins(ctx, moduleAddress, depositAmount) if err != nil { return err, false } diff --git a/x/gov/test_common.go b/x/gov/test_common.go index c8fcba18fd96..88bd13d1fe8b 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -29,16 +29,18 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a staking.RegisterCodec(mapp.Cdc) RegisterCodec(mapp.Cdc) + keyAccount := sdk.NewKVStoreKey(auth.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) keyGov := sdk.NewKVStoreKey(StoreKey) pk := mapp.ParamsKeeper - ck := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) + ak := auth.NewAccountKeeper(mapp.Cdc, keyAccount, mapp.ParamsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) + bk := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) sk := supply.NewKeeper(mapp.Cdc, keySupply) - ds = staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, ck, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) - keeper = NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, ds, DefaultCodespace) + ds = staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, bk, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) + keeper = NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), bk, ak, sk, ds, DefaultCodespace) mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) mapp.QueryRouter().AddRoute(QuerierRoute, NewQuerier(keeper)) diff --git a/x/mint/alias.go b/x/mint/alias.go index 99f17fa85e84..11e7180cf4ac 100644 --- a/x/mint/alias.go +++ b/x/mint/alias.go @@ -22,6 +22,7 @@ var ( ) const ( - StoreKey = keeper.StoreKey - QuerierRoute = keeper.QuerierRoute + StoreKey = keeper.StoreKey + QuerierRoute = keeper.QuerierRoute + DefaultParamspace = keeper.DefaultParamspace ) diff --git a/x/mint/keeper/test_common.go b/x/mint/keeper/test_common.go index f6b49c6cb93b..a5d3cabf87fc 100644 --- a/x/mint/keeper/test_common.go +++ b/x/mint/keeper/test_common.go @@ -20,6 +20,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" + + "github.com/cosmos/cosmos-sdk/x/mint/types" ) type testInput struct { @@ -73,8 +75,8 @@ func newTestInput(t *testing.T) testInput { ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout)) - mintKeeper.SetParams(ctx, DefaultParams()) - mintKeeper.SetMinter(ctx, DefaultInitialMinter()) + mintKeeper.SetParams(ctx, types.DefaultParams()) + mintKeeper.SetMinter(ctx, types.DefaultInitialMinter()) return testInput{ctx, cdc, mintKeeper} } diff --git a/x/staking/alias.go b/x/staking/alias.go index cbc20d7dca06..85c6e50fa5bc 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -69,7 +69,7 @@ var ( ValidatorQueueKey = keeper.ValidatorQueueKey RegisterInvariants = keeper.RegisterInvariants AllInvariants = keeper.AllInvariants - SupplyInvariants = keeper.SupplyInvariants + SupplyInvariants = keeper.BondedTokensInvariant NonNegativePowerInvariant = keeper.NonNegativePowerInvariant PositiveDelegationInvariant = keeper.PositiveDelegationInvariant DelegatorSharesInvariant = keeper.DelegatorSharesInvariant diff --git a/x/supply/alias.go b/x/supply/alias.go index ed559e9d9589..d772e489b23d 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -13,7 +13,9 @@ type ( ) var ( - NewKeeper = keeper.NewKeeper + NewKeeper = keeper.NewKeeper + RegisterInvariants = keeper.RegisterInvariants + NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState ) diff --git a/x/supply/genesis.go b/x/supply/genesis.go index 73ae480a6833..0eecb6e25611 100644 --- a/x/supply/genesis.go +++ b/x/supply/genesis.go @@ -9,7 +9,6 @@ import ( // InitGenesis sets supply information for genesis. func InitGenesis(ctx sdk.Context, k keeper.Keeper, data GenesisState) { - data.Supplier.TotalSupply = k.TotalSupply(ctx) k.SetSupplier(ctx, data.Supplier) } diff --git a/x/supply/keeper/expected_keepers.go b/x/supply/keeper/expected_keepers.go index f4cfc5276c21..7b5b854337da 100644 --- a/x/supply/keeper/expected_keepers.go +++ b/x/supply/keeper/expected_keepers.go @@ -1,6 +1,14 @@ package keeper -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" +) + +// AccountKeeper defines the expected account keeper +type AccountKeeper interface { + IterateAccounts(ctx sdk.Context, process func(auth.Account) (stop bool)) +} // CrisisKeeper defines the expected crisis keeper type CrisisKeeper interface { diff --git a/x/supply/keeper/invariants.go b/x/supply/keeper/invariants.go index 9c2e7adadd34..9a936848884a 100644 --- a/x/supply/keeper/invariants.go +++ b/x/supply/keeper/invariants.go @@ -5,20 +5,23 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/staking/types" ) // RegisterInvariants registers all supply invariants -func RegisterInvariants(ck CrisisKeeper, k Keeper, ak auth.AccountKeeper) { - ck.RegisterRoute(ModuleName, "supply", SupplyInvariants(k, ak)) +func RegisterInvariants(ck CrisisKeeper, k Keeper, accountKeeper AccountKeeper, + distributionKeeper DistributionKeeper, feeCollectionKeeper FeeCollectionKeeper, + stakingKeeper StakingKeeper) { + ck.RegisterRoute( + ModuleName, "supply", + SupplyInvariants(k, accountKeeper, distributionKeeper, feeCollectionKeeper, stakingKeeper)) } // AllInvariants runs all invariants of the staking module. -func AllInvariants(k Keeper, fck types.FeeCollectionKeeper, - dk types.DistributionKeeper, ak auth.AccountKeeper) sdk.Invariant { +func AllInvariants(k Keeper, accountKeeper AccountKeeper, distributionKeeper DistributionKeeper, + feeCollectionKeeper FeeCollectionKeeper, stakingKeeper StakingKeeper) sdk.Invariant { return func(ctx sdk.Context) error { - err := SupplyInvariants(k, ak)(ctx) + err := SupplyInvariants(k, accountKeeper, distributionKeeper, feeCollectionKeeper, stakingKeeper)(ctx) if err != nil { return err } @@ -28,22 +31,29 @@ func AllInvariants(k Keeper, fck types.FeeCollectionKeeper, } // SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations -func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { +func SupplyInvariants(k Keeper, + accountKeeper AccountKeeper, distributionKeeper DistributionKeeper, + feeCollectionKeeper FeeCollectionKeeper, stakingKeeper StakingKeeper) sdk.Invariant { return func(ctx sdk.Context) error { supplier := k.GetSupplier(ctx) var circulatingAmount sdk.Coins var modulesAmount sdk.Coins + var initialVestingAmount sdk.Coins - ak.IterateAccounts(ctx, func(acc auth.Account) bool { + accountKeeper.IterateAccounts(ctx, func(acc auth.Account) bool { + + vacc, isVestingAccount := acc.(auth.VestingAccount) + if isVestingAccount && ctx.BlockHeader().Time.Unix() < vacc.GetEndTime() { + initialVestingAmount = initialVestingAmount.Add(vacc.GetOriginalVesting()) + } macc, isModuleAccount := acc.(auth.ModuleAccount) if isModuleAccount { modulesAmount = modulesAmount.Add(macc.GetCoins()) } else { // basic or vesting accounts - // TODO: keep track of vesting amount instead of original vesting circulatingAmount = circulatingAmount.Add(acc.GetCoins()) } @@ -62,7 +72,26 @@ func SupplyInvariants(k Keeper, ak auth.AccountKeeper) sdk.Invariant { "\tsum of modules accounts tokens: %v", supplier.ModulesSupply, modulesAmount) } - expectedTotalSupply := k.TotalSupply(ctx) + if !supplier.InitialVestingSupply.IsEqual(initialVestingAmount) { + return fmt.Errorf("vesting supply invariance:\n"+ + "\tsupplier.InitialVestingSupply: %v\n"+ + "\tsum of vesting tokens: %v", supplier.InitialVestingSupply, initialVestingAmount) + } + + bondedSupply := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), stakingKeeper.TotalBondedTokens(ctx))) + collectedFees := feeCollectionKeeper.GetCollectedFees(ctx) + communityPool, remainingCommunityPool := distributionKeeper.GetFeePoolCommunityCoins(ctx).TruncateDecimal() + totalRewards, remainingRewards := distributionKeeper.GetTotalRewards(ctx).TruncateDecimal() + + remaining, _ := remainingCommunityPool.Add(remainingRewards).TruncateDecimal() + + expectedTotalSupply := supplier.CirculatingSupply. + Add(supplier.ModulesSupply). + Add(bondedSupply). + Add(collectedFees). + Add(communityPool). + Add(totalRewards). + Add(remaining) if !supplier.TotalSupply.IsEqual(expectedTotalSupply) { return fmt.Errorf("total supply invariance:\n"+ diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index b9d45099c2a2..25beae0b6b78 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -10,21 +10,13 @@ import ( type Keeper struct { cdc *codec.Codec storeKey sdk.StoreKey - - dk DistributionKeeper - fck FeeCollectionKeeper - sk StakingKeeper } // NewKeeper creates a new supply Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, - dk DistributionKeeper, fck FeeCollectionKeeper, sk StakingKeeper) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper { return Keeper{ cdc: cdc, storeKey: key, - dk: dk, - fck: fck, - sk: sk, } } @@ -61,23 +53,3 @@ func (k Keeper) DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coi k.SetSupplier(ctx, supplier) } - -// TotalSupply returns the total supply of the network. Used only for invariance and genesis initialization -// total supply = circulating + modules + collected fees + community pool -// -// NOTE: the staking pool's bonded supply is already considered as it's added to the collected fees on minting -func (k Keeper) TotalSupply(ctx sdk.Context) sdk.Coins { - supplier := k.GetSupplier(ctx) - - collectedFees := k.fck.GetCollectedFees(ctx) - communityPool, remainingCommunityPool := k.dk.GetFeePoolCommunityCoins(ctx).TruncateDecimal() - totalRewards, remainingRewards := k.dk.GetTotalRewards(ctx).TruncateDecimal() - - remaining, _ := remainingCommunityPool.Add(remainingRewards).TruncateDecimal() - return supplier.CirculatingSupply. - Add(supplier.ModulesSupply). - Add(collectedFees). - Add(communityPool). - Add(totalRewards). - Add(remaining) -} From bd6b5a99cec8e0c1f5af263e24046f3e43cee4c2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 25 Apr 2019 17:14:52 +0200 Subject: [PATCH 38/46] initial testing --- cmd/gaia/app/app_test.go | 2 ++ types/staking.go | 2 +- x/distribution/keeper/allocation_test.go | 2 +- x/distribution/keeper/keeper_test.go | 17 ++++++++++++ x/distribution/keeper/test_common.go | 8 +++--- x/mint/alias.go | 7 +++-- x/mint/keeper/keeper.go | 2 +- x/supply/alias.go | 2 ++ x/supply/keeper/keeper.go | 2 +- x/supply/keeper/keeper_test.go | 18 ++++++++----- x/supply/types/supplier.go | 33 +++++------------------- 11 files changed, 53 insertions(+), 42 deletions(-) diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index de21f585ac3f..7a13c4178875 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -1,6 +1,7 @@ package app import ( + "fmt" "os" "testing" @@ -42,6 +43,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error { supply.DefaultGenesisState(), ) + fmt.Println(genesisState.SupplyData) stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState) if err != nil { return err diff --git a/types/staking.go b/types/staking.go index d3a388c937db..58ba094603ce 100644 --- a/types/staking.go +++ b/types/staking.go @@ -17,7 +17,7 @@ const ( Bonded BondStatus = 0x02 // default bond denomination - DefaultBondDenom = "stake" + DefaultBondDenom = "uatom" // Delay, in blocks, between when validator updates are returned to Tendermint and when they are applied. // For example, if this is 0, the validator set at the end of a block will sign the next block, or diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 956121d581d5..ff84c548d6b5 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -105,7 +105,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) { func TestAllocateTokensTruncation(t *testing.T) { communityTax := sdk.NewDec(0) - ctx, _, _, k, sk, fck, _ := CreateTestInputAdvanced(t, false, 1000000, communityTax) + ctx, _, _, k, sk, fck, _, _ := CreateTestInputAdvanced(t, false, 1000000, communityTax) sh := staking.NewHandler(sk) // create validator with 10% commission diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 59471a13287a..d383e9dcf5be 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -62,3 +62,20 @@ func TestWithdrawValidatorCommission(t *testing.T) { require.True(t, true) } + +func TestGetTotalRewards(t *testing.T) { + ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000) + + valCommission := sdk.DecCoins{ + sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))), + sdk.NewDecCoinFromDec("stake", sdk.NewDec(3).Quo(sdk.NewDec(2))), + } + + keeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, valCommission) + keeper.SetValidatorOutstandingRewards(ctx, valOpAddr2, valCommission) + + expectedRewards := valCommission.MulDec(sdk.NewDec(2)) + totalRewards := keeper.GetTotalRewards(ctx) + + require.Equal(t, expectedRewards, totalRewards) +} diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 9c369eb4e6a5..5eb45b95ea9c 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -78,14 +78,14 @@ func CreateTestInputDefault(t *testing.T, isCheckTx bool, initPower int64) ( communityTax := sdk.NewDecWithPrec(2, 2) - ctx, ak, _, dk, sk, fck, _ := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax) + ctx, ak, _, dk, sk, fck, _, _ := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax) return ctx, ak, dk, sk, fck } // hogpodge of all sorts of input required for testing func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, communityTax sdk.Dec) (sdk.Context, auth.AccountKeeper, bank.Keeper, - Keeper, staking.Keeper, DummyFeeCollectionKeeper, params.Keeper) { + Keeper, staking.Keeper, DummyFeeCollectionKeeper, SupplyKeeper, params.Keeper) { initCoins := sdk.TokensFromTendermintPower(initPower) @@ -122,7 +122,9 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, bankKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) sk.SetPool(ctx, staking.InitialPool()) sk.SetParams(ctx, staking.DefaultParams()) + supplyKeeper := supply.NewKeeper(cdc, keySupply) + supplyKeeper.SetSupplier(ctx, supply.DefaultSupplier()) // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, addr := range TestAddrs { @@ -147,7 +149,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, keeper.SetBaseProposerReward(ctx, sdk.NewDecWithPrec(1, 2)) keeper.SetBonusProposerReward(ctx, sdk.NewDecWithPrec(4, 2)) - return ctx, accountKeeper, bankKeeper, keeper, sk, fck, pk + return ctx, accountKeeper, bankKeeper, keeper, sk, fck, supplyKeeper, pk } //__________________________________________________________________________________ diff --git a/x/mint/alias.go b/x/mint/alias.go index 11e7180cf4ac..21b907f90acb 100644 --- a/x/mint/alias.go +++ b/x/mint/alias.go @@ -17,8 +17,11 @@ var ( NewKeeper = keeper.NewKeeper NewQuerier = keeper.NewQuerier - NewGenesisState = types.NewGenesisState - DefaultGenesisState = types.DefaultGenesisState + NewGenesisState = types.NewGenesisState + DefaultGenesisState = types.DefaultGenesisState + InitialMinter = types.InitialMinter + DefaultInitialMinter = types.DefaultInitialMinter + NewParams = types.NewParams ) const ( diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index 8b56c8d6cc0a..1b1daf2b169d 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -52,7 +52,7 @@ func (k Keeper) SetMinter(ctx sdk.Context, minter types.Minter) { store.Set(minterKey, b) } -// CalculateInflationRate recalculates the inflation rate and anual provisions for a new block +// CalculateInflationRate recalculates the inflation rate and annual provisions for a new block func (k Keeper) CalculateInflationRate(ctx sdk.Context) { minter := k.GetMinter(ctx) params := k.GetParams(ctx) diff --git a/x/supply/alias.go b/x/supply/alias.go index d772e489b23d..1cc7cf04cb76 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -16,6 +16,8 @@ var ( NewKeeper = keeper.NewKeeper RegisterInvariants = keeper.RegisterInvariants + NewSupplier = types.NewSupplier + DefaultSupplier = types.DefaultSupplier NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState ) diff --git a/x/supply/keeper/keeper.go b/x/supply/keeper/keeper.go index 25beae0b6b78..df95e3a1dc57 100644 --- a/x/supply/keeper/keeper.go +++ b/x/supply/keeper/keeper.go @@ -25,7 +25,7 @@ func (k Keeper) GetSupplier(ctx sdk.Context) (supplier types.Supplier) { store := ctx.KVStore(k.storeKey) b := store.Get(supplierKey) if b == nil { - panic("Stored fee pool should not have been nil") + panic("Stored supplier should not have been nil") } k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &supplier) return diff --git a/x/supply/keeper/keeper_test.go b/x/supply/keeper/keeper_test.go index e3ad055c43ef..21ed0af0afbe 100644 --- a/x/supply/keeper/keeper_test.go +++ b/x/supply/keeper/keeper_test.go @@ -16,23 +16,29 @@ import ( "github.com/cosmos/cosmos-sdk/x/supply/types" ) +var oneUatom = sdk.NewCoins(sdk.NewCoin("uatom", sdk.OneInt())) + func TestSupplier(t *testing.T) { ctx, keeper := CreateTestInput(t, false) - oneUatom := sdk.NewCoins(sdk.NewCoin("uatom", sdk.OneInt())) require.Panics(t, func() { keeper.GetSupplier(ctx) }, "should panic when supplier is not set") expectedSupplier := types.DefaultSupplier() - expectedSupplier.TotalSupply = expectedSupplier.CirculatingSupply.Add(oneUatom) - keeper.SetSupplier(ctx, expectedSupplier) - expectedSupplier.CirculatingSupply = expectedSupplier.CirculatingSupply.Add(oneUatom) - + // test inflation + expectedSupplier.Inflate(types.TypeCirculating, oneUatom) keeper.InflateSupply(ctx, types.TypeCirculating, oneUatom) supplier := keeper.GetSupplier(ctx) - require.Equal(t, expectedSupplier, supplier) + require.Equal(t, expectedSupplier.CirculatingSupply, supplier.CirculatingSupply) + + // test deflation + expectedSupplier.Deflate(types.TypeCirculating, oneUatom) + keeper.DeflateSupply(ctx, types.TypeCirculating, oneUatom) + + supplier = keeper.GetSupplier(ctx) + require.Equal(t, expectedSupplier.CirculatingSupply, supplier.CirculatingSupply) } func CreateTestInput(t *testing.T, isCheckTx bool) (sdk.Context, Keeper) { diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 506215421e2e..0cc0ce1fab67 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -35,8 +35,8 @@ func NewSupplier(circulating, vesting, modules, total sdk.Coins) Supplier { // DefaultSupplier creates an empty Supplier func DefaultSupplier() Supplier { - - return NewSupplier(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) + zeroBondCoin := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt())) + return NewSupplier(zeroBondCoin, zeroBondCoin, zeroBondCoin, zeroBondCoin) } // Inflate adds coins to a given supply type and updates the total supply @@ -60,40 +60,19 @@ func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { } } -// Deflate safe subtracts coins for a given supply and updates the total supply +// Deflate subtracts coins for a given supply and updates the total supply func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { switch supplyType { case TypeCirculating: - newSupply, ok := supplier.CirculatingSupply.SafeSub(amount) - if !ok { - panic(fmt.Sprintf( - "circulating supply should be greater than given amount: %s < %s", - supplier.CirculatingSupply.String(), amount.String(), - )) - } - supplier.CirculatingSupply = newSupply + supplier.CirculatingSupply = supplier.CirculatingSupply.Sub(amount) case TypeModules: - newSupply, ok := supplier.ModulesSupply.SafeSub(amount) - if !ok { - panic(fmt.Sprintf( - "modules supply should be greater than given amount: %s < %s", - supplier.ModulesSupply.String(), amount.String(), - )) - } - supplier.ModulesSupply = newSupply + supplier.ModulesSupply = supplier.ModulesSupply.Sub(amount) case TypeTotal: - newSupply, ok := supplier.TotalSupply.SafeSub(amount) - if !ok { - panic(fmt.Sprintf( - "total supply should be greater than given amount: %s < %s", - supplier.TotalSupply.String(), amount.String(), - )) - } - supplier.TotalSupply = newSupply + supplier.TotalSupply = supplier.TotalSupply.Sub(amount) default: panic(fmt.Errorf("invalid type %s", supplyType)) From e6b4e796eb7d162fa4eda5d38831ef9214cdc302 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 25 Apr 2019 23:35:31 +0200 Subject: [PATCH 39/46] fix gov tests --- cmd/gaia/app/app.go | 2 +- cmd/gaia/app/app_test.go | 2 -- x/gov/expected_keepers.go | 2 ++ x/gov/test_common.go | 12 ++++++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 6cdd6e9606b7..191edaeb8d03 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -196,7 +196,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b // initialize BaseApp app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint, app.keyDistr, - app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams, + app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams, app.keySupply, app.tkeyParams, app.tkeyStaking, app.tkeyDistr, ) app.SetInitChainer(app.initChainer) diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index 7a13c4178875..de21f585ac3f 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -1,7 +1,6 @@ package app import ( - "fmt" "os" "testing" @@ -43,7 +42,6 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error { supply.DefaultGenesisState(), ) - fmt.Println(genesisState.SupplyData) stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState) if err != nil { return err diff --git a/x/gov/expected_keepers.go b/x/gov/expected_keepers.go index 4009d8e34a69..7e277b37fa24 100644 --- a/x/gov/expected_keepers.go +++ b/x/gov/expected_keepers.go @@ -3,6 +3,7 @@ package gov import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/supply" ) // AccountKeeper defines the expected account keeper @@ -22,4 +23,5 @@ type BankKeeper interface { type SupplyKeeper interface { InflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) DeflateSupply(ctx sdk.Context, supplyType string, amount sdk.Coins) + SetSupplier(ctx sdk.Context, supplier supply.Supplier) // used for testing } diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 88bd13d1fe8b..61801652b3de 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -29,18 +29,16 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a staking.RegisterCodec(mapp.Cdc) RegisterCodec(mapp.Cdc) - keyAccount := sdk.NewKVStoreKey(auth.StoreKey) keyStaking := sdk.NewKVStoreKey(staking.StoreKey) tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) keySupply := sdk.NewKVStoreKey(supply.StoreKey) keyGov := sdk.NewKVStoreKey(StoreKey) pk := mapp.ParamsKeeper - ak := auth.NewAccountKeeper(mapp.Cdc, keyAccount, mapp.ParamsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bk := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) sk := supply.NewKeeper(mapp.Cdc, keySupply) ds = staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, bk, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) - keeper = NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), bk, ak, sk, ds, DefaultCodespace) + keeper = NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), bk, mapp.AccountKeeper, sk, ds, DefaultCodespace) mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) mapp.QueryRouter().AddRoute(QuerierRoute, NewQuerier(keeper)) @@ -48,7 +46,7 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a mapp.SetEndBlocker(getEndBlocker(keeper)) mapp.SetInitChainer(getInitChainer(mapp, keeper, ds, genState)) - require.NoError(t, mapp.CompleteSetup(keyStaking, tkeyStaking, keyGov)) + require.NoError(t, mapp.CompleteSetup(keyStaking, tkeyStaking, keyGov, keySupply)) valTokens := sdk.TokensFromTendermintPower(42) if genAccs == nil || len(genAccs) == 0 { @@ -80,6 +78,12 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, tokens := sdk.TokensFromTendermintPower(100000) stakingGenesis.Pool.NotBondedTokens = tokens + supplier := supply.DefaultSupplier() + supplier.Inflate(supply.TypeTotal, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000)))) + supplier.Inflate(supply.TypeCirculating, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000)))) + + keeper.supplyKeeper.SetSupplier(ctx, supplier) + validators, err := staking.InitGenesis(ctx, stakingKeeper, stakingGenesis) if err != nil { panic(err) From 7b9dd436e0cc1dbb3fc67069b69743bc997d15c3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 26 Apr 2019 11:38:35 +0200 Subject: [PATCH 40/46] add invariant to bonded tokens --- cmd/gaia/app/app.go | 2 +- x/auth/codec.go | 6 ++++++ x/staking/keeper/invariants.go | 23 ++++++++++++++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 191edaeb8d03..939f333fc301 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -172,7 +172,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b // register the crisis routes bank.RegisterInvariants(&app.crisisKeeper, app.accountKeeper) distr.RegisterInvariants(&app.crisisKeeper, app.distrKeeper, app.stakingKeeper) - staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper) + staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper, app.supplyKeeper) supply.RegisterInvariants(&app.crisisKeeper, app.supplyKeeper, app.accountKeeper, app.distrKeeper, app.feeCollectionKeeper, app.stakingKeeper) diff --git a/x/auth/codec.go b/x/auth/codec.go index 0d7694300f1f..6ee243c6b167 100644 --- a/x/auth/codec.go +++ b/x/auth/codec.go @@ -12,6 +12,9 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(&BaseVestingAccount{}, "auth/BaseVestingAccount", nil) cdc.RegisterConcrete(&ContinuousVestingAccount{}, "auth/ContinuousVestingAccount", nil) cdc.RegisterConcrete(&DelayedVestingAccount{}, "auth/DelayedVestingAccount", nil) + cdc.RegisterInterface((*ModuleAccount)(nil), nil) + cdc.RegisterConcrete(&ModuleHolderAccount{}, "auth/ModuleHolderAccount", nil) + cdc.RegisterConcrete(&ModuleMinterAccount{}, "auth/ModuleMinterAccount", nil) cdc.RegisterConcrete(StdTx{}, "auth/StdTx", nil) } @@ -23,6 +26,9 @@ func RegisterBaseAccount(cdc *codec.Codec) { cdc.RegisterConcrete(&BaseVestingAccount{}, "cosmos-sdk/BaseVestingAccount", nil) cdc.RegisterConcrete(&ContinuousVestingAccount{}, "cosmos-sdk/ContinuousVestingAccount", nil) cdc.RegisterConcrete(&DelayedVestingAccount{}, "cosmos-sdk/DelayedVestingAccount", nil) + cdc.RegisterInterface((*ModuleAccount)(nil), nil) + cdc.RegisterConcrete(&ModuleHolderAccount{}, "auth/ModuleHolderAccount", nil) + cdc.RegisterConcrete(&ModuleMinterAccount{}, "auth/ModuleMinterAccount", nil) codec.RegisterCrypto(cdc) } diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go index 632ba0b9d657..3d2760e66d41 100644 --- a/x/staking/keeper/invariants.go +++ b/x/staking/keeper/invariants.go @@ -6,13 +6,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/supply" ) // RegisterInvariants registers all staking invariants -func RegisterInvariants(c types.CrisisKeeper, k Keeper) { +func RegisterInvariants(c types.CrisisKeeper, k Keeper, supplyKeeper supply.Keeper) { c.RegisterRoute(types.ModuleName, "bonded-tokens", - BondedTokensInvariant(k)) + BondedTokensInvariant(k, supplyKeeper)) c.RegisterRoute(types.ModuleName, "nonnegative-power", NonNegativePowerInvariant(k)) c.RegisterRoute(types.ModuleName, "positive-delegation", @@ -22,11 +23,11 @@ func RegisterInvariants(c types.CrisisKeeper, k Keeper) { } // AllInvariants runs all invariants of the staking module. -func AllInvariants(k Keeper) sdk.Invariant { +func AllInvariants(k Keeper, supplyKeeper supply.Keeper) sdk.Invariant { return func(ctx sdk.Context) error { - err := BondedTokensInvariant(k)(ctx) + err := BondedTokensInvariant(k, supplyKeeper)(ctx) if err != nil { return err } @@ -51,9 +52,12 @@ func AllInvariants(k Keeper) sdk.Invariant { } // BondedTokensInvariant checks that the total bonded tokens reflects all bonded tokens in delegations -func BondedTokensInvariant(k Keeper) sdk.Invariant { +func BondedTokensInvariant(k Keeper, supplyKeeper supply.Keeper) sdk.Invariant { return func(ctx sdk.Context) error { pool := k.GetPool(ctx) + supplier := supplyKeeper.GetSupplier(ctx) + + bondDenom := k.BondDenom(ctx) bonded := sdk.ZeroDec() k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool { @@ -72,6 +76,15 @@ func BondedTokensInvariant(k Keeper) sdk.Invariant { "\tsum of account tokens: %v", pool.BondedTokens, bonded) } + stakingTokensFromPool := pool.StakingTokenSupply() + stakingTokensFromSupplier := supplier.TotalAmountOf(bondDenom) + + if !stakingTokensFromPool.Equal(stakingTokensFromSupplier) { + return fmt.Errorf("total bonded token invariance:\n"+ + "\tpool.StakingTokenSupply: %v\n"+ + "\tsupplier.Total of bonded denom: %v", stakingTokensFromPool, stakingTokensFromSupplier) + } + return nil } } From d612bc10d75c02154a908ea2d0e40e86483d2662 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 26 Apr 2019 12:25:23 +0200 Subject: [PATCH 41/46] minor fixes --- types/staking.go | 2 +- x/auth/account.go | 5 ----- x/crisis/handler_test.go | 2 +- x/gov/expected_keepers.go | 2 +- x/gov/keeper.go | 18 +++++------------- x/gov/test_common.go | 4 ++-- 6 files changed, 10 insertions(+), 23 deletions(-) diff --git a/types/staking.go b/types/staking.go index 58ba094603ce..d3a388c937db 100644 --- a/types/staking.go +++ b/types/staking.go @@ -17,7 +17,7 @@ const ( Bonded BondStatus = 0x02 // default bond denomination - DefaultBondDenom = "uatom" + DefaultBondDenom = "stake" // Delay, in blocks, between when validator updates are returned to Tendermint and when they are applied. // For example, if this is 0, the validator set at the end of a block will sign the next block, or diff --git a/x/auth/account.go b/x/auth/account.go index a2fd71a04c1e..af63f3f79ae3 100644 --- a/x/auth/account.go +++ b/x/auth/account.go @@ -563,8 +563,3 @@ func NewModuleHolderAccount(moduleName string) *ModuleHolderAccount { return &ModuleHolderAccount{ModuleMinterAccount: moduleMinterAcc} } - -// SetCoins not supported for ModuleHolderAccount -func (mha ModuleHolderAccount) SetCoins(coins sdk.Coins) error { - return fmt.Errorf("module holders account don't support setting coins") -} diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index acc920e4a1ea..e4f512f174ce 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -23,7 +23,7 @@ var ( func CreateTestInput(t *testing.T) (sdk.Context, Keeper, auth.AccountKeeper, distr.Keeper) { communityTax := sdk.NewDecWithPrec(2, 2) - ctx, accKeeper, bankKeeper, distrKeeper, _, feeCollectionKeeper, paramsKeeper := + ctx, accKeeper, bankKeeper, distrKeeper, _, feeCollectionKeeper, _, paramsKeeper := distr.CreateTestInputAdvanced(t, false, 10, communityTax) paramSpace := paramsKeeper.Subspace(DefaultParamspace) diff --git a/x/gov/expected_keepers.go b/x/gov/expected_keepers.go index 7e277b37fa24..9f639e19d799 100644 --- a/x/gov/expected_keepers.go +++ b/x/gov/expected_keepers.go @@ -15,8 +15,8 @@ type AccountKeeper interface { // BankKeeper defines the expected bank keeper type BankKeeper interface { GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error } // SupplyKeeper defines the expected supply keeper diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 3f7337737449..107de482025c 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -68,7 +68,7 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, } // Logger returns a module-specific logger. -func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/gov") } +func (keeper Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/gov") } // Proposals func (keeper Keeper) SubmitProposal(ctx sdk.Context, content ProposalContent) (proposal Proposal, err sdk.Error) { @@ -357,9 +357,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd } // update the governance module account coin pool - moduleAddress, _ := sdk.AccAddressFromBech32(ModuleName) - - _, err := keeper.ck.AddCoins(ctx, moduleAddress, depositAmount) + err := keeper.ck.SendCoins(ctx, depositorAddr, ModuleAddress, depositAmount) if err != nil { return err, false } @@ -401,7 +399,6 @@ func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID uint64) sdk.Iterato // RefundDeposits Refunds and deletes all the deposits on a specific proposal func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { store := ctx.KVStore(keeper.storeKey) - moduleAddress, _ := sdk.AccAddressFromBech32(ModuleName) depositsIterator := keeper.GetDeposits(ctx, proposalID) defer depositsIterator.Close() for ; depositsIterator.Valid(); depositsIterator.Next() { @@ -409,12 +406,7 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) // update the governance module account coin pool - _, err := keeper.ck.SubtractCoins(ctx, moduleAddress, deposit.Amount) - if err != nil { - panic(err) - } - - _, err = keeper.ck.AddCoins(ctx, deposit.Depositor, deposit.Amount) + err := keeper.ck.SendCoins(ctx, ModuleAddress, deposit.Depositor, deposit.Amount) if err != nil { panic(err) } @@ -430,7 +422,6 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { // DeleteDeposits Deletes all the deposits on a specific proposal without refunding them func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { store := ctx.KVStore(keeper.storeKey) - moduleAddress, _ := sdk.AccAddressFromBech32(ModuleName) depositsIterator := keeper.GetDeposits(ctx, proposalID) defer depositsIterator.Close() for ; depositsIterator.Valid(); depositsIterator.Next() { @@ -438,7 +429,8 @@ func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) // update the governance module account coin pool - _, err := keeper.ck.SubtractCoins(ctx, moduleAddress, deposit.Amount) + // burn deposit + _, err := keeper.ck.SubtractCoins(ctx, ModuleAddress, deposit.Amount) if err != nil { panic(err) } diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 61801652b3de..5d9f6bdcbff8 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -79,8 +79,8 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, stakingGenesis.Pool.NotBondedTokens = tokens supplier := supply.DefaultSupplier() - supplier.Inflate(supply.TypeTotal, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000)))) - supplier.Inflate(supply.TypeCirculating, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000)))) + supplier.Inflate(supply.TypeTotal, sdk.NewCoins(sdk.NewCoin(stakingGenesis.Params.BondDenom, sdk.NewInt(100000)))) + supplier.Inflate(supply.TypeCirculating, sdk.NewCoins(sdk.NewCoin(stakingGenesis.Params.BondDenom, sdk.NewInt(100000)))) keeper.supplyKeeper.SetSupplier(ctx, supplier) From 1fddb0ef935a91429083cd36f66204213a962d49 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sun, 28 Apr 2019 16:01:29 +0200 Subject: [PATCH 42/46] minor invariant changes --- cmd/gaia/app/genesis.go | 15 +++++-------- x/supply/keeper/invariants.go | 41 +++++++++++++++++++++++++---------- x/supply/types/supplier.go | 16 +++++++++----- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index af0602fdb628..139da2cb74a7 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -221,12 +221,11 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } } - notBondedSupply, bondedSupply := + notBondedSupply := updateSupplyFromGenAccounts(genesisState.Accounts, genDoc.GenesisTime, genesisState.StakingData, &genesisState.SupplyData.Supplier) genesisState.StakingData.Pool.NotBondedTokens = notBondedSupply - genesisState.StakingData.Pool.BondedTokens = bondedSupply genesisState.GenTxs = appGenTxs @@ -440,7 +439,8 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm // updateSupplyFromGenAccounts updates the total, circulating, vesting, modules and staking (bonded and not bonded) // supplies from the info provided on genesis accounts func updateSupplyFromGenAccounts(genAccounts []GenesisAccount, genesisTime time.Time, - stakingData staking.GenesisState, supplier *supply.Supplier) (notBondedTokens, bondedTokens sdk.Int) { + stakingData staking.GenesisState, supplier *supply.Supplier) (notBondedTokens sdk.Int) { + notBondedTokens = stakingData.Pool.NotBondedTokens for _, genAcc := range genAccounts { // update initial vesting, circulating and bonded supplies from vesting accounts @@ -459,17 +459,14 @@ func updateSupplyFromGenAccounts(genAccounts []GenesisAccount, genesisTime time. } // update staking pool's not bonded supply - notBondedAmount := genAcc.Coins.AmountOf(stakingData.Params.BondDenom) - if notBondedAmount.GT(sdk.ZeroInt()) { - notBondedTokens = notBondedTokens.Add(notBondedAmount) - } + notBondedTokens = notBondedTokens.Add(genAcc.Coins.AmountOf(stakingData.Params.BondDenom)) supplier.Inflate(supply.TypeTotal, genAcc.Coins) } // add bonded tokens to total supply - bondedSupply := sdk.NewCoins(sdk.NewCoin(stakingData.Params.BondDenom, stakingData.Pool.BondedTokens)) - supplier.Inflate(supply.TypeTotal, bondedSupply) + bondedTokens := sdk.NewCoins(sdk.NewCoin(stakingData.Params.BondDenom, stakingData.Pool.BondedTokens)) + supplier.Inflate(supply.TypeTotal, bondedTokens) return } diff --git a/x/supply/keeper/invariants.go b/x/supply/keeper/invariants.go index 9a936848884a..3f6fd3322677 100644 --- a/x/supply/keeper/invariants.go +++ b/x/supply/keeper/invariants.go @@ -12,8 +12,13 @@ func RegisterInvariants(ck CrisisKeeper, k Keeper, accountKeeper AccountKeeper, distributionKeeper DistributionKeeper, feeCollectionKeeper FeeCollectionKeeper, stakingKeeper StakingKeeper) { ck.RegisterRoute( - ModuleName, "supply", - SupplyInvariants(k, accountKeeper, distributionKeeper, feeCollectionKeeper, stakingKeeper)) + ModuleName, "supplier", + SupplierInvariants(k, accountKeeper), + ) + ck.RegisterRoute( + ModuleName, "total-supply", + TotalSupplyInvariant(k, distributionKeeper, feeCollectionKeeper, stakingKeeper), + ) } // AllInvariants runs all invariants of the staking module. @@ -21,7 +26,12 @@ func AllInvariants(k Keeper, accountKeeper AccountKeeper, distributionKeeper Dis feeCollectionKeeper FeeCollectionKeeper, stakingKeeper StakingKeeper) sdk.Invariant { return func(ctx sdk.Context) error { - err := SupplyInvariants(k, accountKeeper, distributionKeeper, feeCollectionKeeper, stakingKeeper)(ctx) + err := SupplierInvariants(k, accountKeeper)(ctx) + if err != nil { + return err + } + + err = TotalSupplyInvariant(k, distributionKeeper, feeCollectionKeeper, stakingKeeper)(ctx) if err != nil { return err } @@ -30,10 +40,8 @@ func AllInvariants(k Keeper, accountKeeper AccountKeeper, distributionKeeper Dis } } -// SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations -func SupplyInvariants(k Keeper, - accountKeeper AccountKeeper, distributionKeeper DistributionKeeper, - feeCollectionKeeper FeeCollectionKeeper, stakingKeeper StakingKeeper) sdk.Invariant { +// SupplierInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations +func SupplierInvariants(k Keeper, accountKeeper AccountKeeper) sdk.Invariant { return func(ctx sdk.Context) error { supplier := k.GetSupplier(ctx) @@ -78,6 +86,17 @@ func SupplyInvariants(k Keeper, "\tsum of vesting tokens: %v", supplier.InitialVestingSupply, initialVestingAmount) } + return nil + } +} + +// TotalSupplyInvariant checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations +func TotalSupplyInvariant(k Keeper, distributionKeeper DistributionKeeper, + feeCollectionKeeper FeeCollectionKeeper, stakingKeeper StakingKeeper) sdk.Invariant { + + return func(ctx sdk.Context) error { + supplier := k.GetSupplier(ctx) + bondedSupply := sdk.NewCoins(sdk.NewCoin(stakingKeeper.BondDenom(ctx), stakingKeeper.TotalBondedTokens(ctx))) collectedFees := feeCollectionKeeper.GetCollectedFees(ctx) communityPool, remainingCommunityPool := distributionKeeper.GetFeePoolCommunityCoins(ctx).TruncateDecimal() @@ -85,7 +104,7 @@ func SupplyInvariants(k Keeper, remaining, _ := remainingCommunityPool.Add(remainingRewards).TruncateDecimal() - expectedTotalSupply := supplier.CirculatingSupply. + realTotalSupply := supplier.CirculatingSupply. Add(supplier.ModulesSupply). Add(bondedSupply). Add(collectedFees). @@ -93,10 +112,10 @@ func SupplyInvariants(k Keeper, Add(totalRewards). Add(remaining) - if !supplier.TotalSupply.IsEqual(expectedTotalSupply) { + if !supplier.TotalSupply.IsEqual(realTotalSupply) { return fmt.Errorf("total supply invariance:\n"+ - "\texpected total supply: %v\n"+ - "\treal total supply: %v", expectedTotalSupply, supplier.TotalSupply) + "\tsupplier.TotalSupply: %v\n"+ + "\tcalculated total supply: %v", supplier.TotalSupply, realTotalSupply) } return nil diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 0cc0ce1fab67..8484965fbd6b 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -35,11 +35,11 @@ func NewSupplier(circulating, vesting, modules, total sdk.Coins) Supplier { // DefaultSupplier creates an empty Supplier func DefaultSupplier() Supplier { - zeroBondCoin := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt())) - return NewSupplier(zeroBondCoin, zeroBondCoin, zeroBondCoin, zeroBondCoin) + coins := sdk.NewCoins() + return NewSupplier(coins, coins, coins, coins) } -// Inflate adds coins to a given supply type and updates the total supply +// Inflate adds coins to a given supply type func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { switch supplyType { @@ -60,7 +60,7 @@ func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { } } -// Deflate subtracts coins for a given supply and updates the total supply +// Deflate subtracts coins for a given supply func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { switch supplyType { @@ -85,7 +85,7 @@ func (supplier Supplier) CirculatingAmountOf(denom string) sdk.Int { return supplier.CirculatingSupply.AmountOf(denom) } -// VestingAmountOf returns the vesting supply of a coin denomination +// InitalVestingAmountOf returns the vesting supply of a coin denomination func (supplier Supplier) InitalVestingAmountOf(denom string) sdk.Int { return supplier.InitialVestingSupply.AmountOf(denom) @@ -122,6 +122,12 @@ func (supplier Supplier) ValidateBasic() sdk.Error { ) } + if !supplier.TotalSupply.IsValid() { + return sdk.ErrInvalidCoins( + fmt.Sprintf("invalid total supply: %s", supplier.ModulesSupply.String()), + ) + } + return nil } From 392e34260d05d2274a367f3ee0ec24bca7739985 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 29 Apr 2019 14:18:08 +0200 Subject: [PATCH 43/46] fix some gov tests; pending invariance --- x/gov/keeper_test.go | 25 +++++++++++++++++++++---- x/gov/test_common.go | 22 ++++++++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/x/gov/keeper_test.go b/x/gov/keeper_test.go index 12aee4651948..cb012bbea264 100644 --- a/x/gov/keeper_test.go +++ b/x/gov/keeper_test.go @@ -102,6 +102,10 @@ func TestDeposits(t *testing.T) { require.Equal(t, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, expTokens)), addr0Initial) require.True(t, proposal.TotalDeposit.IsEqual(sdk.NewCoins())) + moduleAcc := keeper.ak.GetAccount(ctx, ModuleAddress) + deposits := proposal.TotalDeposit + require.True(t, moduleAcc.GetCoins().IsEqual(deposits)) + // Check no deposits at beginning deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1]) require.False(t, found) @@ -122,32 +126,45 @@ func TestDeposits(t *testing.T) { require.Equal(t, fourStake, proposal.TotalDeposit) require.Equal(t, addr0Initial.Sub(fourStake), keeper.ck.GetCoins(ctx, addrs[0])) + moduleAcc = keeper.ak.GetAccount(ctx, ModuleAddress) + deposits = deposits.Add(fourStake) + require.True(t, moduleAcc.GetCoins().IsEqual(deposits)) + // Check a second deposit from same address err, votingStarted = keeper.AddDeposit(ctx, proposalID, addrs[0], fiveStake) require.Nil(t, err) require.False(t, votingStarted) + deposits = fourStake.Add(fiveStake) deposit, found = keeper.GetDeposit(ctx, proposalID, addrs[0]) require.True(t, found) - require.Equal(t, fourStake.Add(fiveStake), deposit.Amount) + require.Equal(t, deposits, deposit.Amount) require.Equal(t, addrs[0], deposit.Depositor) proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) - require.Equal(t, fourStake.Add(fiveStake), proposal.TotalDeposit) - require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), keeper.ck.GetCoins(ctx, addrs[0])) + require.Equal(t, deposits, proposal.TotalDeposit) + require.Equal(t, addr0Initial.Sub(deposits), keeper.ck.GetCoins(ctx, addrs[0])) + + moduleAcc = keeper.ak.GetAccount(ctx, ModuleAddress) + + require.True(t, moduleAcc.GetCoins().IsEqual(deposits)) // Check third deposit from a new address err, votingStarted = keeper.AddDeposit(ctx, proposalID, addrs[1], fourStake) require.Nil(t, err) require.True(t, votingStarted) + deposits = deposits.Add(fourStake) deposit, found = keeper.GetDeposit(ctx, proposalID, addrs[1]) require.True(t, found) require.Equal(t, addrs[1], deposit.Depositor) require.Equal(t, fourStake, deposit.Amount) proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) - require.Equal(t, fourStake.Add(fiveStake).Add(fourStake), proposal.TotalDeposit) + require.Equal(t, deposits, proposal.TotalDeposit) require.Equal(t, addr1Initial.Sub(fourStake), keeper.ck.GetCoins(ctx, addrs[1])) + moduleAcc = keeper.ak.GetAccount(ctx, ModuleAddress) + require.True(t, moduleAcc.GetCoins().IsEqual(deposits)) + // Check that proposal moved to voting period proposal, ok = keeper.GetProposal(ctx, proposalID) require.True(t, ok) diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 5d9f6bdcbff8..53eb6264bc71 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -43,16 +43,17 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) mapp.QueryRouter().AddRoute(QuerierRoute, NewQuerier(keeper)) - mapp.SetEndBlocker(getEndBlocker(keeper)) - mapp.SetInitChainer(getInitChainer(mapp, keeper, ds, genState)) - - require.NoError(t, mapp.CompleteSetup(keyStaking, tkeyStaking, keyGov, keySupply)) - valTokens := sdk.TokensFromTendermintPower(42) + coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, valTokens)) if genAccs == nil || len(genAccs) == 0 { - genAccs, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs, - sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, valTokens)}) + genAccs, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs, coins) } + accountsSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, coins.AmountOf(sdk.DefaultBondDenom).MulRaw(42))) + + mapp.SetEndBlocker(getEndBlocker(keeper)) + mapp.SetInitChainer(getInitChainer(mapp, keeper, ds, genState, accountsSupply)) + + require.NoError(t, mapp.CompleteSetup(keyStaking, tkeyStaking, keyGov, keySupply)) mock.SetGenesis(mapp, genAccs) @@ -70,7 +71,7 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker { } // gov and staking initchainer -func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, genState GenesisState) sdk.InitChainer { +func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, genState GenesisState, accountsSupply sdk.Coins) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) @@ -79,8 +80,9 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, stakingGenesis.Pool.NotBondedTokens = tokens supplier := supply.DefaultSupplier() - supplier.Inflate(supply.TypeTotal, sdk.NewCoins(sdk.NewCoin(stakingGenesis.Params.BondDenom, sdk.NewInt(100000)))) - supplier.Inflate(supply.TypeCirculating, sdk.NewCoins(sdk.NewCoin(stakingGenesis.Params.BondDenom, sdk.NewInt(100000)))) + notBondedSupply := sdk.NewCoins(sdk.NewCoin(stakingGenesis.Params.BondDenom, sdk.NewInt(100000))) + supplier.Inflate(supply.TypeTotal, notBondedSupply.Add(accountsSupply)) + supplier.Inflate(supply.TypeCirculating, notBondedSupply.Add(accountsSupply)) keeper.supplyKeeper.SetSupplier(ctx, supplier) From b985bacef075273887c09f66b253bc523d893ea5 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 30 Apr 2019 12:32:41 +0200 Subject: [PATCH 44/46] delete mint account from genaccs --- client/lcd/test_helpers.go | 3 ++ cmd/gaia/app/genesis.go | 70 ++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 329b93ff6964..a69997ec6567 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -286,8 +286,11 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress accTokens := sdk.TokensFromTendermintPower(100) accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)} acc := gapp.NewGenesisAccount(&accAuth) + genesisState.Accounts = append(genesisState.Accounts, acc) genesisState.StakingData.Pool.NotBondedTokens = genesisState.StakingData.Pool.NotBondedTokens.Add(accTokens) + genesisState.SupplyData.Supplier.TotalSupply = genesisState.SupplyData.Supplier.TotalSupply.Add(accAuth.Coins) + genesisState.SupplyData.Supplier.TotalSupply = genesisState.SupplyData.Supplier.CirculatingSupply.Add(accAuth.Coins) } inflationMin := sdk.ZeroDec() diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 139da2cb74a7..1c1b365b2d01 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -100,8 +100,7 @@ type GenesisAccount struct { EndTime int64 `json:"end_time"` // vesting end time (UNIX Epoch time) // module account fields - Module string `json:"module"` // name of the module - AllowMint bool `json:"allow_mint"` // checks for module account type + Module string `json:"module"` // name of the module } // NewGenesisAccount creates a GenesisAccount instance from a BaseAccount @@ -135,11 +134,6 @@ func NewGenesisAccountI(acc auth.Account) GenesisAccount { macc, ok := acc.(auth.ModuleAccount) if ok { gacc.Module = macc.GetModuleName() - if err := macc.SetCoins(macc.GetCoins()); err == nil { - gacc.AllowMint = true - } else { - gacc.AllowMint = false - } } return gacc @@ -180,9 +174,6 @@ func (ga *GenesisAccount) ToAccount() auth.Account { // module accounts if ga.Module != "" { - if ga.AllowMint { - return auth.NewModuleMinterAccount(ga.Module) - } return auth.NewModuleHolderAccount(ga.Module) } @@ -221,11 +212,7 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js } } - notBondedSupply := - updateSupplyFromGenAccounts(genesisState.Accounts, genDoc.GenesisTime, - genesisState.StakingData, &genesisState.SupplyData.Supplier) - - genesisState.StakingData.Pool.NotBondedTokens = notBondedSupply + genesisState = updateSupply(genesisState, genDoc.GenesisTime) genesisState.GenTxs = appGenTxs @@ -436,13 +423,16 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm return appGenTxs, persistentPeers, nil } -// updateSupplyFromGenAccounts updates the total, circulating, vesting, modules and staking (bonded and not bonded) +// updateSupply updates the total, circulating, vesting, modules and staking (bonded and not bonded) // supplies from the info provided on genesis accounts -func updateSupplyFromGenAccounts(genAccounts []GenesisAccount, genesisTime time.Time, - stakingData staking.GenesisState, supplier *supply.Supplier) (notBondedTokens sdk.Int) { - notBondedTokens = stakingData.Pool.NotBondedTokens +func updateSupply(genesisState GenesisState, genesisTime time.Time) GenesisState { + var total, totalRewards sdk.Coins + var remainingRewards sdk.DecCoins + + notBondedTokens := genesisState.StakingData.Pool.NotBondedTokens + supplier := &genesisState.SupplyData.Supplier - for _, genAcc := range genAccounts { + for _, genAcc := range genesisState.Accounts { // update initial vesting, circulating and bonded supplies from vesting accounts if genAcc.OriginalVesting.IsAllPositive() { if genesisTime.Unix() < genAcc.EndTime { @@ -459,15 +449,43 @@ func updateSupplyFromGenAccounts(genAccounts []GenesisAccount, genesisTime time. } // update staking pool's not bonded supply - notBondedTokens = notBondedTokens.Add(genAcc.Coins.AmountOf(stakingData.Params.BondDenom)) + notBondedTokens = notBondedTokens.Add(genAcc.Coins.AmountOf(genesisState.StakingData.Params.BondDenom)) + + total = total.Add(genAcc.Coins) + } + + genesisState.StakingData.Pool.NotBondedTokens = notBondedTokens + + // update total supply + bondedTokens := sdk.NewCoins(sdk.NewCoin(genesisState.StakingData.Params.BondDenom, genesisState.StakingData.Pool.BondedTokens)) + collectedFees := genesisState.AuthData.CollectedFees + communityPool, remainingCommunityPool := genesisState.DistrData.FeePool.CommunityPool.TruncateDecimal() - supplier.Inflate(supply.TypeTotal, genAcc.Coins) + for _, outstandingReward := range genesisState.DistrData.OutstandingRewards { + reward, remainder := outstandingReward.OutstandingRewards.TruncateDecimal() + totalRewards = totalRewards.Add(reward) + remainingRewards = remainingRewards.Add(remainder) } - // add bonded tokens to total supply - bondedTokens := sdk.NewCoins(sdk.NewCoin(stakingData.Params.BondDenom, stakingData.Pool.BondedTokens)) - supplier.Inflate(supply.TypeTotal, bondedTokens) - return + remaining, _ := remainingCommunityPool.Add(remainingRewards).TruncateDecimal() + + supplier.TotalSupply = total. + Add(bondedTokens). + Add(collectedFees). + Add(communityPool). + Add(totalRewards). + Add(remaining) + + // fmt.Printf(` + // total: %s + // bondedTokens: %s + // collectedFees: %s + // communityPool: %s + // totalRewards: %s + // remaining: %s + // `, total, bondedTokens, collectedFees, communityPool, totalRewards, remaining) + + return genesisState } func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount { From 2f0d7d0c13c13a6227229b51ccd3bf83c190457b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 30 Apr 2019 13:10:36 +0200 Subject: [PATCH 45/46] cleanup --- x/bank/errors.go | 9 ++---- x/bank/expected_keepers.go | 2 +- x/bank/keeper.go | 31 ++------------------ x/bank/msgs.go | 2 +- x/bank/params.go | 4 +-- x/gov/keeper.go | 49 +++++++++++++++++++++++++++----- x/gov/{key.go => keeper_keys.go} | 37 +----------------------- 7 files changed, 52 insertions(+), 82 deletions(-) rename x/gov/{key.go => keeper_keys.go} (74%) diff --git a/x/bank/errors.go b/x/bank/errors.go index b74f64cc4bb2..7c5feaf4a848 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -4,15 +4,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// CodeType definition -type CodeType = sdk.CodeType - // Bank errors reserve 100 ~ 199. const ( - DefaultCodespace sdk.CodespaceType = ModuleName + DefaultCodespace sdk.CodespaceType = "bank" - CodeSendDisabled CodeType = 101 - CodeInvalidInputsOutputs CodeType = 102 + CodeSendDisabled sdk.CodeType = 101 + CodeInvalidInputsOutputs sdk.CodeType = 102 ) // ErrNoInputs is an error diff --git a/x/bank/expected_keepers.go b/x/bank/expected_keepers.go index 7e66dbd6f440..6d256d926d6e 100644 --- a/x/bank/expected_keepers.go +++ b/x/bank/expected_keepers.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// CrisisKeeper expected crisis keeper +// expected crisis keeper type CrisisKeeper interface { RegisterRoute(moduleName, route string, invar sdk.Invariant) } diff --git a/x/bank/keeper.go b/x/bank/keeper.go index a500d1841505..05a5b3d6e31d 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -26,9 +26,6 @@ type Keeper interface { UndelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Tags, sdk.Error) } -//----------------------------------------------------------------------------- -// BaseKeeper - // BaseKeeper manages transfers between accounts. It implements the Keeper interface. type BaseKeeper struct { BaseSendKeeper @@ -38,8 +35,7 @@ type BaseKeeper struct { } // NewBaseKeeper returns a new BaseKeeper -func NewBaseKeeper( - ak auth.AccountKeeper, +func NewBaseKeeper(ak auth.AccountKeeper, paramSpace params.Subspace, codespace sdk.CodespaceType) BaseKeeper { @@ -92,9 +88,6 @@ func (keeper BaseKeeper) InputOutputCoins( return inputOutputCoins(ctx, keeper.ak, inputs, outputs) } -//------------------ Staking logic ------------------ -// TODO: consider moving out this of bank - // DelegateCoins performs delegation by deducting amt coins from an account with // address addr. For vesting accounts, delegations amounts are tracked for both // vesting and vested coins. @@ -122,9 +115,6 @@ func (keeper BaseKeeper) UndelegateCoins( return undelegateCoins(ctx, keeper.ak, addr, amt) } -//------------------------------------------------------- -// SendKeeper - // SendKeeper defines a module interface that facilitates the transfer of coins // between accounts without the possibility of creating coins. type SendKeeper interface { @@ -138,9 +128,6 @@ type SendKeeper interface { var _ SendKeeper = (*BaseSendKeeper)(nil) -//------------------------------------------------------- -// BaseSendKeeper - // BaseSendKeeper only allows transfers between accounts without the possibility of // creating coins. It implements the SendKeeper interface. type BaseSendKeeper struct { @@ -151,11 +138,8 @@ type BaseSendKeeper struct { } // NewBaseSendKeeper returns a new BaseSendKeeper. -func NewBaseSendKeeper( - ak auth.AccountKeeper, - paramSpace params.Subspace, - codespace sdk.CodespaceType, -) BaseSendKeeper { +func NewBaseSendKeeper(ak auth.AccountKeeper, + paramSpace params.Subspace, codespace sdk.CodespaceType) BaseSendKeeper { return BaseSendKeeper{ BaseViewKeeper: NewBaseViewKeeper(ak, codespace), @@ -188,9 +172,6 @@ func (keeper BaseSendKeeper) SetSendEnabled(ctx sdk.Context, enabled bool) { keeper.paramSpace.Set(ctx, ParamStoreKeySendEnabled, &enabled) } -//------------------------------------------------------- -// ViewKeeper - var _ ViewKeeper = (*BaseViewKeeper)(nil) // ViewKeeper defines a module interface that facilitates read only access to @@ -228,9 +209,6 @@ func (keeper BaseViewKeeper) Codespace() sdk.CodespaceType { return keeper.codespace } -//------------------------------------------------------- -// private functions - func getCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress) sdk.Coins { acc := am.GetAccount(ctx, addr) if acc == nil { @@ -378,9 +356,6 @@ func inputOutputCoins(ctx sdk.Context, am auth.AccountKeeper, inputs []Input, ou return allTags, nil } -//------------------------------------------------------- -// staking - func delegateCoins( ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins, ) (sdk.Tags, sdk.Error) { diff --git a/x/bank/msgs.go b/x/bank/msgs.go index 2455190d345b..c9b4f554482b 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -5,7 +5,7 @@ import ( ) // RouterKey is they name of the bank module -const RouterKey = ModuleName +const RouterKey = "bank" // MsgSend - high level transaction of the coin module type MsgSend struct { diff --git a/x/bank/params.go b/x/bank/params.go index e02f49487d6f..b381e4e847e5 100644 --- a/x/bank/params.go +++ b/x/bank/params.go @@ -5,10 +5,8 @@ import ( ) const ( - // ModuleName is the name of the module - ModuleName = "bank" // DefaultParamspace for params keeper - DefaultParamspace = ModuleName + DefaultParamspace = "bank" // DefaultSendEnabled enabled DefaultSendEnabled = true ) diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 107de482025c..f7185042c5cf 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -7,9 +7,47 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/log" ) +const ( + // ModuleKey is the name of the module + ModuleName = "gov" + + // StoreKey is the store key string for gov + StoreKey = ModuleName + + // RouterKey is the message route for gov + RouterKey = ModuleName + + // QuerierRoute is the querier route for gov + QuerierRoute = ModuleName + + // Parameter store default namestore + DefaultParamspace = ModuleName +) + +// Parameter store key +var ( + ParamStoreKeyDepositParams = []byte("depositparams") + ParamStoreKeyVotingParams = []byte("votingparams") + ParamStoreKeyTallyParams = []byte("tallyparams") + + // TODO: Find another way to implement this without using accounts, or find a cleaner way to implement it using accounts. + DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins"))) + BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins"))) +) + +// Key declaration for parameters +func ParamKeyTable() params.KeyTable { + return params.NewKeyTable( + ParamStoreKeyDepositParams, DepositParams{}, + ParamStoreKeyVotingParams, VotingParams{}, + ParamStoreKeyTallyParams, TallyParams{}, + ) +} + // Governance Keeper type Keeper struct { // The reference to the Param Keeper to get and set Global Params @@ -48,8 +86,6 @@ type Keeper struct { // - depositing funds into proposals, and activating upon sufficient funds being deposited // - users voting on proposals, with weight proportional to stake in the system // - and tallying the result of the vote. -// CONTRACT: Token Holder needs to be added into the bank keeper before calling -// this function func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, paramSpace params.Subspace, bk BankKeeper, ak AccountKeeper, supplyKeeper SupplyKeeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper { @@ -390,13 +426,13 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd return nil, activatedVotingPeriod } -// GetDeposits Gets all the deposits on a specific proposal as an sdk.Iterator +// Gets all the deposits on a specific proposal as an sdk.Iterator func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID uint64) sdk.Iterator { store := ctx.KVStore(keeper.storeKey) return sdk.KVStorePrefixIterator(store, KeyDepositsSubspace(proposalID)) } -// RefundDeposits Refunds and deletes all the deposits on a specific proposal +// Refunds and deletes all the deposits on a specific proposal func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { store := ctx.KVStore(keeper.storeKey) depositsIterator := keeper.GetDeposits(ctx, proposalID) @@ -419,7 +455,7 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) { } } -// DeleteDeposits Deletes all the deposits on a specific proposal without refunding them +// Deletes all the deposits on a specific proposal without refunding them func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { store := ctx.KVStore(keeper.storeKey) depositsIterator := keeper.GetDeposits(ctx, proposalID) @@ -428,8 +464,7 @@ func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) { deposit := &Deposit{} keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) - // update the governance module account coin pool - // burn deposit + // update the governance module account coin pool and burn deposit _, err := keeper.ck.SubtractCoins(ctx, ModuleAddress, deposit.Amount) if err != nil { panic(err) diff --git a/x/gov/key.go b/x/gov/keeper_keys.go similarity index 74% rename from x/gov/key.go rename to x/gov/keeper_keys.go index 81b0e488cdb8..7c9e311c750f 100644 --- a/x/gov/key.go +++ b/x/gov/keeper_keys.go @@ -5,34 +5,8 @@ import ( "fmt" "time" - "github.com/tendermint/tendermint/crypto" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/params" -) - -const ( - // ModuleKey is the name of the module - ModuleName = "gov" - - // StoreKey is the store key string for gov - StoreKey = ModuleName - - // RouterKey is the message route for gov - RouterKey = ModuleName - - // QuerierRoute is the querier route for gov - QuerierRoute = ModuleName - - // Parameter store default namestore - DefaultParamspace = ModuleName -) - -// Parameter store key -var ( - ParamStoreKeyDepositParams = []byte("depositparams") - ParamStoreKeyVotingParams = []byte("votingparams") - ParamStoreKeyTallyParams = []byte("tallyparams") + "github.com/tendermint/tendermint/crypto" ) // Key for getting a the next available proposalID from the store @@ -105,12 +79,3 @@ func KeyInactiveProposalQueueProposal(endTime time.Time, proposalID uint64) []by sdk.Uint64ToBigEndian(proposalID), }, KeyDelimiter) } - -// Key declaration for parameters -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - ParamStoreKeyDepositParams, DepositParams{}, - ParamStoreKeyVotingParams, VotingParams{}, - ParamStoreKeyTallyParams, TallyParams{}, - ) -} From acdc8e2f9f5f3d7e66ce87252ab9d140bec39756 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 30 Apr 2019 15:59:16 +0200 Subject: [PATCH 46/46] add type supply --- x/staking/keeper/invariants.go | 2 +- x/supply/alias.go | 15 +++++--- x/supply/types/supplier.go | 50 ++------------------------ x/supply/types/supply.go | 64 ++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 54 deletions(-) create mode 100644 x/supply/types/supply.go diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go index 3d2760e66d41..f4e4a757dcb2 100644 --- a/x/staking/keeper/invariants.go +++ b/x/staking/keeper/invariants.go @@ -77,7 +77,7 @@ func BondedTokensInvariant(k Keeper, supplyKeeper supply.Keeper) sdk.Invariant { } stakingTokensFromPool := pool.StakingTokenSupply() - stakingTokensFromSupplier := supplier.TotalAmountOf(bondDenom) + stakingTokensFromSupplier := supplier.TotalSupply.AmountOf(bondDenom) if !stakingTokensFromPool.Equal(stakingTokensFromSupplier) { return fmt.Errorf("total bonded token invariance:\n"+ diff --git a/x/supply/alias.go b/x/supply/alias.go index 6083e210ca55..5da39f24d4fc 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -9,6 +9,8 @@ import ( type ( Keeper = keeper.Keeper Supplier = types.Supplier + CoinsSupply = types.CoinsSupply + CoinSupply = types.CoinSupply GenesisState = types.GenesisState ) @@ -16,10 +18,14 @@ var ( NewKeeper = keeper.NewKeeper RegisterInvariants = keeper.RegisterInvariants - NewSupplier = types.NewSupplier - DefaultSupplier = types.DefaultSupplier - NewGenesisState = types.NewGenesisState - DefaultGenesisState = types.DefaultGenesisState + NewSupplier = types.NewSupplier + DefaultSupplier = types.DefaultSupplier + NewCoinsSupply = types.NewCoinsSupply + NewCoinsSupplyFromSupplier = types.NewCoinsSupplyFromSupplier + NewCoinSupply = types.NewCoinSupply + NewCoinSupplyFromSupplier = types.NewCoinSupplyFromSupplier + NewGenesisState = types.NewGenesisState + DefaultGenesisState = types.DefaultGenesisState ) const ( @@ -28,6 +34,5 @@ const ( TypeCirculating = types.TypeCirculating TypeVesting = types.TypeVesting TypeModules = types.TypeModules - TypeLiquid = types.TypeLiquid TypeTotal = types.TypeTotal ) diff --git a/x/supply/types/supplier.go b/x/supply/types/supplier.go index 87c9e09b90bf..8965bc4e6dd6 100644 --- a/x/supply/types/supplier.go +++ b/x/supply/types/supplier.go @@ -11,7 +11,6 @@ const ( TypeCirculating = "circulating" TypeVesting = "vesting" TypeModules = "modules" - TypeLiquid = "liquid" TypeTotal = "total" ) @@ -20,18 +19,16 @@ type Supplier struct { CirculatingSupply sdk.Coins `json:"circulating_supply"` // supply held by accounts that's not vesting; circulating = total - vesting InitialVestingSupply sdk.Coins `json:"initial_vesting_supply"` // initial locked supply held by vesting accounts ModulesSupply sdk.Coins `json:"modules_supply"` // supply held by modules acccounts - LiquidSupply sdk.Coins `json:"liquid_supply"` // sum of account spendable coins at a given time TotalSupply sdk.Coins `json:"total_supply"` // total supply of tokens on the chain } // NewSupplier creates a new Supplier instance -func NewSupplier(circulating, vesting, modules, liquid, total sdk.Coins) Supplier { +func NewSupplier(circulating, vesting, modules, total sdk.Coins) Supplier { return Supplier{ CirculatingSupply: circulating, InitialVestingSupply: vesting, ModulesSupply: modules, - LiquidSupply: liquid, TotalSupply: total, } } @@ -39,7 +36,7 @@ func NewSupplier(circulating, vesting, modules, liquid, total sdk.Coins) Supplie // DefaultSupplier creates an empty Supplier func DefaultSupplier() Supplier { coins := sdk.NewCoins() - return NewSupplier(coins, coins, coins, coins, coins) + return NewSupplier(coins, coins, coins, coins) } // Inflate adds coins to a given supply type @@ -55,9 +52,6 @@ func (supplier *Supplier) Inflate(supplyType string, amount sdk.Coins) { case TypeModules: supplier.ModulesSupply = supplier.ModulesSupply.Add(amount) - case TypeLiquid: - supplier.LiquidSupply = supplier.LiquidSupply.Add(amount) - case TypeTotal: supplier.TotalSupply = supplier.TotalSupply.Add(amount) @@ -77,9 +71,6 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { case TypeModules: supplier.ModulesSupply = supplier.ModulesSupply.Sub(amount) - case TypeLiquid: - supplier.LiquidSupply = supplier.LiquidSupply.Sub(amount) - case TypeTotal: supplier.TotalSupply = supplier.TotalSupply.Sub(amount) @@ -88,36 +79,6 @@ func (supplier *Supplier) Deflate(supplyType string, amount sdk.Coins) { } } -// CirculatingAmountOf returns the circulating supply of a coin denomination -func (supplier Supplier) CirculatingAmountOf(denom string) sdk.Int { - - return supplier.CirculatingSupply.AmountOf(denom) -} - -// InitalVestingAmountOf returns the vesting supply of a coin denomination -func (supplier Supplier) InitalVestingAmountOf(denom string) sdk.Int { - - return supplier.InitialVestingSupply.AmountOf(denom) -} - -// ModulesAmountOf returns the total token holders' supply of a coin denomination -func (supplier Supplier) ModulesAmountOf(denom string) sdk.Int { - - return supplier.ModulesSupply.AmountOf(denom) -} - -// LiquidAmountOf returns the liquid supply of a coin denomination -func (supplier Supplier) LiquidAmountOf(denom string) sdk.Int { - - return supplier.LiquidSupply.AmountOf(denom) -} - -// TotalAmountOf returns the sum of circulating, vesting and modules supply for a specific coin denomination -func (supplier Supplier) TotalAmountOf(denom string) sdk.Int { - - return supplier.TotalSupply.AmountOf(denom) -} - // ValidateBasic validates the Supply coins and returns error if invalid func (supplier Supplier) ValidateBasic() sdk.Error { @@ -136,11 +97,6 @@ func (supplier Supplier) ValidateBasic() sdk.Error { fmt.Sprintf("invalid token holders supply: %s", supplier.ModulesSupply.String()), ) } - if !supplier.LiquidSupply.IsValid() { - return sdk.ErrInvalidCoins( - fmt.Sprintf("invalid liquid supply: %s", supplier.LiquidSupply.String()), - ) - } if !supplier.TotalSupply.IsValid() { return sdk.ErrInvalidCoins( fmt.Sprintf("invalid total supply: %s", supplier.ModulesSupply.String()), @@ -156,11 +112,9 @@ func (supplier Supplier) String() string { Circulating Supply: %s Initial Vesting Supply: %s Modules Supply: %s - Liquid Supply: %s Total Supply: %s`, supplier.CirculatingSupply.String(), supplier.InitialVestingSupply.String(), supplier.ModulesSupply.String(), - supplier.LiquidSupply.String(), supplier.TotalSupply.String()) } diff --git a/x/supply/types/supply.go b/x/supply/types/supply.go new file mode 100644 index 000000000000..6661e5f962e4 --- /dev/null +++ b/x/supply/types/supply.go @@ -0,0 +1,64 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// CoinsSupply defines relevant supply information from all the coins tracked by the current chain. +// It is the format exported to clients. +type CoinsSupply struct { + Circulating sdk.Coins `json:"circulating"` // supply held by accounts that's not vesting; circulating = total - vesting + InitialVesting sdk.Coins `json:"initial_vesting"` // initial locked supply held by vesting accounts + Modules sdk.Coins `json:"modules"` // supply held by modules acccounts + Liquid sdk.Coins `json:"liquid"` // sum of account spendable coins at a given time + Total sdk.Coins `json:"total"` // total supply of tokens on the chain +} + +// NewCoinsSupply creates a supply instance for all the coins +func NewCoinsSupply(circulating, vesting, modules, liquid, total sdk.Coins) CoinsSupply { + return CoinsSupply{ + Circulating: circulating, + InitialVesting: vesting, + Modules: modules, + Liquid: liquid, + Total: total, + } +} + +// NewCoinsSupplyFromSupplier creates CoinsSupply instance from a given Supplier +func NewCoinsSupplyFromSupplier(supplier Supplier) CoinsSupply { + return NewCoinsSupply(supplier.CirculatingSupply, + supplier.InitialVestingSupply, supplier.ModulesSupply, + supplier.TotalSupply.Sub(supplier.InitialVestingSupply), supplier.TotalSupply) +} + +// CoinSupply defines the supply information for a single coin on the current chain. +// It is the format exported to clients when an individual denom is queried. +type CoinSupply struct { + Circulating sdk.Int `json:"circulating"` // supply held by accounts that's not vesting; circulating = total - vesting + InitialVesting sdk.Int `json:"initial_vesting"` // initial locked supply held by vesting accounts + Modules sdk.Int `json:"modules"` // supply held by modules acccounts + Liquid sdk.Int `json:"liquid"` // sum of account spendable coins at a given time + Total sdk.Int `json:"total"` // total supply of tokens on the chain +} + +// NewCoinSupply creates a supply instance for a single coin denom +func NewCoinSupply(circulating, vesting, modules, liquid, total sdk.Int) CoinSupply { + return CoinSupply{ + Circulating: circulating, + InitialVesting: vesting, + Modules: modules, + Liquid: liquid, + Total: total, + } +} + +// NewCoinSupplyFromSupplier creates CoinSupply instance from a given Supplier +func NewCoinSupplyFromSupplier(denom string, supplier Supplier) CoinSupply { + return NewCoinSupply( + supplier.CirculatingSupply.AmountOf(denom), + supplier.InitialVestingSupply.AmountOf(denom), + supplier.ModulesSupply.AmountOf(denom), + supplier.TotalSupply.Sub(supplier.InitialVestingSupply).AmountOf(denom), + supplier.TotalSupply.AmountOf(denom)) +}