-
Notifications
You must be signed in to change notification settings - Fork 368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nd kavamint touchups #1422
Nd kavamint touchups #1422
Conversation
for genesis and params (and other store objects)
repace proto stringers and remove getters; keep sdk.Dec values strings in protos; increase validation of sdk.Dec values in params; increase coverage; add module account permission checks; ensure import and export of genesis does not change state
@@ -216,6 +216,23 @@ | |||
] | |||
} | |||
}, | |||
{ | |||
"url": "./out/swagger/kava/kavamint/v1beta1/query.swagger.json", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is required for the swagger to be generated
import "gogoproto/gogo.proto"; | ||
|
||
option go_package = "github.com/kava-labs/kava/x/kavamint/types"; | ||
|
||
// Params wraps the governance parameters for the kavamint module | ||
message Params { | ||
option (gogoproto.goproto_stringer) = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We override the stringer since sdk.Dec doesn't work well with the built-in method
// yearly inflation of total token supply minted to the community pool. | ||
bytes community_pool_inflation = 1 [ | ||
string community_pool_inflation = 1 [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sdk.Dec should be strings - cosmos/cosmos-sdk#10863
@@ -11,7 +12,7 @@ option go_package = "github.com/kava-labs/kava/x/kavamint/types"; | |||
service Query { | |||
// Params queries the parameters of x/kavamint module. | |||
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { | |||
option (google.api.http).get = "/kava/kavamint/v1beta1/parameters"; | |||
option (google.api.http).get = "/kava/kavamint/v1beta1/params"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
standard is params
, though not all modules have followed it
@@ -12,8 +12,8 @@ import ( | |||
func BeginBlocker(ctx sdk.Context, k keeper.KeeperI) { | |||
params := k.GetParams(ctx) | |||
// determine seconds since last mint | |||
previousBlockTime, found := k.GetPreviousBlockTime(ctx) | |||
if !found || previousBlockTime.IsZero() { | |||
previousBlockTime := k.GetPreviousBlockTime(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just need to protect the zero case -- found is redundant since we have zero value
|
||
if macc := ak.GetModuleAccount(ctx, types.ModuleName); macc == nil { | ||
// get module account -- creates one with allowed permissions if it does not exist | ||
macc := ak.GetModuleAccount(ctx, types.ModuleName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually creates the module account, so the panic is just a double check incase that behavior changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, originally had no check but @DracoLi suggested i add one.
is pulling the call out of the nil check just for clarity on the fact this code potentially does something rather than just checks if an account exists?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote it both ways, but thought this was cleaner and easier to read without the permission check nested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could go either way on it, basically just increased the scope of macc
to use below
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) | ||
} | ||
|
||
// check module account has minter permissions | ||
if !macc.HasPermission(authtypes.Minter) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to check required permissions as well
|
||
// set store state from genesis | ||
keeper.SetParams(ctx, gs.Params) | ||
keeper.SetPreviousBlockTime(ctx, gs.PreviousBlockTime) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change in behavior here -- we allow the zero value to be set, which then gets populated on the first block. Genesis assumes to previous block
previousBlockTime = ctx.BlockTime() | ||
} | ||
return types.NewGenesisState(params, previousBlockTime) | ||
return types.NewGenesisState(keeper.GetParams(ctx), keeper.GetPreviousBlockTime(ctx)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No modifications to genesis on export.
We test that an imported genesis always results in the same exported genesis -- best not to make modifications outside of abci
if err := blockTime.UnmarshalBinary(b); err != nil { | ||
panic(err) | ||
} | ||
return blockTime, true | ||
|
||
return | ||
} | ||
|
||
// SetPreviousBlockTime set the time of the previous block | ||
func (k Keeper) SetPreviousBlockTime(ctx sdk.Context, blockTime time.Time) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We delete the key if the previous block time is blank
time "time" | ||
) | ||
|
||
var ( | ||
// DefaultPreviousBlockTime represents a time that is unset -- no previous block has occured | ||
DefaultPreviousBlockTime = time.Time{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change of default to assume no previous block and no accumulation on the first height after initgenesis
@pirtleshell we can set a previous block time explicity in the upgrade handler if we want
return fmt.Errorf("previous block time not set") | ||
} | ||
return nil | ||
return gs.Params.Validate() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unset is a valid case for new chains since there are no previous blocks
} | ||
}) | ||
} | ||
} | ||
|
||
func TestGenesis_JSONEncoding(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These json tests help serve as examples and prevent regressions in protobuf encoding/tags
x/kavamint/types/params.go
Outdated
// TODO consider lowering max rate. when it's this large the precision is very bad. | ||
MaxMintingRate = sdk.NewDecWithPrec(1765, 1) | ||
// MaxMintingRate returns the per second rate equivalent to 10,000% per year | ||
MaxMintingRate = sdk.MustNewDecFromStr("0.000000146028999310") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reduced the max per second rate significantly -- we should never need a value higher than this. The previous max was too high imo, which if a proposal had a typo could result in a lot of coins minted before another proposal could correct it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed to be the yearly value -- I got confused with the per second rates used in other modules
// String implements fmt.Stringer | ||
func (p Params) String() string { | ||
return fmt.Sprintf(`Params: | ||
CommunityPoolInflation: %s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a helpful change -- protobuf Stringer() doesn't show sdk.Dec with a decimal place
return fmt.Errorf("rate out of bounds. the max allowed rate is %s", MaxMintingRate) | ||
// validateRate ensures rate is properly initialized (non-nil), not negative, and not greater than the max rate | ||
func validateRate(rate sdk.Dec) error { | ||
if rate.IsNil() || rate.IsNegative() || rate.GT(MaxMintingRate) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's important to check that sdk.Dec values are not nill as they will panic if somehow set
@@ -1,48 +0,0 @@ | |||
package keeper | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed -- the legacy querier paths are not needed for new modules
@@ -44,7 +42,7 @@ func (suite *abciTestSuite) CheckCommunityPoolBalance(ctx sdk.Context, expectedA | |||
} | |||
|
|||
func TestGRPCQueryTestSuite(t *testing.T) { | |||
suite.Run(t, new(abciTestSuite)) | |||
//suite.Run(t, new(abciTestSuite)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reminder to re-enable this test
|
||
if macc := ak.GetModuleAccount(ctx, types.ModuleName); macc == nil { | ||
// get module account -- creates one with allowed permissions if it does not exist | ||
macc := ak.GetModuleAccount(ctx, types.ModuleName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, originally had no check but @DracoLi suggested i add one.
is pulling the call out of the nil check just for clarity on the fact this code potentially does something rather than just checks if an account exists?
} | ||
|
||
// SetPreviousBlockTime set the time of the previous block | ||
func (k Keeper) SetPreviousBlockTime(ctx sdk.Context, blockTime time.Time) { | ||
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PreviousBlockTimeKey) | ||
|
||
if blockTime.IsZero() { | ||
store.Delete(types.PreviousBlockTimeKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧠 nice, this makes sense.
}, | ||
{ | ||
"invalid - no time set", | ||
"vali - no time set", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"vali - no time set", | |
"valid - no time set", |
) | ||
|
||
// PreviousBlockTimeKey is the store key for the previous block time | ||
var PreviousBlockTimeKey = []byte{0x00} | ||
var PreviousBlockTimeKey = []byte{0x01} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
start w/ 1 to prevent confusion with nil value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm I think I fat fingered a key here, didn't mean to modify it
draft for review -- will rebase into feat branch instead of merging