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(gno.land): add go type checking to keeper + tx simulation in gnokey #1702

Merged
merged 52 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
85f62ba
refactor(gnovm): rename precompiler to transpiler, move to own package
thehowl Feb 22, 2024
9409285
move transpiler to pkg
thehowl Feb 22, 2024
cb63cf5
Merge branch 'master' into dev/morgan/precompile-refactor
thehowl Feb 22, 2024
3710ded
Merge branch 'dev/morgan/precompile-refactor' of github.com:gnolang/g…
thehowl Feb 22, 2024
37c9e66
fixup
thehowl Feb 22, 2024
59c5bb1
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/preco…
thehowl Feb 26, 2024
d39292b
Merge branch 'master' into dev/morgan/precompile-refactor
thehowl Feb 27, 2024
a25d076
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/preco…
thehowl Feb 28, 2024
a889dea
begin removing support for linked identifiers
thehowl Feb 22, 2024
aae89db
convert native bindings to never use linked types
thehowl Feb 23, 2024
fd2722e
remove InjectNativeMappings
thehowl Feb 23, 2024
8856225
fix errors in genstd
thehowl Feb 27, 2024
d6955d0
remove AddGo2GnoMapping, nolint on btReadonly
thehowl Feb 28, 2024
c3e8ff8
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/preco…
thehowl Feb 28, 2024
1de00fa
Merge branch 'dev/morgan/precompile-refactor' into dev/morgan/natbind…
thehowl Feb 28, 2024
c0581dd
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/natbi…
thehowl Feb 28, 2024
b3c7adb
fmt + bugfix
thehowl Feb 28, 2024
250e292
feat(gno.land): add go type checking to keeper
thehowl Feb 28, 2024
0d8596d
lint + test fixes
thehowl Feb 28, 2024
10c0434
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/natbi…
thehowl Mar 3, 2024
f641c58
Merge branch 'dev/morgan/natbind-no-linkedtype' into dev/morgan/go-ty…
thehowl Mar 3, 2024
9779ff3
use custom type instead of any in importer
thehowl Mar 3, 2024
7b239df
support multiple errors in type checker
thehowl Mar 3, 2024
1b323a2
correctly return error in vm keeper
thehowl Mar 3, 2024
df1679c
add tests to type checker
thehowl Mar 3, 2024
ee0448e
fixup
thehowl Mar 3, 2024
a169800
add integration test for gno.land
thehowl Mar 3, 2024
e53aa22
Merge branch 'master' into dev/morgan/go-types-typecheck
thehowl Mar 20, 2024
172e4ae
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/go-ty…
thehowl Mar 27, 2024
0fa34fa
remove newMemPackage
thehowl Mar 27, 2024
8688167
Merge branch 'dev/morgan/go-types-typecheck' of github.com:gnolang/gn…
thehowl Mar 27, 2024
89d9887
remove unused var
thehowl Mar 27, 2024
ccf0ba9
Merge branch 'master' into dev/morgan/go-types-typecheck
thehowl Apr 15, 2024
338454f
remove other usage in gnoclient
thehowl Apr 15, 2024
6b4ed9e
remove unused import in test
thehowl Apr 15, 2024
0007e73
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/go-ty…
thehowl Apr 17, 2024
9ccb5ee
bump limits for issue-1786 test
thehowl Apr 17, 2024
e20ebbe
bump up to 4M
thehowl Apr 17, 2024
ad2f0b1
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/go-ty…
thehowl May 6, 2024
66fb953
changes from code review
thehowl May 6, 2024
38cba04
fix gas numbers
thehowl May 7, 2024
bee0f30
add transaction simulation in gnokey
thehowl May 7, 2024
3a82a98
fixup lint
thehowl May 7, 2024
39ae304
update docs
thehowl May 7, 2024
dbde296
partial revert of store changes
thehowl May 9, 2024
9ee3cc6
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/go-ty…
thehowl May 9, 2024
f843acb
fixup
thehowl May 9, 2024
2558b09
Revert "fixup"
thehowl May 10, 2024
cc9d45e
Revert "partial revert of store changes"
thehowl May 10, 2024
09f081c
fixup
thehowl May 10, 2024
38719cd
update docs
thehowl May 10, 2024
815c573
Merge branch 'master' of github.com:gnolang/gno into dev/morgan/go-ty…
thehowl May 13, 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
2 changes: 1 addition & 1 deletion gno.land/cmd/gnoland/testdata/addpkg.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## start a new node
gnoland start

## add bar.gno package located in $WORK directory as gno.land/r/foobar/bar
## add bar package located in $WORK directory as gno.land/r/foobar/bar
gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/foobar/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1

## execute Render
Expand Down
21 changes: 21 additions & 0 deletions gno.land/cmd/gnoland/testdata/addpkg_invalid.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# test for add package; ensuring type checker catches invalid code.

# start a new node
gnoland start

# add bar package located in $WORK directory as gno.land/r/foobar/bar
! gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/foobar/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved

# compare render
! stdout .+
stderr 'as string value in return statement'
stderr '"std" imported and not used'

-- bar.gno --
package bar

import "std"

func Render(path string) string {
return 89
}
9 changes: 3 additions & 6 deletions gno.land/cmd/gnoland/testdata/issue-1786.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ loadpkg gno.land/r/demo/wugnot
gnoland start

# add contract
gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/proxywugnot -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/proxywugnot -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1
stdout OK!

# approve wugnot to `proxywugnot ≈ g1fndyg0we60rdfchyy5dwxzkfmhl5u34j932rg3`
Expand All @@ -24,7 +24,7 @@ stdout '10000 uint64'
# unwrap 500 wugnot
gnokey maketx call -pkgpath gno.land/r/demo/proxywugnot -func ProxyUnwrap -args 500 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1

# XXX without patching anything it will panic
# XXX without patching anything it will panic
# panic msg: insufficient coins error
# XXX with pathcing only wugnot.gnot it will panic
# panic msg: RealmSendBanker can only send from the realm package address "g1fndyg0we60rdfchyy5dwxzkfmhl5u34j932rg3", but got "g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6"
Expand All @@ -46,8 +46,6 @@ import (
"std"

"gno.land/r/demo/wugnot"

"gno.land/p/demo/ufmt"
pusers "gno.land/p/demo/users"
)

Expand All @@ -73,7 +71,6 @@ func ProxyUnwrap(wugnotAmount uint64) {
if wugnotAmount == 0 {
return
}
userOldWugnot := wugnot.BalanceOf(pusers.AddressOrName(std.GetOrigCaller()))

// SEND WUGNOT: USER -> PROXY_WUGNOT
wugnot.TransferFrom(pusers.AddressOrName(std.GetOrigCaller()), pusers.AddressOrName(std.CurrentRealm().Addr()), wugnotAmount)
Expand All @@ -84,4 +81,4 @@ func ProxyUnwrap(wugnotAmount uint64) {
// SEND GNOT: PROXY_WUGNOT -> USER
banker := std.GetBanker(std.BankerTypeRealmSend)
banker.SendCoins(std.CurrentRealm().Addr(), std.GetOrigCaller(), std.Coins{{"ugnot", int64(wugnotAmount)}})
}
}
11 changes: 0 additions & 11 deletions gno.land/pkg/gnoclient/client_txs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package gnoclient

import (
"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
"github.com/gnolang/gno/gnovm/pkg/transpiler"
"github.com/gnolang/gno/tm2/pkg/amino"
ctypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types"
"github.com/gnolang/gno/tm2/pkg/crypto"
Expand Down Expand Up @@ -145,11 +144,6 @@ func (c *Client) Run(cfg BaseTxCfg, msgs ...MsgRun) (*ctypes.ResultBroadcastTxCo

caller := c.Signer.Info().GetAddress()

// Transpile and validate Gno syntax
if err = transpiler.TranspileAndCheckMempkg(msg.Package); err != nil {
thehowl marked this conversation as resolved.
Show resolved Hide resolved
return nil, err
}

msg.Package.Name = "main"
msg.Package.Path = ""

Expand Down Expand Up @@ -263,11 +257,6 @@ func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...MsgAddPackage) (*ctypes.Resul

caller := c.Signer.Info().GetAddress()

// Transpile and validate Gno syntax
if err = transpiler.TranspileAndCheckMempkg(msg.Package); err != nil {
return nil, err
}

// Unwrap syntax sugar to vm.MsgCall slice
vmMsgs = append(vmMsgs, std.Msg(vm.MsgAddPackage{
Creator: caller,
Expand Down
3 changes: 0 additions & 3 deletions gno.land/pkg/gnoclient/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ func TestRunSingle_Integration(t *testing.T) {

fileBody := `package main
import (
"std"
"gno.land/p/demo/ufmt"
"gno.land/r/demo/tests"
)
Expand Down Expand Up @@ -299,7 +298,6 @@ func TestRunMultiple_Integration(t *testing.T) {

fileBody1 := `package main
import (
"std"
"gno.land/p/demo/ufmt"
"gno.land/r/demo/tests"
)
Expand All @@ -313,7 +311,6 @@ func main() {

fileBody2 := `package main
import (
"std"
"gno.land/p/demo/ufmt"
"gno.land/r/demo/deep/very/deep"
)
Expand Down
7 changes: 0 additions & 7 deletions gno.land/pkg/keyscli/addpkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/pkg/transpiler"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/keys"
Expand Down Expand Up @@ -102,12 +101,6 @@ func execMakeAddPkg(cfg *MakeAddPkgCfg, args []string, io commands.IO) error {
panic(fmt.Sprintf("found an empty package %q", cfg.PkgPath))
}

// transpile and validate syntax
err = transpiler.TranspileAndCheckMempkg(memPkg)
if err != nil {
panic(err)
}

// parse gas wanted & fee.
gaswanted := cfg.RootCfg.GasWanted
gasfee, err := std.ParseCoin(cfg.RootCfg.GasFee)
Expand Down
7 changes: 1 addition & 6 deletions gno.land/pkg/keyscli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/pkg/transpiler"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/keys"
Expand Down Expand Up @@ -109,11 +108,7 @@ func execMakeRun(cfg *MakeRunCfg, args []string, cmdio commands.IO) error {
if memPkg.IsEmpty() {
panic(fmt.Sprintf("found an empty package %q", memPkg.Path))
}
// transpile and validate syntax
err = transpiler.TranspileAndCheckMempkg(memPkg)
if err != nil {
panic(err)
}

memPkg.Name = "main"
// Set to empty; this will be automatically set by the VM keeper.
memPkg.Path = ""
Expand Down
4 changes: 2 additions & 2 deletions gno.land/pkg/sdk/vm/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (vm *VMKeeper) initBuiltinPackagesAndTypes(store gno.Store) {
// NOTE: native functions/methods added here must be quick operations,
// or account for gas before operation.
// TODO: define criteria for inclusion, and solve gas calculations.
getPackage := func(pkgPath string) (pn *gno.PackageNode, pv *gno.PackageValue) {
getPackage := func(pkgPath string, newStore gno.Store) (pn *gno.PackageNode, pv *gno.PackageValue) {
// otherwise, built-in package value.
// first, load from filepath.
stdlibPath := filepath.Join(vm.stdlibsDir, pkgPath)
Expand All @@ -34,7 +34,7 @@ func (vm *VMKeeper) initBuiltinPackagesAndTypes(store gno.Store) {
PkgPath: "gno.land/r/stdlibs/" + pkgPath,
// PkgPath: pkgPath,
Output: os.Stdout,
Store: store,
Store: newStore,
})
defer m2.Release()
return m2.RunMemPackage(memPkg, true)
Expand Down
26 changes: 25 additions & 1 deletion gno.land/pkg/sdk/vm/errors.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package vm

import "github.com/gnolang/gno/tm2/pkg/errors"
import (
"strings"

"github.com/gnolang/gno/tm2/pkg/errors"
"go.uber.org/multierr"
)

// for convenience:
type abciError struct{}
Expand All @@ -13,11 +18,21 @@
InvalidPkgPathError struct{ abciError }
InvalidStmtError struct{ abciError }
InvalidExprError struct{ abciError }
TypeCheckError struct {
abciError
Errors []string
}
)

func (e InvalidPkgPathError) Error() string { return "invalid package path" }
func (e InvalidStmtError) Error() string { return "invalid statement" }
func (e InvalidExprError) Error() string { return "invalid expression" }
func (e TypeCheckError) Error() string {
thehowl marked this conversation as resolved.
Show resolved Hide resolved
var bld strings.Builder
bld.WriteString("invalid gno package; type check errors:\n")
bld.WriteString(strings.Join(e.Errors, "\n"))
return bld.String()

Check warning on line 34 in gno.land/pkg/sdk/vm/errors.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/errors.go#L30-L34

Added lines #L30 - L34 were not covered by tests
}

func ErrInvalidPkgPath(msg string) error {
return errors.Wrap(InvalidPkgPathError{}, msg)
Expand All @@ -30,3 +45,12 @@
func ErrInvalidExpr(msg string) error {
return errors.Wrap(InvalidExprError{}, msg)
}

func ErrTypeCheck(err error) error {
var tce TypeCheckError
errs := multierr.Errors(err)
for _, err := range errs {
tce.Errors = append(tce.Errors, err.Error())

Check warning on line 53 in gno.land/pkg/sdk/vm/errors.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/errors.go#L49-L53

Added lines #L49 - L53 were not covered by tests
}
return errors.NewWithData(tce).Stacktrace()

Check warning on line 55 in gno.land/pkg/sdk/vm/errors.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/errors.go#L55

Added line #L55 was not covered by tests
}
13 changes: 13 additions & 0 deletions gno.land/pkg/sdk/vm/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@
return ErrInvalidPkgPath("reserved package name: " + pkgPath)
}

// Validate Gno syntax and type check.
if err := gno.TypeCheckMemPackage(memPkg, store); err != nil {
thehowl marked this conversation as resolved.
Show resolved Hide resolved
return ErrTypeCheck(err)

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

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/keeper.go#L165

Added line #L165 was not covered by tests
}

// Pay deposit from creator.
pkgAddr := gno.DerivePkgAddr(pkgPath)

Expand Down Expand Up @@ -317,6 +322,11 @@
return "", ErrInvalidPkgPath(err.Error())
}

// Validate Gno syntax and type check.
if err = gno.TypeCheckMemPackage(memPkg, store); err != nil {
return "", ErrTypeCheck(err)

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

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/keeper.go#L327

Added line #L327 was not covered by tests
}

// Send send-coins to pkg from caller.
err = vm.bank.SendCoins(ctx, caller, pkgAddr, send)
if err != nil {
Expand Down Expand Up @@ -562,6 +572,9 @@
return memFile.Body, nil
} else {
memPkg := store.GetMemPackage(dirpath)
if memPkg == nil {
return "", fmt.Errorf("package %q is not available", dirpath) // TODO: XSS protection

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

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/sdk/vm/keeper.go#L575-L576

Added lines #L575 - L576 were not covered by tests
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved
}
for i, memfile := range memPkg.Files {
if i > 0 {
res += "\n"
Expand Down
4 changes: 0 additions & 4 deletions gno.land/pkg/sdk/vm/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ func TestVMKeeperAddPackage(t *testing.T) {
Name: "test.gno",
Body: `package test

import "std"

func Echo() string {
return "hello world"
}`,
Expand Down Expand Up @@ -413,8 +411,6 @@ func TestNumberOfArgsError(t *testing.T) {
Name: "test.gno",
Body: `package test

import "std"

func Echo(msg string) string {
return "echo:"+msg
}`,
Expand Down
1 change: 1 addition & 0 deletions gno.land/pkg/sdk/vm/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ var Package = amino.RegisterPackage(amino.NewPackage(
InvalidPkgPathError{}, "InvalidPkgPathError",
InvalidStmtError{}, "InvalidStmtError",
InvalidExprError{}, "InvalidExprError",
TypeCheckError{}, "TypeCheckError",
thehowl marked this conversation as resolved.
Show resolved Hide resolved
))
Loading
Loading