Skip to content
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

feat(keeper): add vm/qpath query #2969

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions gno.land/cmd/gnoland/testdata/qpath.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
loadpkg gno.land/r/foobar $WORK

gnoland start

gnokey query vm/qpaths -data "0:1"
! stdout 'gno.land/r/foobar'


gnokey query vm/qpaths -data "0:100"
stdout 'gno.land/r/foobar'

-- foo.gno --
package main

func main() {
println("foo")
}
51 changes: 51 additions & 0 deletions gno.land/pkg/sdk/vm/handler.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package vm

import (
"bytes"
"context"
"encoding/json"
"fmt"
"strconv"
"strings"

abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types"
Expand Down Expand Up @@ -79,6 +82,7 @@
QueryFuncs = "qfuncs"
QueryEval = "qeval"
QueryFile = "qfile"
QueryPaths = "qpaths"
)

func (vh vmHandler) Query(ctx sdk.Context, req abci.RequestQuery) abci.ResponseQuery {
Expand All @@ -100,6 +104,8 @@
res = vh.queryEval(ctx, req)
case QueryFile:
res = vh.queryFile(ctx, req)
case QueryPaths:
res = vh.queryPaths(ctx, req)

Check warning on line 108 in gno.land/pkg/sdk/vm/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/handler.go#L107-L108

Added lines #L107 - L108 were not covered by tests
default:
return sdk.ABCIResponseQueryFromError(
std.ErrUnknownRequest(fmt.Sprintf(
Expand Down Expand Up @@ -178,6 +184,51 @@
return
}

// queryPaths retrieves paginated package paths based on request data.
// The request format is "offset:limit". If not provided, defaults are offset=0 and limit=50.
func (vh vmHandler) queryPaths(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) {
var err error
var limit, offset int

Check warning on line 191 in gno.land/pkg/sdk/vm/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/handler.go#L189-L191

Added lines #L189 - L191 were not covered by tests

data := bytes.TrimSpace(req.Data)
before, after, found := strings.Cut(string(data), ":")
if !found {
res = sdk.ABCIResponseQueryFromError(
fmt.Errorf("invalid data format, should be `offset:limit`"),
)
return

Check warning on line 199 in gno.land/pkg/sdk/vm/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/handler.go#L193-L199

Added lines #L193 - L199 were not covered by tests
}

if offset, err = strconv.Atoi(before); err != nil {
res = sdk.ABCIResponseQueryFromError(
fmt.Errorf("unable to parse limit %q: %w", before, err),
)
} else if limit, err = strconv.Atoi(after); err != nil {
res = sdk.ABCIResponseQueryFromError(
fmt.Errorf("unable to parse offset %q: %w", after, err),
)

Check warning on line 209 in gno.land/pkg/sdk/vm/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/handler.go#L202-L209

Added lines #L202 - L209 were not covered by tests
}

if res.Error != nil {
return

Check warning on line 213 in gno.land/pkg/sdk/vm/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/handler.go#L212-L213

Added lines #L212 - L213 were not covered by tests
}

paths, err := vh.vm.QueryPackagesPath(ctx, offset, limit)
if err != nil {
res = sdk.ABCIResponseQueryFromError(err)
return

Check warning on line 219 in gno.land/pkg/sdk/vm/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/handler.go#L216-L219

Added lines #L216 - L219 were not covered by tests
}

res.Data, err = json.Marshal(paths)
if err != nil {
res = sdk.ABCIResponseQueryFromError(
fmt.Errorf("unable to marshal result: %w", err),
)

Check warning on line 226 in gno.land/pkg/sdk/vm/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/handler.go#L222-L226

Added lines #L222 - L226 were not covered by tests
}

return

Check warning on line 229 in gno.land/pkg/sdk/vm/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/handler.go#L229

Added line #L229 was not covered by tests
}

// queryEval evaluates any expression in readonly mode and returns the results.
func (vh vmHandler) queryEval(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) {
pkgPath, expr := parseQueryEvalData(string(req.Data))
Expand Down
18 changes: 18 additions & 0 deletions gno.land/pkg/sdk/vm/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,24 @@
return res, nil
}

const MaxPackagesLimit = 100

// QueryPackagesPath returns public facing function signatures.
func (vm *VMKeeper) QueryPackagesPath(ctx sdk.Context, page, pageSize int) (paths []string, err error) {
if page < 0 {
return nil, fmt.Errorf("invalid page, cannot be negative")

Check warning on line 642 in gno.land/pkg/sdk/vm/keeper.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/keeper.go#L640-L642

Added lines #L640 - L642 were not covered by tests
}

if pageSize > MaxPackagesLimit || pageSize < 0 {
return nil, fmt.Errorf("invalid page size, cannot be negative or above %d ", MaxPackagesLimit)

Check warning on line 646 in gno.land/pkg/sdk/vm/keeper.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/keeper.go#L645-L646

Added lines #L645 - L646 were not covered by tests
}

store := vm.newGnoTransactionStore(ctx) // throwaway (never committed) // XXX: is that really needed ?
offset := page * pageSize
paths = store.ListMemPackagePath(uint64(offset), uint64(pageSize))
return paths, nil

Check warning on line 652 in gno.land/pkg/sdk/vm/keeper.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/keeper.go#L649-L652

Added lines #L649 - L652 were not covered by tests
}

// QueryFuncs returns public facing function signatures.
func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionSignatures, err error) {
store := vm.newGnoTransactionStore(ctx) // throwaway (never committed)
Expand Down
31 changes: 31 additions & 0 deletions gnovm/pkg/gnolang/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
AddMemPackage(memPkg *std.MemPackage)
GetMemPackage(path string) *std.MemPackage
GetMemFile(path string, name string) *std.MemFile
ListMemPackagePath(offset, limit uint64) []string
IterMemPackage() <-chan *std.MemPackage
ClearObjectCache() // run before processing a message
SetPackageInjector(PackageInjector) // for natives
Expand Down Expand Up @@ -704,6 +705,36 @@
return memFile
}

// ListMemPackagePath retrieves a paginated list of package paths.
func (ds *defaultStore) ListMemPackagePath(offset, limit uint64) []string {
ctrkey := []byte(backendPackageIndexCtrKey())
ctrbz := ds.baseStore.Get(ctrkey)
if ctrbz == nil {
return nil

Check warning on line 713 in gnovm/pkg/gnolang/store.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/store.go#L709-L713

Added lines #L709 - L713 were not covered by tests
}

ctr, err := strconv.Atoi(string(ctrbz))
if err != nil {
panic(fmt.Errorf("failed to convert counter to integer: %w", err))

Check warning on line 718 in gnovm/pkg/gnolang/store.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/store.go#L716-L718

Added lines #L716 - L718 were not covered by tests
}

paths := make([]string, 0, limit)
to := min(uint64(ctr), offset+limit)

Check warning on line 722 in gnovm/pkg/gnolang/store.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/store.go#L721-L722

Added lines #L721 - L722 were not covered by tests

// Fetching and filtering data
for from := offset + 1; from <= to; from++ {
idxkey := []byte(backendPackageIndexKey(from))
path := ds.baseStore.Get(idxkey)
if path == nil {
panic(fmt.Errorf("missing package index %d", from))

Check warning on line 729 in gnovm/pkg/gnolang/store.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/store.go#L725-L729

Added lines #L725 - L729 were not covered by tests
}

paths = append(paths, string(path))

Check warning on line 732 in gnovm/pkg/gnolang/store.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/store.go#L732

Added line #L732 was not covered by tests
}

return paths

Check warning on line 735 in gnovm/pkg/gnolang/store.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/store.go#L735

Added line #L735 was not covered by tests
}

func (ds *defaultStore) IterMemPackage() <-chan *std.MemPackage {
ctrkey := []byte(backendPackageIndexCtrKey())
ctrbz := ds.baseStore.Get(ctrkey)
Expand Down
Loading