Skip to content

Commit

Permalink
feat(tm2/sdk/params): initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
moul committed Oct 11, 2024
1 parent 628f965 commit b930513
Show file tree
Hide file tree
Showing 11 changed files with 612 additions and 20 deletions.
12 changes: 6 additions & 6 deletions tm2/pkg/sdk/auth/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ func NewAccountKeeper(
}
}

// Logger returns a module-specific logger.
func (ak AccountKeeper) Logger(ctx sdk.Context) *slog.Logger {
return ctx.Logger().With("module", fmt.Sprintf("auth"))
}

// NewAccountWithAddress implements AccountKeeper.
func (ak AccountKeeper) NewAccountWithAddress(ctx sdk.Context, addr crypto.Address) std.Account {
acc := ak.proto()
Expand All @@ -53,7 +48,12 @@ func (ak AccountKeeper) NewAccountWithAddress(ctx sdk.Context, addr crypto.Addre
return acc
}

// GetAccount implements AccountKeeper.
// Logger returns a module-specific logger.
func (ak AccountKeeper) Logger(ctx sdk.Context) *slog.Logger {
return ctx.Logger().With("module", ModuleName)
}

// GetAccount returns a specific account in the AccountKeeper.
func (ak AccountKeeper) GetAccount(ctx sdk.Context, addr crypto.Address) std.Account {
stor := ctx.Store(ak.key)
bz := stor.Get(AddressStoreKey(addr))
Expand Down
4 changes: 2 additions & 2 deletions tm2/pkg/sdk/bank/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ type BankKeeperI interface {

var _ BankKeeperI = BankKeeper{}

// BBankKeeper only allows transfers between accounts without the possibility of
// creating coins. It implements the BankKeeper interface.
// BankKeeper only allows transfers between accounts without the possibility of
// creating coins. It implements the BankKeeperI interface.
type BankKeeper struct {
ViewKeeper

Expand Down
6 changes: 6 additions & 0 deletions tm2/pkg/sdk/params/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package params

const (
ModuleName = "params"
StoreKey = ModuleName
)
13 changes: 13 additions & 0 deletions tm2/pkg/sdk/params/doc.go
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
83 changes: 83 additions & 0 deletions tm2/pkg/sdk/params/handler.go
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:]
}
151 changes: 151 additions & 0 deletions tm2/pkg/sdk/params/keeper.go
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
Loading

0 comments on commit b930513

Please sign in to comment.