-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(gno.land): add go type checking to keeper + tx simulation in gno…
…key (#1702) Split from #1695 for ease of reviewing. Merge order: 1. #1700 2. #1702 (this one!) 3. #1695 \ #1730 This PR removes `TranspileAndCheckMempkg` in favour of performing the type checking it was supposed to do using `go/types` with a custom importer. This importer works together with Gno's `Store`, and can as such be used to type check Gno packages without ever writing a single file to disk. It is important to note that by "Go type check" I mean a variety of compile-time checks the Go compiler performs; in fact, this is much more powerful than running "gofmt" as we are currently doing. Additionally, it adds a new flag to gnokey, `-simulate`, to control transaction simulation before committing a transaction. See [this issue comment](#1702 (comment)) Resolves #1661. ## Reviewing notes - transpiler.TranspileAndCheckMempkg has been removed from the gnokey client and gnoclient, in favour of having this step be performed on the vm keeper. This paves the way for clients to not have to include the entire GnoVM, which I call a win. - Stdlib io had a precompiling error due to an unused variable (`remaining`); I updated it to the latest code on Go's standard libraries. - `Store` changes - `Store` has been changed to have its `getPackage` method work by detecting import cycles, without risking race conditions (the current implementation is not thread-safe). This is done by creating a new store, `importerStore`, which contains the previously imported paths in the current chain. Cyclic imports are still (correctly) detected in the tests. - `GetMemPackage` has been changed to return nil when a package cannot be found. This matches its behaviour with `GetMemFile`, which already did this when the file does not exist. - `GetMemPackage`, if a package is not found in the store, now attempts retrieving it using Store.GetPackage first. The underlying reason is that the Gno importer for the type checker needs to access the source of the standard libraries; however, these are never in any transaction and are not executed "per se" when the blockchain start. As a consequence, they may not exist within the Store; as a solution, when using GetMemPackage, we ensure that a package does not exist by checking if GetPackage does not retrieve it through getMemPackage and save it.
- Loading branch information
Showing
25 changed files
with
730 additions
and
151 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
||
# check error message | ||
! 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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# test for gnokey maketx -simulate options, and how they return any errors | ||
|
||
loadpkg gno.land/r/hello $WORK/hello | ||
|
||
# start a new node | ||
gnoland start | ||
|
||
# Initial state: assert that sequence == 0. | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "0"' | ||
|
||
# attempt adding the "test" package. | ||
# the package has a syntax error; simulation should catch this ahead of time and prevent the tx. | ||
# -simulate test | ||
! gnokey maketx addpkg -pkgdir $WORK/test -pkgpath gno.land/r/test -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -simulate test test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "0"' | ||
# -simulate only | ||
! gnokey maketx addpkg -pkgdir $WORK/test -pkgpath gno.land/r/test -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -simulate only test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "0"' | ||
# -simulate skip | ||
! gnokey maketx addpkg -pkgdir $WORK/test -pkgpath gno.land/r/test -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -simulate skip test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "1"' | ||
|
||
# attempt calling hello.SetName correctly. | ||
# -simulate test and skip should do it successfully, -simulate only should not. | ||
# -simulate test | ||
gnokey maketx call -pkgpath gno.land/r/hello -func SetName -args John -gas-wanted 2000000 -gas-fee 1000000ugnot -broadcast -chainid tendermint_test -simulate test test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "2"' | ||
gnokey query vm/qeval --data "gno.land/r/hello\nHello()" | ||
stdout 'Hello, John!' | ||
# -simulate only | ||
gnokey maketx call -pkgpath gno.land/r/hello -func SetName -args Paul -gas-wanted 2000000 -gas-fee 1000000ugnot -broadcast -chainid tendermint_test -simulate only test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "2"' | ||
gnokey query vm/qeval --data "gno.land/r/hello\nHello()" | ||
stdout 'Hello, John!' | ||
# -simulate skip | ||
gnokey maketx call -pkgpath gno.land/r/hello -func SetName -args George -gas-wanted 2000000 -gas-fee 1000000ugnot -broadcast -chainid tendermint_test -simulate skip test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "3"' | ||
gnokey query vm/qeval --data "gno.land/r/hello\nHello()" | ||
stdout 'Hello, George!' | ||
|
||
# attempt calling hello.Grumpy (always panics). | ||
# all calls should fail, however -test skip should increase the account sequence. | ||
# none should change the name (ie. panic rollbacks). | ||
# -simulate test | ||
! gnokey maketx call -pkgpath gno.land/r/hello -func Grumpy -gas-wanted 2000000 -gas-fee 1000000ugnot -broadcast -chainid tendermint_test -simulate test test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "3"' | ||
gnokey query vm/qeval --data "gno.land/r/hello\nHello()" | ||
stdout 'Hello, George!' | ||
# -simulate only | ||
! gnokey maketx call -pkgpath gno.land/r/hello -func Grumpy -gas-wanted 2000000 -gas-fee 1000000ugnot -broadcast -chainid tendermint_test -simulate only test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "3"' | ||
gnokey query vm/qeval --data "gno.land/r/hello\nHello()" | ||
stdout 'Hello, George!' | ||
# -simulate skip | ||
! gnokey maketx call -pkgpath gno.land/r/hello -func Grumpy -gas-wanted 2000000 -gas-fee 1000000ugnot -broadcast -chainid tendermint_test -simulate skip test1 | ||
gnokey query auth/accounts/$USER_ADDR_test1 | ||
stdout '"sequence": "4"' | ||
gnokey query vm/qeval --data "gno.land/r/hello\nHello()" | ||
stdout 'Hello, George!' | ||
|
||
-- test/test.gno -- | ||
package test | ||
|
||
func Render(path string) string { | ||
return 89 | ||
} | ||
|
||
-- hello/hello.gno -- | ||
package hello | ||
|
||
var name = "Ringo" | ||
|
||
func SetName(newName string) { | ||
name = newName | ||
} | ||
|
||
func Hello() string { | ||
return "Hello, " + name + "!" | ||
} | ||
|
||
func Grumpy() string { | ||
name = "SCOUNDREL" | ||
panic("YOU MAY NOT GREET ME, " + name) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.