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

[WIP]feat: vm result, error handling #718

Closed
wants to merge 4 commits into from
Closed
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
6 changes: 6 additions & 0 deletions gnovm/pkg/gnolang/gonative.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,12 @@ func Gno2GoValue(tv *TypedValue, rv reflect.Value) (ret reflect.Value) {
return gno2GoValue(tv, rv)
}

func Gno2GoType(tv *TypedValue) (ret reflect.Type) {
bt := baseOf(tv.T)
ret = gno2GoType(bt)
return
}

// Default run-time representation of go-native values. It is
// "lazy" in the sense that unnamed complex types like arrays and
// slices aren't translated to Gno canonical types except as
Expand Down
195 changes: 195 additions & 0 deletions gnovm/pkg/gnolang/str2gno.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package gnolang

import (
"encoding/base64"
"fmt"
"strconv"
)

// These convert string representations of public-facing arguments to GNO types.
// The limited set of input types available should map 1:1 to types supported
// in FunctionSignature{}.
// String representation of arg must be deterministic.
// NOTE: very important that there is no malleability.
func ConvertArgToGno(arg string, argT Type) (tv TypedValue) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this copied from anywhere?

tv.T = argT
switch bt := BaseOf(argT).(type) {
case PrimitiveType:
switch bt {
case BoolType:
if arg == "true" {
tv.SetBool(true)
return
} else if arg == "false" {
tv.SetBool(false)
return
} else {
panic(fmt.Sprintf(
"unexpected bool value %q",
arg))
}
case StringType:
tv.SetString(StringValue(arg))
return
case IntType:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
i64, err := strconv.ParseInt(arg, 10, 64)
if err != nil {
panic(fmt.Sprintf(
"error parsing int %q: %v",
arg, err))
}
tv.SetInt(int(i64))
return
case Int8Type:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
i8, err := strconv.ParseInt(arg, 10, 8)
if err != nil {
panic(fmt.Sprintf(
"error parsing int8 %q: %v",
arg, err))
}
tv.SetInt8(int8(i8))
return
case Int16Type:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
i16, err := strconv.ParseInt(arg, 10, 16)
if err != nil {
panic(fmt.Sprintf(
"error parsing int16 %q: %v",
arg, err))
}
tv.SetInt16(int16(i16))
return
case Int32Type:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
i32, err := strconv.ParseInt(arg, 10, 32)
if err != nil {
panic(fmt.Sprintf(
"error parsing int32 %q: %v",
arg, err))
}
tv.SetInt32(int32(i32))
return
case Int64Type:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
i64, err := strconv.ParseInt(arg, 10, 64)
if err != nil {
panic(fmt.Sprintf(
"error parsing int64 %q: %v",
arg, err))
}
tv.SetInt64(i64)
return
case UintType:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
u64, err := strconv.ParseUint(arg, 10, 64)
if err != nil {
panic(fmt.Sprintf(
"error parsing uint %q: %v",
arg, err))
}
tv.SetUint(uint(u64))
return
case Uint8Type:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
u8, err := strconv.ParseUint(arg, 10, 8)
if err != nil {
panic(fmt.Sprintf(
"error parsing uint8 %q: %v",
arg, err))
}
tv.SetUint8(uint8(u8))
return
case Uint16Type:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
u16, err := strconv.ParseUint(arg, 10, 16)
if err != nil {
panic(fmt.Sprintf(
"error parsing uint16 %q: %v",
arg, err))
}
tv.SetUint16(uint16(u16))
return
case Uint32Type:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
u32, err := strconv.ParseUint(arg, 10, 32)
if err != nil {
panic(fmt.Sprintf(
"error parsing uint32 %q: %v",
arg, err))
}
tv.SetUint32(uint32(u32))
return
case Uint64Type:
if arg[0] == '+' {
panic("numbers cannot start with +")
}
u64, err := strconv.ParseUint(arg, 10, 64)
if err != nil {
panic(fmt.Sprintf(
"error parsing uint64 %q: %v",
arg, err))
}
tv.SetUint64(uint64(u64))
return
default:
panic(fmt.Sprintf("unexpected primitive type %s", bt.String()))
}
case *ArrayType:
if bt.Elt == Uint8Type {
bz, err := base64.StdEncoding.DecodeString(arg)
if err != nil {
panic(fmt.Sprintf(
"error parsing byte array %q: %v",
arg, err))
}
tv.V = &ArrayValue{
Data: bz,
}
return
} else {
panic("unexpected array type in contract arg")
}
case *SliceType:
if bt.Elt == Uint8Type {
bz, err := base64.StdEncoding.DecodeString(arg)
if err != nil {
panic(fmt.Sprintf(
"error parsing byte array %q: %v",
arg, err))
}
tv.V = &SliceValue{
Base: &ArrayValue{
Data: bz,
},
Offset: 0,
Length: len(bz),
Maxcap: len(bz),
}
return
} else {
panic("unexpected slice type in contract arg")
}
default:
panic(fmt.Sprintf("unexpected type in contract arg: %v", argT))
}
}
57 changes: 57 additions & 0 deletions gnovm/stdlibs/std/msg.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package std

import "errors"

const (
ModuleName = "vm"
RouterKey = ModuleName
)
// std result
type Result struct {
Response
// GasWanted int64
// GasUsed int64
// additional fields?
}

func GnoResult(r Response) *Result {
return &Result{Response: r}
}

type Event string

func (e Event) AssertABCIEvent() {}

type Response struct {
ErrMsg string // TODO: user err_code instead, for safety
Data []byte
Events []Event
// gas limit?

Log string // nondeterministic
Info string // nondeterministic
}

func NewResponse() Response {
return Response{}
}

func (r Response) WithData(data []byte) Response {
r.Data = data
return r
}

func (r Response) WithEvents(events []Event) Response {
r.Events = events
return r
}

func (r Response) WithLog(log string) Response {
r.Log = log
return r
}

func (r Response) WithInfo(info string) Response {
r.Info = info
return r
}
25 changes: 25 additions & 0 deletions tm2/pkg/sdk/vm/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"fmt"
"strconv"

"errors"
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/tm2/pkg/sdk"
)

// These convert string representations of public-facing arguments to GNO types.
Expand Down Expand Up @@ -195,3 +197,26 @@ func convertArgToGno(arg string, argT gno.Type) (tv gno.TypedValue) {
panic(fmt.Sprintf("unexpected type in contract arg: %v", argT))
}
}

func Gno2SdkResult(r VMResult) (res sdk.Result) {
if r.ErrMsg != "" {
res.Error = sdk.ABCIError(errors.New(r.ErrMsg))
}
res.Data = r.Data
res.Info = r.Info
res.Log = r.Log
return
}

func prefixData(value []byte) []byte {
// 1 is default length for a `length` prefix
data := make([]byte, 0, len(value)+1)
data = append(data, byte(len(value)))
data = append(data, value...)
return data
}

func gnoResultFromData(data []byte) (res VMResult) {
res.Data = data
return
}
Loading