-
Notifications
You must be signed in to change notification settings - Fork 389
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tm2/sdk/params): initial version
- Loading branch information
Showing
11 changed files
with
612 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package params | ||
|
||
const ( | ||
ModuleName = "params" | ||
StoreKey = ModuleName | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Package params provides a lightweight implementation inspired by the x/params | ||
// module of the Cosmos SDK. | ||
// | ||
// It includes a keeper for managing key-value pairs with module identifiers as | ||
// prefixes, along with a global querier for retrieving any key from any module. | ||
// | ||
// Changes: This version removes the concepts of subspaces and proposals, | ||
// allowing the creation of multiple keepers identified by a provided prefix. | ||
// Proposals may be added later when governance modules are introduced. The | ||
// transient store and .Modified helper have also been removed but can be | ||
// implemented later if needed. Keys are represented as strings instead of | ||
// []byte. | ||
package params |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package params | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" | ||
"github.com/gnolang/gno/tm2/pkg/sdk" | ||
"github.com/gnolang/gno/tm2/pkg/std" | ||
) | ||
|
||
type paramsHandler struct { | ||
params ParamsKeeper | ||
} | ||
|
||
func NewHandler(params ParamsKeeper) paramsHandler { | ||
return paramsHandler{ | ||
params: params, | ||
} | ||
} | ||
|
||
func (bh paramsHandler) Process(ctx sdk.Context, msg std.Msg) sdk.Result { | ||
errMsg := fmt.Sprintf("unrecognized params message type: %T", msg) | ||
return abciResult(std.ErrUnknownRequest(errMsg)) | ||
} | ||
|
||
//---------------------------------------- | ||
// Query | ||
|
||
const QueryParams = "params" | ||
|
||
func (bh paramsHandler) Query(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) { | ||
switch secondPart(req.Path) { | ||
case QueryParams: | ||
return bh.queryParam(ctx, req) | ||
default: | ||
res = sdk.ABCIResponseQueryFromError( | ||
std.ErrUnknownRequest("unknown params query endpoint")) | ||
return | ||
} | ||
} | ||
|
||
// queryParam returns param for a key. | ||
func (bh paramsHandler) queryParam(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) { | ||
// parse key from path. | ||
key := thirdPartWithSlashes(req.Path) | ||
if key == "" { | ||
res = sdk.ABCIResponseQueryFromError( | ||
std.ErrUnknownRequest("param key is empty")) | ||
} | ||
|
||
// XXX: validate | ||
|
||
panic("not implemented") | ||
|
||
return | ||
} | ||
|
||
//---------------------------------------- | ||
// misc | ||
|
||
func abciResult(err error) sdk.Result { | ||
return sdk.ABCIResultFromError(err) | ||
} | ||
|
||
// returns the second component of a path. | ||
func secondPart(path string) string { | ||
parts := strings.Split(path, "/") | ||
if len(parts) < 2 { | ||
return "" | ||
} else { | ||
return parts[1] | ||
} | ||
} | ||
|
||
// returns the third component of a path, including other slashes. | ||
func thirdPartWithSlashes(path string) string { | ||
secondSlash := strings.Index(path[strings.Index(path, "/")+1:], "/") | ||
if secondSlash == -1 { | ||
return "" // Return original if less than two slashes | ||
} | ||
return path[strings.Index(path, "/")+secondSlash+1:] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package params | ||
|
||
import ( | ||
"fmt" | ||
"log/slog" | ||
"maps" | ||
"reflect" | ||
|
||
"github.com/gnolang/gno/tm2/pkg/amino" | ||
"github.com/gnolang/gno/tm2/pkg/sdk" | ||
"github.com/gnolang/gno/tm2/pkg/store" | ||
) | ||
|
||
// global paramstore Keeper. | ||
type ParamsKeeper struct { | ||
key store.StoreKey | ||
table KeyTable | ||
prefix string | ||
} | ||
|
||
// NewParamsKeeper returns a new ParamsKeeper. | ||
func NewParamsKeeper(key store.StoreKey, prefix string) ParamsKeeper { | ||
return ParamsKeeper{ | ||
key: key, | ||
table: NewKeyTable(), | ||
prefix: prefix, | ||
} | ||
} | ||
|
||
// Logger returns a module-specific logger. | ||
// XXX: why do we expose this? | ||
func (pk ParamsKeeper) Logger(ctx sdk.Context) *slog.Logger { | ||
return ctx.Logger().With("module", ModuleName) | ||
} | ||
|
||
func (pk ParamsKeeper) Has(ctx sdk.Context, key string) bool { | ||
stor := ctx.Store(pk.key) | ||
return stor.Has([]byte(key)) | ||
} | ||
|
||
func (pk ParamsKeeper) Get(ctx sdk.Context, key string, ptr interface{}) { | ||
pk.checkType(key, ptr) | ||
stor := ctx.Store(pk.key) | ||
bz := stor.Get([]byte(key)) | ||
err := amino.UnmarshalJSON(bz, ptr) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func (pk ParamsKeeper) GetIfExists(ctx sdk.Context, key string, ptr interface{}) { | ||
stor := ctx.Store(pk.key) | ||
bz := stor.Get([]byte(key)) | ||
if bz == nil { | ||
return | ||
} | ||
pk.checkType(key, ptr) | ||
err := amino.UnmarshalJSON(bz, ptr) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func (pk ParamsKeeper) GetRaw(ctx sdk.Context, key string) []byte { | ||
stor := ctx.Store(pk.key) | ||
return stor.Get([]byte(key)) | ||
} | ||
|
||
func (pk ParamsKeeper) Set(ctx sdk.Context, key string, value interface{}) { | ||
pk.checkType(key, value) | ||
stor := ctx.Store(pk.key) | ||
bz, err := amino.MarshalJSON(value) | ||
if err != nil { | ||
panic(err) | ||
} | ||
stor.Set([]byte(key), bz) | ||
} | ||
|
||
func (pk ParamsKeeper) Update(ctx sdk.Context, key string, value []byte) error { | ||
attr, ok := pk.table.m[key] | ||
if !ok { | ||
panic(fmt.Sprintf("parameter %s not registered", key)) | ||
} | ||
|
||
ty := attr.ty | ||
dest := reflect.New(ty).Interface() | ||
pk.GetIfExists(ctx, key, dest) | ||
|
||
if err := amino.UnmarshalJSON(value, dest); err != nil { | ||
return err | ||
} | ||
|
||
destValue := reflect.Indirect(reflect.ValueOf(dest)).Interface() | ||
if err := pk.Validate(ctx, key, destValue); err != nil { | ||
return err | ||
} | ||
|
||
pk.Set(ctx, key, dest) | ||
return nil | ||
} | ||
|
||
func (pk ParamsKeeper) Validate(ctx sdk.Context, key string, value interface{}) error { | ||
attr, ok := pk.table.m[key] | ||
if !ok { | ||
return fmt.Errorf("parameter %s not registered", key) | ||
} | ||
|
||
if err := attr.vfn(value); err != nil { | ||
return fmt.Errorf("invalid parameter value: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (pk ParamsKeeper) checkType(key string, value interface{}) { | ||
attr, ok := pk.table.m[key] | ||
if !ok { | ||
panic(fmt.Sprintf("parameter %s is not registered", key)) | ||
} | ||
|
||
ty := attr.ty | ||
pty := reflect.TypeOf(value) | ||
if pty.Kind() == reflect.Ptr { | ||
pty = pty.Elem() | ||
} | ||
|
||
if pty != ty { | ||
panic("type mismatch with registered table") | ||
} | ||
} | ||
|
||
func (pk ParamsKeeper) HasKeyTable() bool { | ||
return len(pk.table.m) > 0 | ||
} | ||
|
||
func (pk ParamsKeeper) WithKeyTable(table KeyTable) ParamsKeeper { | ||
if table.m == nil { | ||
panic("WithKeyTable() called with nil KeyTable") | ||
} | ||
if len(pk.table.m) != 0 { | ||
panic("WithKeyTable() called on already initialized Keeper") | ||
} | ||
|
||
maps.Copy(pk.table.m, table.m) | ||
return pk | ||
} | ||
|
||
// XXX: GetAllKeys | ||
// XXX: GetAllParams | ||
// XXX: ViewKeeper | ||
// XXX: ModuleKeeper |
Oops, something went wrong.