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): handle JSON arguments in MsgCall #1776

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f3da0f2
wip: json -> gnotypes
gfanton Feb 22, 2024
e3e3d10
wip: use args as input
gfanton Mar 14, 2024
b67363b
fix: skip unexported fields in `gno2GoValue`
gfanton Mar 14, 2024
f7897e2
fix(call): json encoding
gfanton Mar 14, 2024
d8e547d
fix: minor fixes
gfanton Mar 18, 2024
cecbaa5
fix: useless print
gfanton Mar 20, 2024
59f3734
feat: update convertArgToGno to now support struct & array
gfanton Mar 25, 2024
c6c2acd
feat: add convert test
gfanton Mar 25, 2024
fe3095d
chore: cleanup test
gfanton Mar 25, 2024
f4f3bb7
fix: txtar test
gfanton Mar 26, 2024
6028481
Merge branch 'master' into feat/json-to-gnotypes
gfanton Mar 26, 2024
1673362
fix(merge): new txtar test
gfanton Mar 26, 2024
738a031
fix: lint
gfanton Mar 26, 2024
df0eb4f
chore: improve comments
gfanton Mar 26, 2024
b02c09f
fix: gnoclient tests
gfanton Mar 27, 2024
b3d2b3b
fix: test and call overall reply
gfanton Mar 28, 2024
9893c92
chore: lint
gfanton Mar 28, 2024
48f1599
Merge branch 'master' into feat/json-to-gnotypes
gfanton Mar 29, 2024
06a1942
feat(doc): add doc for eval calls
gfanton Mar 29, 2024
90a211c
chore(test): add reference to unsupported interface marshal
gfanton Mar 29, 2024
8c95718
chore: lint
gfanton Mar 29, 2024
eba3d40
feat: add qeval simple test
gfanton Mar 29, 2024
85a5368
Merge branch 'master' into feat/json-to-gnotypes
gfanton Mar 31, 2024
19ef9ec
fix: typo
gfanton Mar 31, 2024
1d04d38
Merge branch 'master' into feat/json-to-gnotypes
gfanton Apr 3, 2024
92611b6
Merge branch 'master' into feat/json-to-gnotypes
gfanton Apr 8, 2024
74cf99e
Merge remote-tracking branch 'master' into feat/json-to-gnotypes
gfanton Apr 21, 2024
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
38 changes: 38 additions & 0 deletions gno.land/pkg/sdk/vm/convert_json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package vm

import (
"encoding/json"
"reflect"

"github.com/gnolang/gno/gnovm/pkg/gnolang"
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/tm2/pkg/amino"
gfanton marked this conversation as resolved.
Show resolved Hide resolved
)

func UnmarshalJSON(alloc *gno.Allocator, store gno.Store, b []byte, t gno.Type) (tv gno.TypedValue, err error) {
gfanton marked this conversation as resolved.
Show resolved Hide resolved
gfanton marked this conversation as resolved.
Show resolved Hide resolved
gfanton marked this conversation as resolved.
Show resolved Hide resolved
tv.T = t
gvalue := gnolang.Gno2GoValue(&tv, reflect.Value{})
v := reflect.New(gvalue.Type())
if err := amino.UnmarshalJSON(b, v.Interface()); err != nil {
gfanton marked this conversation as resolved.
Show resolved Hide resolved
return tv, err
}

return gnolang.Go2GnoValue(alloc, store, v.Elem()), nil
}

func UnmarshalNativeValueJSON(alloc *gno.Allocator, b []byte, t gno.Type) (tv gno.TypedValue, err error) {
tv.T = t
gvalue := gnolang.Gno2GoValue(&tv, reflect.Value{})
v := reflect.New(gvalue.Type())
if err = amino.UnmarshalJSON(b, v.Interface()); err != nil {
return tv, err
}

return gnolang.Go2GnoNativeValue(alloc, v.Elem()), nil
}

func MarshalJSON(tv *gno.TypedValue) ([]byte, error) {
rv := gnolang.Gno2GoValue(tv, reflect.Value{})
// XXX: use amino
gfanton marked this conversation as resolved.
Show resolved Hide resolved
return json.Marshal(rv.Interface())
}
106 changes: 91 additions & 15 deletions gno.land/pkg/sdk/vm/keeper.go
gfanton marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) {
pkgPath := msg.PkgPath // to import
fnc := msg.Func
store := vm.getGnoStore(ctx)

// Get the package and function type.
pv := store.GetPackage(pkgPath, false)
pl := gno.PackageNodeLocation(pkgPath)
Expand All @@ -217,16 +218,44 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) {
mpn := gno.NewPackageNode("main", "main", nil)
mpn.Define("pkg", gno.TypedValue{T: &gno.PackageType{}, V: pv})
mpv := mpn.NewPackage()
// Parse expression.

if len(msg.Args) != len(ft.Params) {
return "", fmt.Errorf("wrong number of arguments in call to %s: want %d got %d", fnc, len(ft.Params), len(msg.Args))
}

request := make([]gno.TypedValue, len(ft.Params))
gfanton marked this conversation as resolved.
Show resolved Hide resolved
for i, arg := range msg.Args {
pt := ft.Params[i].Type
arg = strings.TrimSpace(arg)
if len(arg) > 2 &&
gfanton marked this conversation as resolved.
Show resolved Hide resolved
((arg[0] == '{' && arg[len(arg)-1] == '}') ||
(arg[0] == '[' && arg[len(arg)-1] == ']')) {
gfanton marked this conversation as resolved.
Show resolved Hide resolved
// Handle JSON argument
request[i], err = UnmarshalJSON(store.GetAllocator(), store, []byte(arg), pt)
if err != nil {
return "", fmt.Errorf("unable to unmarshal arg#%d: %w", err)
gfanton marked this conversation as resolved.
Show resolved Hide resolved
}

continue
}

request[i] = convertArgToGno(arg, pt)

}

// Create expresion
argslist := ""
for i := range msg.Args {
for i := range ft.Params {
if i > 0 {
argslist += ","
}
argslist += fmt.Sprintf("arg%d", i)
}

expr := fmt.Sprintf(`pkg.%s(%s)`, fnc, argslist)
fmt.Printf("expr%v\r\n", expr)
xn := gno.MustParseExpr(expr)

// Send send-coins to pkg from caller.
pkgAddr := gno.DerivePkgAddr(pkgPath)
caller := msg.Caller
Expand All @@ -235,21 +264,19 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) {
if err != nil {
return "", err
}

// Convert Args to gno values.
cx := xn.(*gno.CallExpr)
if cx.Varg {
panic("variadic calls not yet supported")
}
if len(msg.Args) != len(ft.Params) {
panic(fmt.Sprintf("wrong number of arguments in call to %s: want %d got %d", fnc, len(ft.Params), len(msg.Args)))
}
for i, arg := range msg.Args {
argType := ft.Params[i].Type
atv := convertArgToGno(arg, argType)

for i, arg := range request {
cx.Args[i] = &gno.ConstExpr{
TypedValue: atv,
TypedValue: arg,
}
}

// Make context.
// NOTE: if this is too expensive,
// could it be safely partially memoized?
Expand Down Expand Up @@ -283,15 +310,64 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) {
}
m.Release()
}()

rtvs := m.Eval(xn)
ctx.Logger().Info("CPUCYCLES call", "num-cycles", m.Cycles)
for i, rtv := range rtvs {
res = res + rtv.String()
if i < len(rtvs)-1 {
res += "\n"

// Result

// Iterate through params
var response gno.TypedValue
{
var sv gno.StructValue
var st gno.StructType

gfanton marked this conversation as resolved.
Show resolved Hide resolved
// Generate result Typed Valye
gfanton marked this conversation as resolved.
Show resolved Hide resolved
result := gno.TypedValue{
V: &gno.ArrayValue{
List: rtvs,
},
T: &gno.ArrayType{
Elt: &gno.InterfaceType{},
Len: len(rtvs),
},
}

// Define response fields
responseFS := []gno.FieldType{
gno.FieldType{
Name: gno.Name("Result"),
Type: result.T,
},
gno.FieldType{
Name: gno.Name("CPUCycles"),
Type: gno.Int64Type,
},
}
responseTV := make([]gno.TypedValue, 0, len(responseFS))

// Add result value
responseTV = append(responseTV, result)

// Add cpucycle to responses
cycle := gno.TypedValue{T: gno.Int64Type}
cycle.SetInt64(m.Cycles)
responseTV = append(responseTV, cycle)

st.PkgPath = mpn.PkgPath
st.Fields = responseFS
sv.Fields = responseTV

response.T = &st
response.V = &sv
}
return res, nil

ctx.Logger().Info("CPUCYCLES call", "num-cycles", m.Cycles)
resraw, err := MarshalJSON(&response)
gfanton marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return "", fmt.Errorf("unable to unarmsahll result: %w", err)
}

return string(resraw), nil
// TODO pay for gas? TODO see context?
}

Expand Down
6 changes: 6 additions & 0 deletions gnovm/pkg/gnolang/gonative.go
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,12 @@ func gno2GoValue(tv *TypedValue, rv reflect.Value) (ret reflect.Value) {
if ftv.IsUndefined() {
continue
}

// Skip unexported field
gfanton marked this conversation as resolved.
Show resolved Hide resolved
if rt.Field(i).PkgPath != "" {
gfanton marked this conversation as resolved.
Show resolved Hide resolved
continue
}

gno2GoValue(ftv, rv.Field(i))
}
case *MapType:
Expand Down
Loading