diff --git a/examples/gno.land/p/demo/acl/gno.mod b/examples/gno.land/p/demo/acl/gno.mod index 176cde637bd..45ccdbe34d4 100644 --- a/examples/gno.land/p/demo/acl/gno.mod +++ b/examples/gno.land/p/demo/acl/gno.mod @@ -1,6 +1,6 @@ -module gno.land/p/demo/acl +module gno.land/p/demo/acl v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/testutils v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/testutils v0.1.0 ) diff --git a/examples/gno.land/p/demo/avl/gno.mod b/examples/gno.land/p/demo/avl/gno.mod index a6a2a1362e3..c7d446f4376 100644 --- a/examples/gno.land/p/demo/avl/gno.mod +++ b/examples/gno.land/p/demo/avl/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/avl +module gno.land/p/demo/avl v0.1.0 diff --git a/examples/gno.land/p/demo/bank/gno.mod b/examples/gno.land/p/demo/bank/gno.mod index 810731aed04..1b5227f6443 100644 --- a/examples/gno.land/p/demo/bank/gno.mod +++ b/examples/gno.land/p/demo/bank/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/bank +module gno.land/p/demo/bank v0.1.0 diff --git a/examples/gno.land/p/demo/bf/gno.mod b/examples/gno.land/p/demo/bf/gno.mod index b887582196c..50e634d0d75 100644 --- a/examples/gno.land/p/demo/bf/gno.mod +++ b/examples/gno.land/p/demo/bf/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/bf +module gno.land/p/demo/bf v0.1.0 diff --git a/examples/gno.land/p/demo/blog/gno.mod b/examples/gno.land/p/demo/blog/gno.mod index 65f58e7a0f6..868e6fa2d56 100644 --- a/examples/gno.land/p/demo/blog/gno.mod +++ b/examples/gno.land/p/demo/blog/gno.mod @@ -1,7 +1,7 @@ -module gno.land/p/demo/blog +module gno.land/p/demo/blog v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/mux v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/mux v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/p/demo/cford32/gno.mod b/examples/gno.land/p/demo/cford32/gno.mod index 20b99c65e4c..15d7c1495b6 100644 --- a/examples/gno.land/p/demo/cford32/gno.mod +++ b/examples/gno.land/p/demo/cford32/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/cford32 +module gno.land/p/demo/cford32 v0.1.0 diff --git a/examples/gno.land/p/demo/dom/gno.mod b/examples/gno.land/p/demo/dom/gno.mod index 83ca827cf66..22362d68ddf 100644 --- a/examples/gno.land/p/demo/dom/gno.mod +++ b/examples/gno.land/p/demo/dom/gno.mod @@ -1,3 +1,3 @@ -module gno.land/p/demo/dom +module gno.land/p/demo/dom v0.1.0 -require gno.land/p/demo/avl v0.0.0-latest +require gno.land/p/demo/avl v0.1.0 diff --git a/examples/gno.land/p/demo/flow/gno.mod b/examples/gno.land/p/demo/flow/gno.mod index 5adddbfe021..265bef68199 100644 --- a/examples/gno.land/p/demo/flow/gno.mod +++ b/examples/gno.land/p/demo/flow/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/flow +module gno.land/p/demo/flow v0.1.0 diff --git a/examples/gno.land/p/demo/gnode/gno.mod b/examples/gno.land/p/demo/gnode/gno.mod index a93c2051830..7b1dcabc2be 100644 --- a/examples/gno.land/p/demo/gnode/gno.mod +++ b/examples/gno.land/p/demo/gnode/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/gnode +module gno.land/p/demo/gnode v0.1.0 diff --git a/examples/gno.land/p/demo/grc/exts/gno.mod b/examples/gno.land/p/demo/grc/exts/gno.mod index 001c4bf1df0..f2224ae91a8 100644 --- a/examples/gno.land/p/demo/grc/exts/gno.mod +++ b/examples/gno.land/p/demo/grc/exts/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/grc/exts +module gno.land/p/demo/grc/exts v0.1.0 diff --git a/examples/gno.land/p/demo/grc/exts/vault/gno.mod b/examples/gno.land/p/demo/grc/exts/vault/gno.mod index 2720bf09d95..52bae123c67 100644 --- a/examples/gno.land/p/demo/grc/exts/vault/gno.mod +++ b/examples/gno.land/p/demo/grc/exts/vault/gno.mod @@ -1,6 +1,6 @@ -module gno.land/p/demo/grc/exts/vault +module gno.land/p/demo/grc/exts/vault v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/grc/grc20 v0.1.0 ) diff --git a/examples/gno.land/p/demo/grc/grc1155/gno.mod b/examples/gno.land/p/demo/grc/grc1155/gno.mod index b8db3675cf0..04b57fa5288 100644 --- a/examples/gno.land/p/demo/grc/grc1155/gno.mod +++ b/examples/gno.land/p/demo/grc/grc1155/gno.mod @@ -1,7 +1,7 @@ -module gno.land/p/demo/grc/grc1155 +module gno.land/p/demo/grc/grc1155 v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/p/demo/users v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/ufmt v0.1.0 + gno.land/p/demo/users v0.1.0 ) diff --git a/examples/gno.land/p/demo/grc/grc20/gno.mod b/examples/gno.land/p/demo/grc/grc20/gno.mod index fd80766a956..6d0af030e5e 100644 --- a/examples/gno.land/p/demo/grc/grc20/gno.mod +++ b/examples/gno.land/p/demo/grc/grc20/gno.mod @@ -1,7 +1,7 @@ -module gno.land/p/demo/grc/grc20 +module gno.land/p/demo/grc/grc20 v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/grc/exts v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/grc/exts v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/p/demo/grc/grc721/gno.mod b/examples/gno.land/p/demo/grc/grc721/gno.mod index 1eada28e4ee..d3380fb2cca 100644 --- a/examples/gno.land/p/demo/grc/grc721/gno.mod +++ b/examples/gno.land/p/demo/grc/grc721/gno.mod @@ -1,8 +1,8 @@ -module gno.land/p/demo/grc/grc721 +module gno.land/p/demo/grc/grc721 v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/testutils v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/p/demo/users v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/testutils v0.1.0 + gno.land/p/demo/ufmt v0.1.0 + gno.land/p/demo/users v0.1.0 ) diff --git a/examples/gno.land/p/demo/grc/grc777/gno.mod b/examples/gno.land/p/demo/grc/grc777/gno.mod index 9fbf2f2b7cd..f5298f21d31 100644 --- a/examples/gno.land/p/demo/grc/grc777/gno.mod +++ b/examples/gno.land/p/demo/grc/grc777/gno.mod @@ -1,3 +1,3 @@ -module gno.land/p/demo/grc/grc777 +module gno.land/p/demo/grc/grc777 v0.1.0 -require gno.land/p/demo/grc/exts v0.0.0-latest +require gno.land/p/demo/grc/exts v0.1.0 diff --git a/examples/gno.land/p/demo/groups/gno.mod b/examples/gno.land/p/demo/groups/gno.mod index 0e9f7cf2a7c..c1155159059 100644 --- a/examples/gno.land/p/demo/groups/gno.mod +++ b/examples/gno.land/p/demo/groups/gno.mod @@ -1,6 +1,6 @@ -module gno.land/p/demo/groups +module gno.land/p/demo/groups v0.1.0 require ( - gno.land/p/demo/maths v0.0.0-latest - gno.land/r/demo/boards v0.0.0-latest + gno.land/p/demo/maths v0.1.0 + gno.land/r/demo/boards v0.1.0 ) diff --git a/examples/gno.land/p/demo/math_eval/int32/gno.mod b/examples/gno.land/p/demo/math_eval/int32/gno.mod index de57497a699..448393d8868 100644 --- a/examples/gno.land/p/demo/math_eval/int32/gno.mod +++ b/examples/gno.land/p/demo/math_eval/int32/gno.mod @@ -1,3 +1,3 @@ -module gno.land/p/demo/math_eval/int32 +module gno.land/p/demo/math_eval/int32 v0.1.0 -require gno.land/p/demo/ufmt v0.0.0-latest +require gno.land/p/demo/ufmt v0.1.0 diff --git a/examples/gno.land/p/demo/maths/gno.mod b/examples/gno.land/p/demo/maths/gno.mod index d320b653702..ca8ba96cd40 100644 --- a/examples/gno.land/p/demo/maths/gno.mod +++ b/examples/gno.land/p/demo/maths/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/maths +module gno.land/p/demo/maths v0.1.0 diff --git a/examples/gno.land/p/demo/merkle/gno.mod b/examples/gno.land/p/demo/merkle/gno.mod index ae70400aa6d..bb6c784fd23 100644 --- a/examples/gno.land/p/demo/merkle/gno.mod +++ b/examples/gno.land/p/demo/merkle/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/merkle +module gno.land/p/demo/merkle v0.1.0 diff --git a/examples/gno.land/p/demo/microblog/gno.mod b/examples/gno.land/p/demo/microblog/gno.mod index 9bbcfa19e31..05e1659e963 100644 --- a/examples/gno.land/p/demo/microblog/gno.mod +++ b/examples/gno.land/p/demo/microblog/gno.mod @@ -1,6 +1,6 @@ -module gno.land/p/demo/microblog +module gno.land/p/demo/microblog v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/p/demo/mux/gno.mod b/examples/gno.land/p/demo/mux/gno.mod index 972a531e14c..ff7c845ccbc 100644 --- a/examples/gno.land/p/demo/mux/gno.mod +++ b/examples/gno.land/p/demo/mux/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/mux +module gno.land/p/demo/mux v0.1.0 diff --git a/examples/gno.land/p/demo/ownable/gno.mod b/examples/gno.land/p/demo/ownable/gno.mod index 9a9abb1e661..407ce1b9c17 100644 --- a/examples/gno.land/p/demo/ownable/gno.mod +++ b/examples/gno.land/p/demo/ownable/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/ownable +module gno.land/p/demo/ownable v0.1.0 diff --git a/examples/gno.land/p/demo/pausable/gno.mod b/examples/gno.land/p/demo/pausable/gno.mod index 08c7a4f7e5f..79abceac2fe 100644 --- a/examples/gno.land/p/demo/pausable/gno.mod +++ b/examples/gno.land/p/demo/pausable/gno.mod @@ -1,3 +1,3 @@ -module gno.land/p/demo/pausable +module gno.land/p/demo/pausable v0.1.0 -require gno.land/p/demo/ownable v0.0.0-latest +require gno.land/p/demo/ownable v0.1.0 diff --git a/examples/gno.land/p/demo/rand/gno.mod b/examples/gno.land/p/demo/rand/gno.mod index 098af152648..6e2e70ca9e4 100644 --- a/examples/gno.land/p/demo/rand/gno.mod +++ b/examples/gno.land/p/demo/rand/gno.mod @@ -1,3 +1,3 @@ // Draft -module gno.land/p/demo/rand +module gno.land/p/demo/rand v0.1.0 diff --git a/examples/gno.land/p/demo/releases/gno.mod b/examples/gno.land/p/demo/releases/gno.mod index 93214b9bc08..de36f4a5a5f 100644 --- a/examples/gno.land/p/demo/releases/gno.mod +++ b/examples/gno.land/p/demo/releases/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/releases +module gno.land/p/demo/releases v0.1.0 diff --git a/examples/gno.land/p/demo/seqid/gno.mod b/examples/gno.land/p/demo/seqid/gno.mod index d1390012c3c..5309e203652 100644 --- a/examples/gno.land/p/demo/seqid/gno.mod +++ b/examples/gno.land/p/demo/seqid/gno.mod @@ -1,3 +1,3 @@ -module gno.land/p/demo/seqid +module gno.land/p/demo/seqid v0.1.0 -require gno.land/p/demo/cford32 v0.0.0-latest +require gno.land/p/demo/cford32 v0.1.0 diff --git a/examples/gno.land/p/demo/stack/gno.mod b/examples/gno.land/p/demo/stack/gno.mod index e39ec7b8f28..873f265cd4d 100644 --- a/examples/gno.land/p/demo/stack/gno.mod +++ b/examples/gno.land/p/demo/stack/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/stack +module gno.land/p/demo/stack v0.1.0 diff --git a/examples/gno.land/p/demo/svg/gno.mod b/examples/gno.land/p/demo/svg/gno.mod index 0af7ba0636d..f809ef2398a 100644 --- a/examples/gno.land/p/demo/svg/gno.mod +++ b/examples/gno.land/p/demo/svg/gno.mod @@ -1,3 +1,3 @@ -module gno.land/p/demo/svg +module gno.land/p/demo/svg v0.1.0 -require gno.land/p/demo/ufmt v0.0.0-latest +require gno.land/p/demo/ufmt v0.1.0 diff --git a/examples/gno.land/p/demo/tamagotchi/gno.mod b/examples/gno.land/p/demo/tamagotchi/gno.mod index 58441284a6b..76c07ea6d75 100644 --- a/examples/gno.land/p/demo/tamagotchi/gno.mod +++ b/examples/gno.land/p/demo/tamagotchi/gno.mod @@ -1,3 +1,3 @@ -module gno.land/p/demo/tamagotchi +module gno.land/p/demo/tamagotchi v0.1.0 -require gno.land/p/demo/ufmt v0.0.0-latest +require gno.land/p/demo/ufmt v0.1.0 diff --git a/examples/gno.land/p/demo/tests/gno.mod b/examples/gno.land/p/demo/tests/gno.mod index 5d80e106567..89b639b993d 100644 --- a/examples/gno.land/p/demo/tests/gno.mod +++ b/examples/gno.land/p/demo/tests/gno.mod @@ -1,6 +1,6 @@ -module gno.land/p/demo/tests +module gno.land/p/demo/tests v0.1.0 require ( - gno.land/p/demo/tests/subtests v0.0.0-latest - gno.land/r/demo/tests v0.0.0-latest + gno.land/p/demo/tests/subtests v0.1.0 + gno.land/r/demo/tests v0.1.0 ) diff --git a/examples/gno.land/p/demo/tests/subtests/gno.mod b/examples/gno.land/p/demo/tests/subtests/gno.mod index c8333722809..195df7da0a5 100644 --- a/examples/gno.land/p/demo/tests/subtests/gno.mod +++ b/examples/gno.land/p/demo/tests/subtests/gno.mod @@ -1,4 +1,4 @@ -module gno.land/p/demo/tests/subtests +module gno.land/p/demo/tests/subtests v0.1.0 // TODO: this file should not exist. // This is a temporary workaround. Until https://github.com/gnolang/gno/issues/852 diff --git a/examples/gno.land/p/demo/testutils/gno.mod b/examples/gno.land/p/demo/testutils/gno.mod index 0c97bf4b367..3c1bdfff75e 100644 --- a/examples/gno.land/p/demo/testutils/gno.mod +++ b/examples/gno.land/p/demo/testutils/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/testutils +module gno.land/p/demo/testutils v0.1.0 diff --git a/examples/gno.land/p/demo/ufmt/gno.mod b/examples/gno.land/p/demo/ufmt/gno.mod index 61b52b09fed..5530f179708 100644 --- a/examples/gno.land/p/demo/ufmt/gno.mod +++ b/examples/gno.land/p/demo/ufmt/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/ufmt +module gno.land/p/demo/ufmt v0.1.0 diff --git a/examples/gno.land/p/demo/ui/gno.mod b/examples/gno.land/p/demo/ui/gno.mod index 41f5cb78d83..d2e6bb2451a 100644 --- a/examples/gno.land/p/demo/ui/gno.mod +++ b/examples/gno.land/p/demo/ui/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/ui +module gno.land/p/demo/ui v0.1.0 diff --git a/examples/gno.land/p/demo/users/gno.mod b/examples/gno.land/p/demo/users/gno.mod index ad652803fb8..32876e169dc 100644 --- a/examples/gno.land/p/demo/users/gno.mod +++ b/examples/gno.land/p/demo/users/gno.mod @@ -1 +1 @@ -module gno.land/p/demo/users +module gno.land/p/demo/users v0.1.0 diff --git a/examples/gno.land/r/demo/art/gnoface/gno.mod b/examples/gno.land/r/demo/art/gnoface/gno.mod index bc17ee9df3b..e2aa02902e1 100644 --- a/examples/gno.land/r/demo/art/gnoface/gno.mod +++ b/examples/gno.land/r/demo/art/gnoface/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/art/gnoface +module gno.land/r/demo/art/gnoface v0.1.0 require ( - gno.land/p/demo/rand v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/rand v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/r/demo/art/millipede/gno.mod b/examples/gno.land/r/demo/art/millipede/gno.mod index 346e3a1673c..e128ec59c6f 100644 --- a/examples/gno.land/r/demo/art/millipede/gno.mod +++ b/examples/gno.land/r/demo/art/millipede/gno.mod @@ -1,3 +1,3 @@ -module gno.land/r/demo/art/millipede +module gno.land/r/demo/art/millipede v0.1.0 -require gno.land/p/demo/ufmt v0.0.0-latest +require gno.land/p/demo/ufmt v0.1.0 diff --git a/examples/gno.land/r/demo/banktest/gno.mod b/examples/gno.land/r/demo/banktest/gno.mod index 7660f338c13..a707a7dd885 100644 --- a/examples/gno.land/r/demo/banktest/gno.mod +++ b/examples/gno.land/r/demo/banktest/gno.mod @@ -1 +1 @@ -module gno.land/r/demo/banktest +module gno.land/r/demo/banktest v0.1.0 diff --git a/examples/gno.land/r/demo/boards/gno.mod b/examples/gno.land/r/demo/boards/gno.mod index 434ad019883..324e763e531 100644 --- a/examples/gno.land/r/demo/boards/gno.mod +++ b/examples/gno.land/r/demo/boards/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/boards +module gno.land/r/demo/boards v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/r/demo/users v0.1.0 ) diff --git a/examples/gno.land/r/demo/deep/very/deep/gno.mod b/examples/gno.land/r/demo/deep/very/deep/gno.mod index ab5a9ef8536..369c0ee137d 100644 --- a/examples/gno.land/r/demo/deep/very/deep/gno.mod +++ b/examples/gno.land/r/demo/deep/very/deep/gno.mod @@ -1 +1 @@ -module gno.land/r/demo/deep/very/deep +module gno.land/r/demo/deep/very/deep v0.1.0 diff --git a/examples/gno.land/r/demo/foo1155/gno.mod b/examples/gno.land/r/demo/foo1155/gno.mod index 0a405c5b4a2..a8ac3463304 100644 --- a/examples/gno.land/r/demo/foo1155/gno.mod +++ b/examples/gno.land/r/demo/foo1155/gno.mod @@ -1,8 +1,8 @@ -module gno.land/r/demo/foo1155 +module gno.land/r/demo/foo1155 v0.1.0 require ( - gno.land/p/demo/grc/grc1155 v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/p/demo/users v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest + gno.land/p/demo/grc/grc1155 v0.1.0 + gno.land/p/demo/ufmt v0.1.0 + gno.land/p/demo/users v0.1.0 + gno.land/r/demo/users v0.1.0 ) diff --git a/examples/gno.land/r/demo/foo20/gno.mod b/examples/gno.land/r/demo/foo20/gno.mod index 96fefcf6163..3cc47621b44 100644 --- a/examples/gno.land/r/demo/foo20/gno.mod +++ b/examples/gno.land/r/demo/foo20/gno.mod @@ -1,8 +1,8 @@ -module gno.land/r/demo/foo20 +module gno.land/r/demo/foo20 v0.1.0 require ( - gno.land/p/demo/grc/grc20 v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/p/demo/users v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest + gno.land/p/demo/grc/grc20 v0.1.0 + gno.land/p/demo/ufmt v0.1.0 + gno.land/p/demo/users v0.1.0 + gno.land/r/demo/users v0.1.0 ) diff --git a/examples/gno.land/r/demo/foo721/gno.mod b/examples/gno.land/r/demo/foo721/gno.mod index e013677379d..ceb67c84b4c 100644 --- a/examples/gno.land/r/demo/foo721/gno.mod +++ b/examples/gno.land/r/demo/foo721/gno.mod @@ -1,8 +1,8 @@ -module gno.land/r/demo/foo721 +module gno.land/r/demo/foo721 v0.1.0 require ( - gno.land/p/demo/grc/grc721 v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/p/demo/users v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest + gno.land/p/demo/grc/grc721 v0.1.0 + gno.land/p/demo/ufmt v0.1.0 + gno.land/p/demo/users v0.1.0 + gno.land/r/demo/users v0.1.0 ) diff --git a/examples/gno.land/r/demo/groups/gno.mod b/examples/gno.land/r/demo/groups/gno.mod index fc6756e13e2..8c06ba53d9e 100644 --- a/examples/gno.land/r/demo/groups/gno.mod +++ b/examples/gno.land/r/demo/groups/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/groups +module gno.land/r/demo/groups v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/r/demo/users v0.1.0 ) diff --git a/examples/gno.land/r/demo/keystore/gno.mod b/examples/gno.land/r/demo/keystore/gno.mod index af0b907c259..6bdc66344f4 100644 --- a/examples/gno.land/r/demo/keystore/gno.mod +++ b/examples/gno.land/r/demo/keystore/gno.mod @@ -1,7 +1,7 @@ -module gno.land/r/demo/keystore +module gno.land/r/demo/keystore v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/testutils v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/testutils v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/r/demo/markdown_test/gno.mod b/examples/gno.land/r/demo/markdown_test/gno.mod index 19c0d1dcfb3..7d412ec4d35 100644 --- a/examples/gno.land/r/demo/markdown_test/gno.mod +++ b/examples/gno.land/r/demo/markdown_test/gno.mod @@ -1 +1 @@ -module gno.land/r/demo/markdown_test +module gno.land/r/demo/markdown_test v0.1.0 diff --git a/examples/gno.land/r/demo/math_eval/gno.mod b/examples/gno.land/r/demo/math_eval/gno.mod index 0e3fcfe6e9b..2f09228a500 100644 --- a/examples/gno.land/r/demo/math_eval/gno.mod +++ b/examples/gno.land/r/demo/math_eval/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/math_eval +module gno.land/r/demo/math_eval v0.1.0 require ( - gno.land/p/demo/math_eval/int32 v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/math_eval/int32 v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/r/demo/microblog/gno.mod b/examples/gno.land/r/demo/microblog/gno.mod index 3285127b025..f096d095be7 100644 --- a/examples/gno.land/r/demo/microblog/gno.mod +++ b/examples/gno.land/r/demo/microblog/gno.mod @@ -1,9 +1,9 @@ -module gno.land/r/demo/microblog +module gno.land/r/demo/microblog v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/microblog v0.0.0-latest - gno.land/p/demo/testutils v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/microblog v0.1.0 + gno.land/p/demo/testutils v0.1.0 + gno.land/p/demo/ufmt v0.1.0 + gno.land/r/demo/users v0.1.0 ) diff --git a/examples/gno.land/r/demo/nft/gno.mod b/examples/gno.land/r/demo/nft/gno.mod index 89e0055be51..91661d198a2 100644 --- a/examples/gno.land/r/demo/nft/gno.mod +++ b/examples/gno.land/r/demo/nft/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/nft +module gno.land/r/demo/nft v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/grc/grc721 v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/grc/grc721 v0.1.0 ) diff --git a/examples/gno.land/r/demo/releases_example/gno.mod b/examples/gno.land/r/demo/releases_example/gno.mod index 22f640fe797..8bcb7f9dd59 100644 --- a/examples/gno.land/r/demo/releases_example/gno.mod +++ b/examples/gno.land/r/demo/releases_example/gno.mod @@ -1,3 +1,3 @@ -module gno.land/r/demo/releases_example +module gno.land/r/demo/releases_example v0.1.0 -require gno.land/p/demo/releases v0.0.0-latest +require gno.land/p/demo/releases v0.1.0 diff --git a/examples/gno.land/r/demo/tamagotchi/gno.mod b/examples/gno.land/r/demo/tamagotchi/gno.mod index b7a2deea2c2..4aa80d30b16 100644 --- a/examples/gno.land/r/demo/tamagotchi/gno.mod +++ b/examples/gno.land/r/demo/tamagotchi/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/tamagotchi +module gno.land/r/demo/tamagotchi v0.1.0 require ( - gno.land/p/demo/tamagotchi v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/tamagotchi v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/r/demo/tests/gno.mod b/examples/gno.land/r/demo/tests/gno.mod index 9c5162f848e..c2652b75919 100644 --- a/examples/gno.land/r/demo/tests/gno.mod +++ b/examples/gno.land/r/demo/tests/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/tests +module gno.land/r/demo/tests v0.1.0 require ( - gno.land/p/demo/testutils v0.0.0-latest - gno.land/r/demo/tests/subtests v0.0.0-latest + gno.land/p/demo/testutils v0.1.0 + gno.land/r/demo/tests/subtests v0.1.0 ) diff --git a/examples/gno.land/r/demo/tests/subtests/gno.mod b/examples/gno.land/r/demo/tests/subtests/gno.mod index 9f466ff77b9..5eb3d25408f 100644 --- a/examples/gno.land/r/demo/tests/subtests/gno.mod +++ b/examples/gno.land/r/demo/tests/subtests/gno.mod @@ -1,4 +1,4 @@ -module gno.land/r/demo/tests/subtests +module gno.land/r/demo/tests/subtests v0.1.0 // TODO: this file should not exist. // This is a temporary workaround. Until https://github.com/gnolang/gno/issues/852 diff --git a/examples/gno.land/r/demo/tests/tests_test.gno b/examples/gno.land/r/demo/tests/tests_test.gno index 3dcbeecf18c..21d70d40a93 100644 --- a/examples/gno.land/r/demo/tests/tests_test.gno +++ b/examples/gno.land/r/demo/tests/tests_test.gno @@ -34,8 +34,8 @@ func TestAssertOriginCall(t *testing.T) { func TestPrevRealm(t *testing.T) { var ( - user1Addr = std.DerivePkgAddr("user1.gno") - rTestsAddr = std.DerivePkgAddr("gno.land/r/demo/tests") + user1Addr = std.DerivePkgAddr("user1.gno", "") + rTestsAddr = std.DerivePkgAddr("gno.land/r/demo/tests", "v0.1.0") ) // When a single realm in the frames, PrevRealm returns the user if addr := GetPrevRealm().Addr(); addr != user1Addr { diff --git a/examples/gno.land/r/demo/tests_foo/gno.mod b/examples/gno.land/r/demo/tests_foo/gno.mod index 226271ae4b0..f8e0ce7cd7c 100644 --- a/examples/gno.land/r/demo/tests_foo/gno.mod +++ b/examples/gno.land/r/demo/tests_foo/gno.mod @@ -1,3 +1,3 @@ -module gno.land/r/demo/tests_foo +module gno.land/r/demo/tests_foo v0.1.0 -require gno.land/r/demo/tests v0.0.0-latest +require gno.land/r/demo/tests v0.1.0 diff --git a/examples/gno.land/r/demo/types/gno.mod b/examples/gno.land/r/demo/types/gno.mod index 0e86e5d5676..669560645a6 100644 --- a/examples/gno.land/r/demo/types/gno.mod +++ b/examples/gno.land/r/demo/types/gno.mod @@ -1,3 +1,3 @@ -module gno.land/r/demo/types +module gno.land/r/demo/types v0.1.0 -require gno.land/p/demo/avl v0.0.0-latest +require gno.land/p/demo/avl v0.1.0 diff --git a/examples/gno.land/r/demo/ui/gno.mod b/examples/gno.land/r/demo/ui/gno.mod index 42be8cec3f0..95b70c2c0f9 100644 --- a/examples/gno.land/r/demo/ui/gno.mod +++ b/examples/gno.land/r/demo/ui/gno.mod @@ -1,3 +1,3 @@ -module gno.land/r/demo/ui +module gno.land/r/demo/ui v0.1.0 -require gno.land/p/demo/ui v0.0.0-latest +require gno.land/p/demo/ui v0.1.0 diff --git a/examples/gno.land/r/demo/users/gno.mod b/examples/gno.land/r/demo/users/gno.mod index a2ee2ea86ba..59a70bdaabd 100644 --- a/examples/gno.land/r/demo/users/gno.mod +++ b/examples/gno.land/r/demo/users/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/users +module gno.land/r/demo/users v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/users v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/users v0.1.0 ) diff --git a/examples/gno.land/r/demo/wugnot/gno.mod b/examples/gno.land/r/demo/wugnot/gno.mod index 1f03ded515c..491b895973b 100644 --- a/examples/gno.land/r/demo/wugnot/gno.mod +++ b/examples/gno.land/r/demo/wugnot/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/demo/wugnot +module gno.land/r/demo/wugnot v0.1.0 require ( - gno.land/p/demo/grc/grc20 v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/grc/grc20 v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/r/gnoland/blog/gno.mod b/examples/gno.land/r/gnoland/blog/gno.mod index 1d64238cdc8..0e1eea099db 100644 --- a/examples/gno.land/r/gnoland/blog/gno.mod +++ b/examples/gno.land/r/gnoland/blog/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/gnoland/blog +module gno.land/r/gnoland/blog v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/blog v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/blog v0.1.0 ) diff --git a/examples/gno.land/r/gnoland/faucet/gno.mod b/examples/gno.land/r/gnoland/faucet/gno.mod index 693b0e795cf..86dd8f3d147 100644 --- a/examples/gno.land/r/gnoland/faucet/gno.mod +++ b/examples/gno.land/r/gnoland/faucet/gno.mod @@ -1,7 +1,7 @@ -module gno.land/r/gnoland/faucet +module gno.land/r/gnoland/faucet v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/testutils v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/testutils v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/r/gnoland/home/gno.mod b/examples/gno.land/r/gnoland/home/gno.mod index 2864958930c..84ffa6de7a9 100644 --- a/examples/gno.land/r/gnoland/home/gno.mod +++ b/examples/gno.land/r/gnoland/home/gno.mod @@ -1,7 +1,7 @@ -module gno.land/r/gnoland/home +module gno.land/r/gnoland/home v0.1.0 require ( - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/p/demo/ui v0.0.0-latest - gno.land/r/gnoland/blog v0.0.0-latest + gno.land/p/demo/ufmt v0.1.0 + gno.land/p/demo/ui v0.1.0 + gno.land/r/gnoland/blog v0.1.0 ) diff --git a/examples/gno.land/r/gnoland/pages/gno.mod b/examples/gno.land/r/gnoland/pages/gno.mod index 31e9ad2c85b..d71ea033154 100644 --- a/examples/gno.land/r/gnoland/pages/gno.mod +++ b/examples/gno.land/r/gnoland/pages/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/gnoland/pages +module gno.land/r/gnoland/pages v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/blog v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/blog v0.1.0 ) diff --git a/examples/gno.land/r/manfred/config/gno.mod b/examples/gno.land/r/manfred/config/gno.mod index 516bf38528e..1ea12f4aefa 100644 --- a/examples/gno.land/r/manfred/config/gno.mod +++ b/examples/gno.land/r/manfred/config/gno.mod @@ -1 +1 @@ -module gno.land/r/manfred/config +module gno.land/r/manfred/config v0.1.0 diff --git a/examples/gno.land/r/manfred/home/gno.mod b/examples/gno.land/r/manfred/home/gno.mod index 6e7aac70cc7..c0e7c17ff61 100644 --- a/examples/gno.land/r/manfred/home/gno.mod +++ b/examples/gno.land/r/manfred/home/gno.mod @@ -1,3 +1,3 @@ -module gno.land/r/manfred/home +module gno.land/r/manfred/home v0.1.0 -require gno.land/r/manfred/config v0.0.0-latest +require gno.land/r/manfred/config v0.1.0 diff --git a/examples/gno.land/r/manfred/present/gno.mod b/examples/gno.land/r/manfred/present/gno.mod index 5d50447e0e0..43457f9e430 100644 --- a/examples/gno.land/r/manfred/present/gno.mod +++ b/examples/gno.land/r/manfred/present/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/manfred/present +module gno.land/r/manfred/present v0.1.0 require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/blog v0.0.0-latest + gno.land/p/demo/avl v0.1.0 + gno.land/p/demo/blog v0.1.0 ) diff --git a/examples/gno.land/r/system/names/gno.mod b/examples/gno.land/r/system/names/gno.mod index cd4fd0aae4a..888b5d3b97a 100644 --- a/examples/gno.land/r/system/names/gno.mod +++ b/examples/gno.land/r/system/names/gno.mod @@ -1,3 +1,3 @@ -module gno.land/r/system/names +module gno.land/r/system/names v0.1.0 -require gno.land/p/demo/avl v0.0.0-latest +require gno.land/p/demo/avl v0.1.0 diff --git a/examples/gno.land/r/system/rewards/gno.mod b/examples/gno.land/r/system/rewards/gno.mod index e785c4675b5..fbdf6b56040 100644 --- a/examples/gno.land/r/system/rewards/gno.mod +++ b/examples/gno.land/r/system/rewards/gno.mod @@ -1 +1 @@ -module gno.land/r/system/rewards +module gno.land/r/system/rewards v0.1.0 diff --git a/examples/gno.land/r/system/validators/gno.mod b/examples/gno.land/r/system/validators/gno.mod index fdc8d556e56..1026e5d0c40 100644 --- a/examples/gno.land/r/system/validators/gno.mod +++ b/examples/gno.land/r/system/validators/gno.mod @@ -1 +1 @@ -module gno.land/r/system/validators +module gno.land/r/system/validators v0.1.0 diff --git a/examples/gno.land/r/x/manfred_outfmt/gno.mod b/examples/gno.land/r/x/manfred_outfmt/gno.mod index e6f705c46b9..14661b75831 100644 --- a/examples/gno.land/r/x/manfred_outfmt/gno.mod +++ b/examples/gno.land/r/x/manfred_outfmt/gno.mod @@ -1,6 +1,6 @@ -module gno.land/r/x/manfred_outfmt +module gno.land/r/x/manfred_outfmt v0.1.0 require ( - gno.land/p/demo/rand v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/rand v0.1.0 + gno.land/p/demo/ufmt v0.1.0 ) diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/gno.mod b/examples/gno.land/r/x/manfred_upgrade_patterns/gno.mod index d6e97dc39b9..21b1ec776cb 100644 --- a/examples/gno.land/r/x/manfred_upgrade_patterns/gno.mod +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/gno.mod @@ -1,3 +1,3 @@ // Draft -module gno.land/r/x/manfred_upgrade_patterns +module gno.land/r/x/manfred_upgrade_patterns v0.1.0 diff --git a/gno.land/cmd/gnoland/testdata/addpkg.txtar b/gno.land/cmd/gnoland/testdata/addpkg.txtar index e7437552b50..5d7e8c60354 100644 --- a/gno.land/cmd/gnoland/testdata/addpkg.txtar +++ b/gno.land/cmd/gnoland/testdata/addpkg.txtar @@ -4,10 +4,10 @@ gnoland start ## add bar.gno 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 +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 ## execute Render -gnokey maketx call -pkgpath gno.land/r/foobar/bar -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foobar/bar@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 ## compare render stdout '("hello from foo" string)' @@ -15,6 +15,9 @@ stdout 'OK!' stdout 'GAS WANTED: 2000000' stdout 'GAS USED: [0-9]+' +-- gno.mod -- +module gno.land/r/foobar/bar v0.0.0 + -- bar.gno -- package bar diff --git a/gno.land/cmd/gnoland/testdata/append.txtar b/gno.land/cmd/gnoland/testdata/append.txtar index 46b66f9524b..4f7650ccdf8 100644 --- a/gno.land/cmd/gnoland/testdata/append.txtar +++ b/gno.land/cmd/gnoland/testdata/append.txtar @@ -3,72 +3,77 @@ loadpkg gno.land/p/demo/ufmt # start a new node gnoland start -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/append -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 1 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '1' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '1' -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func AppendNil -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func AppendNil -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 2 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '2' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '2' -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 3 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '3' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '3' -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("1-2-3-" string)' stdout OK! # Call Pop -gnokey maketx call -pkgpath gno.land/r/append -func Pop -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Pop -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-" string)' stdout OK! # Call Append 42 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '42' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '42' -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func CopyAppend -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func CopyAppend -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func PopB -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func PopB -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func AppendMoreAndC -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func AppendMoreAndC -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func ReassignC -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func ReassignC -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-70-100-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args 'd' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args 'd' -broadcast -chainid=tendermint_test test1 stdout '("1-" string)' stdout OK! +-- gno.mod -- +module gno.land/r/append v0.0.0 + +require gno.land/p/demo/ufmt v0.1.0 + -- append.gno -- package append diff --git a/gno.land/cmd/gnoland/testdata/float-arg.txtar b/gno.land/cmd/gnoland/testdata/float-arg.txtar index ac684fc8fab..d349ae58913 100644 --- a/gno.land/cmd/gnoland/testdata/float-arg.txtar +++ b/gno.land/cmd/gnoland/testdata/float-arg.txtar @@ -3,14 +3,17 @@ ## start a new node gnoland start -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/float_realm -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -gnokey maketx call -pkgpath gno.land/r/demo/float_realm --func AddF32 -args 10.5 --args 20 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/float_realm@v0.0.0 --func AddF32 -args 10.5 --args 20 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 stdout '(30.5 float32)' -gnokey maketx call -pkgpath gno.land/r/demo/float_realm --func AddF64 -args 3.1 --args 2.2 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/float_realm@v0.0.0 --func AddF64 -args 3.1 --args 2.2 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 stdout '(5.3[0-9]* float64)' +-- gno.mod -- +module gno.land/r/demo/float_realm v0.0.0 + -- float_realm.gno -- package float_realm diff --git a/gno.land/cmd/gnoland/testdata/grc20-registry.txtar b/gno.land/cmd/gnoland/testdata/grc20-registry.txtar index 20e78f7ba6e..bd108f3a971 100644 --- a/gno.land/cmd/gnoland/testdata/grc20-registry.txtar +++ b/gno.land/cmd/gnoland/testdata/grc20-registry.txtar @@ -6,17 +6,20 @@ loadpkg gno.land/r/registry $WORK/registry gnoland start # we call Transfer with foo20, before it's registered -gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/registry@v0.0.0 -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout 'not found' # add foo20, and foo20wrapper -gnokey maketx addpkg -pkgdir $WORK/foo20 -pkgpath gno.land/r/foo20 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -gnokey maketx addpkg -pkgdir $WORK/foo20wrapper -pkgpath gno.land/r/foo20wrapper -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK/foo20 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK/foo20wrapper -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 # we call Transfer with foo20, after it's registered -gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/registry@v0.0.0 -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout 'same address, success!' +-- registry/gno.mod -- +module gno.land/r/registry v0.0.0 + -- registry/registry.gno -- package registry @@ -42,15 +45,8 @@ func TransferByName(name string, to string, amount uint64) string { return "not found" } --- foo20wrapper/foo20wrapper.gno -- -package foo20wrapper - -import "gno.land/r/registry" -import "gno.land/r/foo20" - -func init() { - registry.Register("foo20", foo20.Transfer) -} +-- foo20/gno.mod -- +module gno.land/r/foo20 v0.0.0 -- foo20/foo20.gno -- package foo20 @@ -61,3 +57,21 @@ func Transfer(to std.Address, amount uint64) string { println("transfer from=" + std.PrevRealm().Addr().String() + " to=" + to.String() + " some-amount") return std.PrevRealm().Addr().String() } + +-- foo20wrapper/gno.mod -- +module gno.land/r/foo20wrapper v0.0.0 + +require ( + gno.land/r/registry v0.0.0 + gno.land/r/foo20 v0.0.0 +) + +-- foo20wrapper/foo20wrapper.gno -- +package foo20wrapper + +import "gno.land/r/registry" +import "gno.land/r/foo20" + +func init() { + registry.Register("foo20", foo20.Transfer) +} diff --git a/gno.land/cmd/gnoland/testdata/issue-1167.txtar b/gno.land/cmd/gnoland/testdata/issue-1167.txtar index c43f7a45bd5..5bef5408a60 100644 --- a/gno.land/cmd/gnoland/testdata/issue-1167.txtar +++ b/gno.land/cmd/gnoland/testdata/issue-1167.txtar @@ -4,38 +4,38 @@ loadpkg gno.land/p/demo/avl gnoland start # add contract -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/xx -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! # execute New -gnokey maketx call -pkgpath gno.land/r/demo/xx -func New -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx@v0.0.0 -func New -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! # execute Delta for the first time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx@v0.0.0 -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '"1,1,1;" string' # execute Delta for the second time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx@v0.0.0 -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;" string' # execute Delta for the third time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx@v0.0.0 -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;3,3,3;" string' # execute Render -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Render -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx@v0.0.0 -func Render -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;3,3,3;" string' -- gno.mod -- -module gno.land/r/demo/xx +module gno.land/r/demo/xx v0.0.0 require ( - gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/avl v0.1.0 ) -- realm.gno -- diff --git a/gno.land/cmd/gnoland/testdata/issue-1588.txtar b/gno.land/cmd/gnoland/testdata/issue-1588.txtar index dc2467ca75e..32f5b9bb200 100644 --- a/gno.land/cmd/gnoland/testdata/issue-1588.txtar +++ b/gno.land/cmd/gnoland/testdata/issue-1588.txtar @@ -3,18 +3,18 @@ gnoland start # add contract -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/xx -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/demo/xx -func DefineFamily -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx@v0.0.0 -func DefineFamily -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/demo/xx -func GetOutcastChildAge -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx@v0.0.0 -func GetOutcastChildAge -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '(10 int)' -- gno.mod -- -module gno.land/r/demo/xx +module gno.land/r/demo/xx v0.0.0 -- realm.gno -- package xx diff --git a/gno.land/cmd/gnoland/testdata/issue-gnochess-97.txtar b/gno.land/cmd/gnoland/testdata/issue-gnochess-97.txtar index 89406d328d4..e5c08000bc1 100644 --- a/gno.land/cmd/gnoland/testdata/issue-gnochess-97.txtar +++ b/gno.land/cmd/gnoland/testdata/issue-gnochess-97.txtar @@ -2,17 +2,20 @@ gnoland start -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/bug97 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -gnokey maketx call -pkgpath 'gno.land/r/demo/bug97' -func 'RealmCall1' -gas-fee 1000000ugnot -gas-wanted 2000000 -send '' -broadcast -chainid='tendermint_test' test1 +gnokey maketx call -pkgpath 'gno.land/r/demo/bug97@v0.0.0' -func 'RealmCall1' -gas-fee 1000000ugnot -gas-wanted 2000000 -send '' -broadcast -chainid='tendermint_test' test1 stdout 'OK!' -gnokey maketx call -pkgpath 'gno.land/r/demo/bug97' -func 'RealmCall2' -gas-fee 1000000ugnot -gas-wanted 2000000 -send '' -broadcast -chainid='tendermint_test' test1 +gnokey maketx call -pkgpath 'gno.land/r/demo/bug97@v0.0.0' -func 'RealmCall2' -gas-fee 1000000ugnot -gas-wanted 2000000 -send '' -broadcast -chainid='tendermint_test' test1 stdout 'OK!' -gnokey maketx call -pkgpath 'gno.land/r/demo/bug97' -func 'RealmCall1' -gas-fee 1000000ugnot -gas-wanted 2000000 -send '' -broadcast -chainid='tendermint_test' test1 +gnokey maketx call -pkgpath 'gno.land/r/demo/bug97@v0.0.0' -func 'RealmCall1' -gas-fee 1000000ugnot -gas-wanted 2000000 -send '' -broadcast -chainid='tendermint_test' test1 stdout 'OK!' +-- gno.mod -- +module gno.land/r/demo/bug97 v0.0.0 + -- bug97.gno -- package bug97 diff --git a/gno.land/cmd/gnoland/testdata/pr-1112.txtar b/gno.land/cmd/gnoland/testdata/pr-1112.txtar index 128bb48e1aa..78223c44a20 100644 --- a/gno.land/cmd/gnoland/testdata/pr-1112.txtar +++ b/gno.land/cmd/gnoland/testdata/pr-1112.txtar @@ -3,11 +3,11 @@ gnoland start # add contract -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/mapindex -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! # call map -gnokey maketx call -pkgpath gno.land/r/demo/mapindex -func FindMapWithKey -args 3 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/mapindex@v1.0.0 -func FindMapWithKey -args 3 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '"three" string' @@ -16,8 +16,7 @@ stdout '"three" string' -- gno.mod -- -module gno.land/r/demo/mapindex - +module gno.land/r/demo/mapindex v1.0.0 -- realm.gno -- package mapindex diff --git a/gno.land/cmd/gnoland/testdata/realm-state.txtar b/gno.land/cmd/gnoland/testdata/realm-state.txtar new file mode 100644 index 00000000000..255304dd588 --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/realm-state.txtar @@ -0,0 +1,51 @@ +# test for realm state persistence (to be removed) + +## start a new node +gnoland start + +## add bar.gno package located in $WORK directory +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +stdout 'OK!' +stdout 'GAS WANTED: 2000000' +stdout 'GAS USED: [0-9]+' + +## execute Increment +gnokey maketx call -pkgpath gno.land/r/temp/counter@v1.0.0 -func Increment -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +## compare render +stdout '(1 int)' +stdout 'OK!' +stdout 'GAS WANTED: 2000000' +stdout 'GAS USED: [0-9]+' + +## execute Count +gnokey maketx call -pkgpath gno.land/r/temp/counter@v1.0.0 -func Count -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +## compare render +stdout '(1 int)' +stdout 'OK!' +stdout 'GAS WANTED: 2000000' +stdout 'GAS USED: [0-9]+' + +-- counter.gno -- +package counter + +var counter int + +func Increment() int { + counter += 1 + return counter +} + +func Decrement() int { + counter -= 1 + return counter +} + +func Count() int { + return counter +} + +-- gno.mod -- +module gno.land/r/temp/counter v1.0.0 diff --git a/gno.land/cmd/gnoland/testdata/run.txtar b/gno.land/cmd/gnoland/testdata/run.txtar index 7246a10a1a4..9166339f262 100644 --- a/gno.land/cmd/gnoland/testdata/run.txtar +++ b/gno.land/cmd/gnoland/testdata/run.txtar @@ -3,6 +3,15 @@ loadpkg gno.land/r/foobar/bar $WORK/bar ## start a new node gnoland start +## execute Render +gnokey maketx run -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 $WORK/script + +## compare render +stdout 'main: --- hello from foo ---' +stdout 'OK!' +stdout 'GAS WANTED: 200000' +stdout 'GAS USED: ' + ## execute Render gnokey maketx run -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 $WORK/script/script.gno @@ -12,6 +21,9 @@ stdout 'OK!' stdout 'GAS WANTED: 200000' stdout 'GAS USED: ' +-- bar/gno.mod -- +module gno.land/r/foobar/bar v0.0.0 + -- bar/bar.gno -- package bar @@ -19,9 +31,16 @@ func Render(path string) string { return "hello from foo" } +-- script/gno.mod -- +module gno.land/r/demo/script v0.0.0 + +require gno.land/r/foobar/bar v0.0.0 + -- script/script.gno -- package main + import "gno.land/r/foobar/bar" + func main() { println("main: ---", bar.Render(""), "---") } diff --git a/gno.land/cmd/gnoland/testdata/versioning.txtar b/gno.land/cmd/gnoland/testdata/versioning.txtar new file mode 100644 index 00000000000..1d3c860da3c --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/versioning.txtar @@ -0,0 +1,81 @@ +# test package versioning + +## start a new node +gnoland start + +## add `hello`(v1) package located in $WORK/helloworld/v1 +gnokey maketx addpkg -pkgdir $WORK/helloworld/v1 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +## add `hello`(v2) package located in $WORK/helloworld/v2 +gnokey maketx addpkg -pkgdir $WORK/helloworld/v2 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +## add `foo` realm; imports pkg `hello` v1 +gnokey maketx addpkg -pkgdir $WORK/foo -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +## add `bar` realm; imports pkg `hello` v2 +gnokey maketx addpkg -pkgdir $WORK/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +## execute Render from `foo` realm +gnokey maketx call -pkgpath gno.land/r/temp/foo@v0.0.1 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 + +## compare render +stdout '("hello from v1" string)' +stdout 'OK!' +stdout 'GAS WANTED: 2000000' +stdout 'GAS USED: [0-9]+' + +## execute Render from `bar` realm +gnokey maketx call -pkgpath gno.land/r/temp/bar@v0.0.1 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 + +## compare render +stdout '("hello from v2" string)' +stdout 'OK!' +stdout 'GAS WANTED: 2000000' +stdout 'GAS USED: [0-9]+' + +-- helloworld/v1/hello.gno -- +package hello + +func SayHello() string { + return "hello from v1" +} + +-- helloworld/v1/gno.mod -- +module gno.land/p/helloworld/hello v1.0.0 + +-- helloworld/v2/hello.gno -- +package hello + +func SayHello() string { + return "hello from v2" +} + +-- helloworld/v2/gno.mod -- +module gno.land/p/helloworld/hello v2.0.0 + +-- foo/foo.gno -- +package foo + +import "gno.land/p/helloworld/hello" + +func Render(path string) string { + return hello.SayHello() +} + +-- foo/gno.mod -- +module gno.land/r/temp/foo v0.0.1 + +require gno.land/p/helloworld/hello v1.0.0 + +-- bar/bar.gno -- +package bar + +import "gno.land/p/helloworld/hello" + +func Render(path string) string { + return hello.SayHello() +} + +-- bar/gno.mod -- +module gno.land/r/temp/bar v0.0.1 + +require gno.land/p/helloworld/hello v2.0.0 diff --git a/gno.land/cmd/gnoland/testdata/wugnot.txtar b/gno.land/cmd/gnoland/testdata/wugnot.txtar index 1640909fdb9..b0d65bb006c 100644 --- a/gno.land/cmd/gnoland/testdata/wugnot.txtar +++ b/gno.land/cmd/gnoland/testdata/wugnot.txtar @@ -2,44 +2,44 @@ loadpkg gno.land/r/demo/wugnot gnoland start -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '# wrapped GNOT \(\$wugnot\)' stdout 'Decimals..: 0' stdout 'Total supply..: 0' stdout 'Known accounts..: 0' stdout 'OK!' -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout 'OK!' -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout 'Total supply..: 12345678' stdout 'Known accounts..: 1' stdout 'OK!' # XXX: use test2 instead (depends on https://github.com/gnolang/gno/issues/1269#issuecomment-1806386069) -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout 'OK!' -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout 'Total supply..: 24691356' stdout 'Known accounts..: 1' # should be 2 once we can use test2 stdout 'OK!' # XXX: replace hardcoded address with test3 -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Transfer -gas-fee 1000000ugnot -gas-wanted 2000000 -args 'g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq' -args '10000000' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Transfer -gas-fee 1000000ugnot -gas-wanted 2000000 -args 'g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq' -args '10000000' -broadcast -chainid=tendermint_test test1 stdout 'OK!' -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout 'Total supply..: 24691356' stdout 'Known accounts..: 2' # should be 3 once we can use test2 stdout 'OK!' # XXX: use test3 instead (depends on https://github.com/gnolang/gno/issues/1269#issuecomment-1806386069) -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Withdraw -args 10000000 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Withdraw -args 10000000 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout 'OK!' -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot@v0.0.1 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout 'Total supply..: 14691356' stdout 'Known accounts..: 2' # should be 3 once we can use test2 stdout 'OK!' diff --git a/gno.land/genesis/genesis_txs.jsonl b/gno.land/genesis/genesis_txs.jsonl index 3baf9d3231b..359aebb2dd5 100644 --- a/gno.land/genesis/genesis_txs.jsonl +++ b/gno.land/genesis/genesis_txs.jsonl @@ -1,17 +1,17 @@ -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s:1\ng13sm84nuqed3fuank8huh7x9mupgw22uft3lcl8:1\ng1m6732pkrngu9vrt0g7056lvr9kcqc4mv83xl5q:1\ng1wg88rhzlwxjd2z4j5de5v5xq30dcf6rjq3dhsj:1\ng18pmaskasz7mxj6rmgrl3al58xu45a7w0l5nmc0:1\ng19wwhkmqlns70604ksp6rkuuu42qhtvyh05lffz:1\ng187982000zsc493znqt828s90cmp6hcp2erhu6m:1\ng1ndpsnrspdnauckytvkfv8s823t3gmpqmtky8pl:1\ng16ja66d65emkr0zxd2tu7xjvm7utthyhpej0037:1\ng1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5:1\ng1trkzq75ntamsnw9xnrav2v7gy2lt5g6p29yhdr:1\ng1rrf8s5mrmu00sx04fzfsvc399fklpeg2x0a7mz:1\ng19p5ntfvpt4lwq4jqsmnxsnelhf3tff9scy3w8w:1\ng1tue8l73d6rq4vhqdsp2sr3zhuzpure3k2rnwpz:1\ng14hhsss4ngx5kq77je5g0tl4vftg8qp45ceadk3:1\ng1768hvkh7anhd40ch4h7jdh6j3mpcs7hrat4gl0:1\ng15fa8kyjhu88t9dr8zzua8fwdvkngv5n8yqsm0n:1\ng1xhccdjcscuhgmt3quww6qdy3j3czqt3urc2eac:1\ng1z629z04f85k4t5gnkk5egpxw9tqxeec435esap:1\ng1pfldkplz9puq0v82lu9vqcve9nwrxuq9qe5ttv:1\ng152pn0g5qfgxr7yx8zlwjq48hytkafd8x7egsfv:1\ng1cf2ye686ke38vjyqakreprljum4xu6rwf5jskq:1\ng1c5shztyaj4gjrc5zlwmh9xhex5w7l4asffs2w6:1\ng1lhpx2ktk0ha3qw42raxq4m24a4c4xqxyrgv54q:1\ng1026p54q0j902059sm2zsv37krf0ghcl7gmhyv7:1\ng1n4yvwnv77frq2ccuw27dmtjkd7u4p4jg0pgm7k:1\ng13m7f2e6r3lh3ykxupacdt9sem2tlvmaamwjhll:1\ng19uxluuecjlsqvwmwu8sp6pxaaqfhk972q975xd:1\ng1j80fpcsumfkxypvydvtwtz3j4sdwr8c2u0lr64:1\ng1tjdpptuk9eysq6z38nscqyycr998xjyx3w8jvw:1\ng19t3n89slfemgd3mwuat4lajwcp0yxrkadgeg7a:1\ng1yqndt8xx92l9h494jfruz2w79swzjes3n4wqjc:1\ng13278z0a5ufeg80ffqxpda9dlp599t7ekregcy6:1\ng1ht236wjd83x96uqwh9rh3fq6pylyn78mtwq9v6:1\ng1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9:1\ng1wwppuzdns5u6c6jqpkzua24zh6ppsus6399cea:1\ng1k8pjnguyu36pkc8hy0ufzgpzfmj2jl78la7ek3:1\ng1e8umkzumtxgs8399lw0us4rclea3xl5gxy9spp:1\ng14qekdkj2nmmwea4ufg9n002a3pud23y8k7ugs5:1\ng19w2488ntfgpduzqq3sk4j5x387zynwknqdvjqf:1\ng1495y3z7zrej4rendysnw5kaeu4g3d7x7w0734g:1\ng1hygx8ga9qakhkczyrzs9drm8j8tu4qds9y5e3r:1\ng1f977l6wxdh3qu60kzl75vx2wmzswu68l03r8su:1\ng1644qje5rx6jsdqfkzmgnfcegx4dxkjh6rwqd69:1\ng1mzjajymvmtksdwh3wkrndwj6zls2awl9q83dh6:1\ng1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq:10\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa:10\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t:5\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"S8iMMzlOMK8dmox78R9Z8+pSsS8YaTCXrIcaHDpiOgkOy7gqoQJ0oftM0zf8zAz4xpezK8Lzg8Q0fCdXJxV76w=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1thlf3yct7n7ex70k0p62user0kn6mj6d3s0cg3\ng1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"njczE6xYdp01+CaUU/8/v0YC/NuZD06+qLind+ZZEEMNaRe/4Ln+4z7dG6HYlaWUMsyI1KCoB6NIehoE0PZ44Q=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s\ng13sm84nuqed3fuank8huh7x9mupgw22uft3lcl8\ng1m6732pkrngu9vrt0g7056lvr9kcqc4mv83xl5q\ng1wg88rhzlwxjd2z4j5de5v5xq30dcf6rjq3dhsj\ng18pmaskasz7mxj6rmgrl3al58xu45a7w0l5nmc0\ng19wwhkmqlns70604ksp6rkuuu42qhtvyh05lffz\ng187982000zsc493znqt828s90cmp6hcp2erhu6m\ng1ndpsnrspdnauckytvkfv8s823t3gmpqmtky8pl\ng16ja66d65emkr0zxd2tu7xjvm7utthyhpej0037\ng1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5\ng1trkzq75ntamsnw9xnrav2v7gy2lt5g6p29yhdr\ng1rrf8s5mrmu00sx04fzfsvc399fklpeg2x0a7mz\ng19p5ntfvpt4lwq4jqsmnxsnelhf3tff9scy3w8w\ng1tue8l73d6rq4vhqdsp2sr3zhuzpure3k2rnwpz\ng14hhsss4ngx5kq77je5g0tl4vftg8qp45ceadk3\ng1768hvkh7anhd40ch4h7jdh6j3mpcs7hrat4gl0\ng15fa8kyjhu88t9dr8zzua8fwdvkngv5n8yqsm0n\ng1xhccdjcscuhgmt3quww6qdy3j3czqt3urc2eac\ng1z629z04f85k4t5gnkk5egpxw9tqxeec435esap\ng1pfldkplz9puq0v82lu9vqcve9nwrxuq9qe5ttv\ng152pn0g5qfgxr7yx8zlwjq48hytkafd8x7egsfv\ng1cf2ye686ke38vjyqakreprljum4xu6rwf5jskq\ng1c5shztyaj4gjrc5zlwmh9xhex5w7l4asffs2w6\ng1lhpx2ktk0ha3qw42raxq4m24a4c4xqxyrgv54q\ng1026p54q0j902059sm2zsv37krf0ghcl7gmhyv7\ng1n4yvwnv77frq2ccuw27dmtjkd7u4p4jg0pgm7k\ng13m7f2e6r3lh3ykxupacdt9sem2tlvmaamwjhll\ng19uxluuecjlsqvwmwu8sp6pxaaqfhk972q975xd\ng1j80fpcsumfkxypvydvtwtz3j4sdwr8c2u0lr64\ng1tjdpptuk9eysq6z38nscqyycr998xjyx3w8jvw\ng19t3n89slfemgd3mwuat4lajwcp0yxrkadgeg7a\ng1yqndt8xx92l9h494jfruz2w79swzjes3n4wqjc\ng13278z0a5ufeg80ffqxpda9dlp599t7ekregcy6\ng1ht236wjd83x96uqwh9rh3fq6pylyn78mtwq9v6\ng1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9\ng1wwppuzdns5u6c6jqpkzua24zh6ppsus6399cea\ng1k8pjnguyu36pkc8hy0ufzgpzfmj2jl78la7ek3\ng1e8umkzumtxgs8399lw0us4rclea3xl5gxy9spp\ng14qekdkj2nmmwea4ufg9n002a3pud23y8k7ugs5\ng19w2488ntfgpduzqq3sk4j5x387zynwknqdvjqf\ng1495y3z7zrej4rendysnw5kaeu4g3d7x7w0734g\ng1hygx8ga9qakhkczyrzs9drm8j8tu4qds9y5e3r\ng1f977l6wxdh3qu60kzl75vx2wmzswu68l03r8su\ng1644qje5rx6jsdqfkzmgnfcegx4dxkjh6rwqd69\ng1mzjajymvmtksdwh3wkrndwj6zls2awl9q83dh6\ng1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t\n"]}],"fee":{"gas_wanted":"4000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"7AmlhZhsVkxCUl0bbpvpPMnIKihwtG7A5IFR6Tg4xStWLgaUr05XmWRKlO2xjstTtwbVKQT5mFL4h5wyX4SQzw=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","func":"Register","args":["","administrator","g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"AqCqe0cS55Ym7/BvPDoCDyPP5q8284gecVQ2PMOlq/4lJpO9Q18SOWKI15dMEBY1pT0AYyhCeTirlsM1I3Y4Cg=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","func":"Register","args":["","zo_oma","Love is the encryption key\u003c3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A6yg5/iiktruezVw5vZJwLlGwyrvw8RlqOToTRMWXkE2"},"signature":"GGp+bVL2eEvKecPqgcULSABYOSnSMnJzfIsR8ZIRER1GGX/fOiCReX4WKMrGLVROJVfbLQkDRwvhS4TLHlSoSQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","func":"Register","args":["","manfred","https://github.com/moul"]}],"fee":{"gas_wanted":"2000000","gas_fee":"2000000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"9CWeNbKx+hEL+RdHplAVAFntcrAVx5mK9tMqoywuHVoreH844n3yOxddQrGfBk6T2tMBmNWakERRqWZfS+bYAQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","func":"Register","args":["","piupiu","@piux2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"Ar68lqbU2YC63fbMcYUtJhYO3/66APM/EqF7m0nUjGyz"},"signature":"pTUpP0d/XlfVe3TH1hlaoLhKadzIKG1gtQ/Ueuat72p+659RWRea58Z0mk6GgPE/EeTbhMEY45zufevBdGJVoQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5","send":"","pkg_path":"gno.land/r/demo/users","func":"Register","args":["g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","anarcher","https://twitter.com/anarcher"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AjpLbKdQeH+yB/1OCB148l5GlRRrXma71hdA8EES3H7f"},"signature":"pf5xm8oWIQIOEwSGw4icPmynLXb1P1HxKfjeh8UStU1mlIBPKa7yppeIMPpAflC0o2zjFR7Axe7CimAebm3BHg=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g15gdm49ktawvkrl88jadqpucng37yxutucuwaef","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","func":"Register","args":["","ideamour","\u003c3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AhClx4AsDuX3DNCPxhDwWnrfd4MIZmxJE4vt47ClVvT2"},"signature":"IQe64af878k6HjLDqIJeg27GXAVF6xS+96cDe2jMlxNV6+8sOcuUctp0GiWVnYfN4tpthC6d4WhBo+VlpHqkbg=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateBoard","args":["testboard"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"vzlSxEFh5jOkaSdv3rsV91v/OJKEF2qSuoCpri1u5tRWq62T7xr3KHRCF5qFnn4aQX/yE8g8f/Y//WPOCUGhJw=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Hello World","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm \nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n## Starting the `gnoland` node node/validator.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### build gnoland.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake \n```\n\n### add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mnemonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### start gnoland validator node.\n\n```bash\n./build/gnoland\n```\n\n(This can be reset with `make reset`).\n\n### start gnoland web server (optional).\n\n```bash\ngo run ./gnoland/website\n```\n\n## Signing and broadcasting transactions.\n\n### publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100ugnot --gas-fee 1ugnot --gas-wanted 2000000 \u003e addpkg.avl.unsigned.txt\n./build/gnokey query \"auth/accounts/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\"\n./build/gnokey sign test1 --txpath addpkg.avl.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 0 \u003e addpkg.avl.signed.txt\n./build/gnokey broadcast addpkg.avl.signed.txt --remote %%REMOTE%%\n```\n\n### publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100ugnot --gas-fee 1ugnot --gas-wanted 300000000 \u003e addpkg.boards.unsigned.txt\n./build/gnokey sign test1 --txpath addpkg.boards.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 1 \u003e addpkg.boards.signed.txt\n./build/gnokey broadcast addpkg.boards.signed.txt --remote %%REMOTE%%\n```\n\n### create a board with a smart contract call.\n\n```bash\n./build/gnokey maketx call test1 --pkgpath \"gno.land/r/demo/boards\" --func CreateBoard --args \"testboard\" --gas-fee 1ugnot --gas-wanted 2000000 \u003e createboard.unsigned.txt\n./build/gnokey sign test1 --txpath createboard.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 2 \u003e createboard.signed.txt\n./build/gnokey broadcast createboard.signed.txt --remote %%REMOTE%%\n```\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"testboard\\\")\"\n```\n\n### create a post of a board with a smart contract call.\n\n```bash\n./build/gnokey maketx call test1 --pkgpath \"gno.land/r/demo/boards\" --func CreatePost --args 1 --args \"Hello World\" --args#file \"./examples/gno.land/r/demo/boards/README.md\" --gas-fee 1ugnot --gas-wanted 2000000 \u003e createpost.unsigned.txt\n./build/gnokey sign test1 --txpath createpost.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 3 \u003e createpost.signed.txt\n./build/gnokey broadcast createpost.signed.txt --remote %%REMOTE%%\n```\n\n### create a comment to a post.\n\n```bash\n./build/gnokey maketx call test1 --pkgpath \"gno.land/r/demo/boards\" --func CreateReply --args 1 --args 1 --args \"A comment\" --gas-fee 1ugnot --gas-wanted 2000000 \u003e createcomment.unsigned.txt\n./build/gnokey sign test1 --txpath createcomment.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 4 \u003e createcomment.signed.txt\n./build/gnokey broadcast createcomment.signed.txt --remote %%REMOTE%%\n```\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ntestboard/1\"\n```\n\n### render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:testboard` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ntestboard\"\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"V43B1waFxhzheW9TfmCpjLdrC4dC1yjUGES5y3J6QsNar6hRpNz4G1thzWmWK7xXhg8u1PCIpxLxGczKQYhuPw=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","NFT example","NFT's are all the rage these days, for various reasons.\n\nI read over EIP-721 which appears to be the de-facto NFT standard on Ethereum. Then, made a sample implementation of EIP-721 (let's here called GRC-721). The implementation isn't complete, but it demonstrates the main functionality.\n\n - [EIP-721](https://eips.ethereum.org/EIPS/eip-721)\n - [gno.land/r/demo/nft/nft.gno](https://gno.land/r/demo/nft/nft.gno)\n - [zrealm_nft3.gno test](https://github.com/gnolang/gno/blob/master/examples/gno.land/r/demo/nft/z_3_filetest.gno)\n\nIn short, this demonstrates how to implement Ethereum contract interfaces in Gno.land; by using only standard Go language features.\n\nPlease leave a comment ([guide](https://gno.land/r/demo/boards:testboard/1)).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"ZXfrTiHxPFQL8uSm+Tv7WXIHPMca9okhm94RAlC6YgNbB1VHQYYpoP4w+cnL3YskVzGrOZxensXa9CAZ+cNNeg=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Simple echo example with coins","This is a simple test realm contract that demonstrates how to use the banker.\n\nSee [gno.land/r/demo/banktest/banktest.gno](/r/banktest/banktest.gno) to see the original contract code.\n\nThis article will go through each line to explain how it works.\n\n```go\npackage banktest\n```\n\nThis package is locally named \"banktest\" (could be anything).\n\n```go\nimport (\n\t\"std\"\n)\n```\n\nThe \"std\" package is defined by the gno code in stdlibs/std/. \u003c/br\u003e\nSelf explanatory; and you'll see more usage from std later.\n\n```go\ntype activity struct {\n\tcaller std.Address\n\tsent std.Coins\n\treturned std.Coins\n\ttime std.Time\n}\n\nfunc (act *activity) String() string {\n\treturn act.caller.String() + \" \" +\n\t\tact.sent.String() + \" sent, \" +\n\t\tact.returned.String() + \" returned, at \" +\n\t\tstd.FormatTimestamp(act.time, \"2006-01-02 3:04pm MST\")\n}\n\nvar latest [10]*activity\n```\n\nThis is just maintaining a list of recent activity to this contract.\nNotice that the \"latest\" variable is defined \"globally\" within\nthe context of the realm with path \"gno.land/r/demo/banktest\".\n\nThis means that calls to functions defined within this package\nare encapsulated within this \"data realm\", where the data is \nmutated based on transactions that can potentially cross many\nrealm and non-realm packge boundaries (in the call stack).\n\n```go\n// Deposit will take the coins (to the realm's pkgaddr) or return them to user.\nfunc Deposit(returnDenom string, returnAmount int64) string {\n\tstd.AssertOriginCall()\n\tcaller := std.GetOrigCaller()\n\tsend := std.Coins{{returnDenom, returnAmount}}\n```\n\nThis is the beginning of the definition of the contract function named\n\"Deposit\". `std.AssertOriginCall() asserts that this function was called by a\ngno transactional Message. The caller is the user who signed off on this\ntransactional message. Send is the amount of deposit sent along with this\nmessage.\n\n```go\n\t// record activity\n\tact := \u0026activity{\n\t\tcaller: caller,\n\t\tsent: std.GetOrigSend(),\n\t\treturned: send,\n\t\ttime: std.GetTimestamp(),\n\t}\n\tfor i := len(latest) - 2; i \u003e= 0; i-- {\n\t\tlatest[i+1] = latest[i] // shift by +1.\n\t}\n\tlatest[0] = act\n```\n\nUpdating the \"latest\" array for viewing at gno.land/r/demo/banktest: (w/ trailing colon).\n\n```go\n\t// return if any.\n\tif returnAmount \u003e 0 {\n```\n\nIf the user requested the return of coins...\n\n```go\n\t\tbanker := std.GetBanker(std.BankerTypeOrigSend)\n```\n\nuse a std.Banker instance to return any deposited coins to the original sender.\n\n```go\n\t\tpkgaddr := std.GetOrigPkgAddr()\n\t\t// TODO: use std.Coins constructors, this isn't generally safe.\n\t\tbanker.SendCoins(pkgaddr, caller, send)\n\t\treturn \"returned!\"\n```\n\nNotice that each realm package has an associated Cosmos address.\n\n\nFinally, the results are rendered via an ABCI query call when you visit [/r/banktest:](/r/banktest:).\n\n```go\nfunc Render(path string) string {\n\t// get realm coins.\n\tbanker := std.GetBanker(std.BankerTypeReadonly)\n\tcoins := banker.GetCoins(std.GetOrigPkgAddr())\n\n\t// render\n\tres := \"\"\n\tres += \"## recent activity\\n\"\n\tres += \"\\n\"\n\tfor _, act := range latest {\n\t\tif act == nil {\n\t\t\tbreak\n\t\t}\n\t\tres += \" * \" + act.String() + \"\\n\"\n\t}\n\tres += \"\\n\"\n\tres += \"## total deposits\\n\"\n\tres += coins.String()\n\treturn res\n}\n```\n\nYou can call this contract yourself, by vistiing [/r/banktest](/r/banktest) and the [quickstart guide](/r/boards:testboard/4).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"iZX/llZlNTdZMLv1goCTgK2bWqzT8enlTq56wMTCpVxJGA0BTvuEM5Nnt9vrnlG6Taqj2GuTrmEnJBkDFTmt9g=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","TASK: Describe in your words","Describe in an essay (250+ words), on your favorite medium, why you are interested in gno.land and gnolang.\n\nReply here with a URL link to your written piece as a comment, for rewards.\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"4HBNtrta8HdeHj4JTN56PBTRK8GOe31NMRRXDiyYtjozuyRdWfOGEsGjGgHWcoBUJq6DepBgD4FetdqfhZ6TNQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Getting Started","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm\nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n\n\n## Build `gnokey`, create your account, and interact with Gno.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### Build `gnokey`.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake\n```\n\n### Generate a seed/mnemonic code.\n\n```bash\n./build/gnokey generate\n```\n\nNOTE: You can generate 24 words with any good bip39 generator.\n\n### Create a new account using your mnemonic.\n\n```bash\n./build/gnokey add KEYNAME --recover\n```\n\nNOTE: `KEYNAME` is your key identifier, and should be changed.\n\n### Verify that you can see your account locally.\n\n```bash\n./build/gnokey list\n```\n\n## Interact with the blockchain:\n\n### Get your current balance, account number, and sequence number.\n\n```bash\n./build/gnokey query auth/accounts/ACCOUNT_ADDR --remote %%REMOTE%%\n```\n\nNOTE: you can retrieve your `ACCOUNT_ADDR` with `./build/gnokey list`.\n\n### Acquire testnet tokens using the official faucet.\n\nGo to https://gno.land/faucet\n\n### Create a board with a smart contract call.\n\nNOTE: `BOARDNAME` will be the slug of the board, and should be changed.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateBoard\" --args \"BOARDNAME\" --gas-fee \"1000000ugnot\" --gas-wanted \"2000000\" --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateBoard\n\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"BOARDNAME\\\")\" --remote %%REMOTE%%\n```\n\n### Create a post of a board with a smart contract call.\n\nNOTE: If a board was created successfully, your SEQUENCE_NUMBER would have increased.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateThread\" --args BOARD_ID --args \"Hello gno.land\" --args\\#file \"./examples/gno.land/r/demo/boards/example_post.md\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateThread\n\n### Create a comment to a post.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateReply\" --args \"BOARD_ID\" --args \"1\" --args \"1\" --args \"Nice to meet you too.\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\nBOARDNAME/1\" --remote %%REMOTE%%\n```\n\n### Render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:gnolang` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ngnolang\"\n```\n\n## Starting a local `gnoland` node:\n\n### Add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mneonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### Start `gnoland` node.\n\n```bash\n./build/gnoland\n```\n\nNOTE: This can be reset with `make reset`\n\n### Publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n\n### Publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 300000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post1","First post","Lorem Ipsum","2022-05-20T13:17:22Z","","tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum","2022-05-20T13:17:23Z","","tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} \ No newline at end of file +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Invite","args":["g1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s:1\ng13sm84nuqed3fuank8huh7x9mupgw22uft3lcl8:1\ng1m6732pkrngu9vrt0g7056lvr9kcqc4mv83xl5q:1\ng1wg88rhzlwxjd2z4j5de5v5xq30dcf6rjq3dhsj:1\ng18pmaskasz7mxj6rmgrl3al58xu45a7w0l5nmc0:1\ng19wwhkmqlns70604ksp6rkuuu42qhtvyh05lffz:1\ng187982000zsc493znqt828s90cmp6hcp2erhu6m:1\ng1ndpsnrspdnauckytvkfv8s823t3gmpqmtky8pl:1\ng16ja66d65emkr0zxd2tu7xjvm7utthyhpej0037:1\ng1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5:1\ng1trkzq75ntamsnw9xnrav2v7gy2lt5g6p29yhdr:1\ng1rrf8s5mrmu00sx04fzfsvc399fklpeg2x0a7mz:1\ng19p5ntfvpt4lwq4jqsmnxsnelhf3tff9scy3w8w:1\ng1tue8l73d6rq4vhqdsp2sr3zhuzpure3k2rnwpz:1\ng14hhsss4ngx5kq77je5g0tl4vftg8qp45ceadk3:1\ng1768hvkh7anhd40ch4h7jdh6j3mpcs7hrat4gl0:1\ng15fa8kyjhu88t9dr8zzua8fwdvkngv5n8yqsm0n:1\ng1xhccdjcscuhgmt3quww6qdy3j3czqt3urc2eac:1\ng1z629z04f85k4t5gnkk5egpxw9tqxeec435esap:1\ng1pfldkplz9puq0v82lu9vqcve9nwrxuq9qe5ttv:1\ng152pn0g5qfgxr7yx8zlwjq48hytkafd8x7egsfv:1\ng1cf2ye686ke38vjyqakreprljum4xu6rwf5jskq:1\ng1c5shztyaj4gjrc5zlwmh9xhex5w7l4asffs2w6:1\ng1lhpx2ktk0ha3qw42raxq4m24a4c4xqxyrgv54q:1\ng1026p54q0j902059sm2zsv37krf0ghcl7gmhyv7:1\ng1n4yvwnv77frq2ccuw27dmtjkd7u4p4jg0pgm7k:1\ng13m7f2e6r3lh3ykxupacdt9sem2tlvmaamwjhll:1\ng19uxluuecjlsqvwmwu8sp6pxaaqfhk972q975xd:1\ng1j80fpcsumfkxypvydvtwtz3j4sdwr8c2u0lr64:1\ng1tjdpptuk9eysq6z38nscqyycr998xjyx3w8jvw:1\ng19t3n89slfemgd3mwuat4lajwcp0yxrkadgeg7a:1\ng1yqndt8xx92l9h494jfruz2w79swzjes3n4wqjc:1\ng13278z0a5ufeg80ffqxpda9dlp599t7ekregcy6:1\ng1ht236wjd83x96uqwh9rh3fq6pylyn78mtwq9v6:1\ng1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9:1\ng1wwppuzdns5u6c6jqpkzua24zh6ppsus6399cea:1\ng1k8pjnguyu36pkc8hy0ufzgpzfmj2jl78la7ek3:1\ng1e8umkzumtxgs8399lw0us4rclea3xl5gxy9spp:1\ng14qekdkj2nmmwea4ufg9n002a3pud23y8k7ugs5:1\ng19w2488ntfgpduzqq3sk4j5x387zynwknqdvjqf:1\ng1495y3z7zrej4rendysnw5kaeu4g3d7x7w0734g:1\ng1hygx8ga9qakhkczyrzs9drm8j8tu4qds9y5e3r:1\ng1f977l6wxdh3qu60kzl75vx2wmzswu68l03r8su:1\ng1644qje5rx6jsdqfkzmgnfcegx4dxkjh6rwqd69:1\ng1mzjajymvmtksdwh3wkrndwj6zls2awl9q83dh6:1\ng1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq:10\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa:10\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t:5\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"S8iMMzlOMK8dmox78R9Z8+pSsS8YaTCXrIcaHDpiOgkOy7gqoQJ0oftM0zf8zAz4xpezK8Lzg8Q0fCdXJxV76w=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Invite","args":["g1thlf3yct7n7ex70k0p62user0kn6mj6d3s0cg3\ng1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"njczE6xYdp01+CaUU/8/v0YC/NuZD06+qLind+ZZEEMNaRe/4Ln+4z7dG6HYlaWUMsyI1KCoB6NIehoE0PZ44Q=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Invite","args":["g1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s\ng13sm84nuqed3fuank8huh7x9mupgw22uft3lcl8\ng1m6732pkrngu9vrt0g7056lvr9kcqc4mv83xl5q\ng1wg88rhzlwxjd2z4j5de5v5xq30dcf6rjq3dhsj\ng18pmaskasz7mxj6rmgrl3al58xu45a7w0l5nmc0\ng19wwhkmqlns70604ksp6rkuuu42qhtvyh05lffz\ng187982000zsc493znqt828s90cmp6hcp2erhu6m\ng1ndpsnrspdnauckytvkfv8s823t3gmpqmtky8pl\ng16ja66d65emkr0zxd2tu7xjvm7utthyhpej0037\ng1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5\ng1trkzq75ntamsnw9xnrav2v7gy2lt5g6p29yhdr\ng1rrf8s5mrmu00sx04fzfsvc399fklpeg2x0a7mz\ng19p5ntfvpt4lwq4jqsmnxsnelhf3tff9scy3w8w\ng1tue8l73d6rq4vhqdsp2sr3zhuzpure3k2rnwpz\ng14hhsss4ngx5kq77je5g0tl4vftg8qp45ceadk3\ng1768hvkh7anhd40ch4h7jdh6j3mpcs7hrat4gl0\ng15fa8kyjhu88t9dr8zzua8fwdvkngv5n8yqsm0n\ng1xhccdjcscuhgmt3quww6qdy3j3czqt3urc2eac\ng1z629z04f85k4t5gnkk5egpxw9tqxeec435esap\ng1pfldkplz9puq0v82lu9vqcve9nwrxuq9qe5ttv\ng152pn0g5qfgxr7yx8zlwjq48hytkafd8x7egsfv\ng1cf2ye686ke38vjyqakreprljum4xu6rwf5jskq\ng1c5shztyaj4gjrc5zlwmh9xhex5w7l4asffs2w6\ng1lhpx2ktk0ha3qw42raxq4m24a4c4xqxyrgv54q\ng1026p54q0j902059sm2zsv37krf0ghcl7gmhyv7\ng1n4yvwnv77frq2ccuw27dmtjkd7u4p4jg0pgm7k\ng13m7f2e6r3lh3ykxupacdt9sem2tlvmaamwjhll\ng19uxluuecjlsqvwmwu8sp6pxaaqfhk972q975xd\ng1j80fpcsumfkxypvydvtwtz3j4sdwr8c2u0lr64\ng1tjdpptuk9eysq6z38nscqyycr998xjyx3w8jvw\ng19t3n89slfemgd3mwuat4lajwcp0yxrkadgeg7a\ng1yqndt8xx92l9h494jfruz2w79swzjes3n4wqjc\ng13278z0a5ufeg80ffqxpda9dlp599t7ekregcy6\ng1ht236wjd83x96uqwh9rh3fq6pylyn78mtwq9v6\ng1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9\ng1wwppuzdns5u6c6jqpkzua24zh6ppsus6399cea\ng1k8pjnguyu36pkc8hy0ufzgpzfmj2jl78la7ek3\ng1e8umkzumtxgs8399lw0us4rclea3xl5gxy9spp\ng14qekdkj2nmmwea4ufg9n002a3pud23y8k7ugs5\ng19w2488ntfgpduzqq3sk4j5x387zynwknqdvjqf\ng1495y3z7zrej4rendysnw5kaeu4g3d7x7w0734g\ng1hygx8ga9qakhkczyrzs9drm8j8tu4qds9y5e3r\ng1f977l6wxdh3qu60kzl75vx2wmzswu68l03r8su\ng1644qje5rx6jsdqfkzmgnfcegx4dxkjh6rwqd69\ng1mzjajymvmtksdwh3wkrndwj6zls2awl9q83dh6\ng1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t\n"]}],"fee":{"gas_wanted":"4000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"7AmlhZhsVkxCUl0bbpvpPMnIKihwtG7A5IFR6Tg4xStWLgaUr05XmWRKlO2xjstTtwbVKQT5mFL4h5wyX4SQzw=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Register","args":["","administrator","g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"AqCqe0cS55Ym7/BvPDoCDyPP5q8284gecVQ2PMOlq/4lJpO9Q18SOWKI15dMEBY1pT0AYyhCeTirlsM1I3Y4Cg=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Register","args":["","zo_oma","Love is the encryption key\u003c3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A6yg5/iiktruezVw5vZJwLlGwyrvw8RlqOToTRMWXkE2"},"signature":"GGp+bVL2eEvKecPqgcULSABYOSnSMnJzfIsR8ZIRER1GGX/fOiCReX4WKMrGLVROJVfbLQkDRwvhS4TLHlSoSQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Register","args":["","manfred","https://github.com/moul"]}],"fee":{"gas_wanted":"2000000","gas_fee":"2000000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"9CWeNbKx+hEL+RdHplAVAFntcrAVx5mK9tMqoywuHVoreH844n3yOxddQrGfBk6T2tMBmNWakERRqWZfS+bYAQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Register","args":["","piupiu","@piux2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"Ar68lqbU2YC63fbMcYUtJhYO3/66APM/EqF7m0nUjGyz"},"signature":"pTUpP0d/XlfVe3TH1hlaoLhKadzIKG1gtQ/Ueuat72p+659RWRea58Z0mk6GgPE/EeTbhMEY45zufevBdGJVoQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5","send":"","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Register","args":["g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","anarcher","https://twitter.com/anarcher"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AjpLbKdQeH+yB/1OCB148l5GlRRrXma71hdA8EES3H7f"},"signature":"pf5xm8oWIQIOEwSGw4icPmynLXb1P1HxKfjeh8UStU1mlIBPKa7yppeIMPpAflC0o2zjFR7Axe7CimAebm3BHg=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g15gdm49ktawvkrl88jadqpucng37yxutucuwaef","send":"2000000000ugnot","pkg_path":"gno.land/r/demo/users","pkg_version":"v0.0.1","func":"Register","args":["","ideamour","\u003c3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AhClx4AsDuX3DNCPxhDwWnrfd4MIZmxJE4vt47ClVvT2"},"signature":"IQe64af878k6HjLDqIJeg27GXAVF6xS+96cDe2jMlxNV6+8sOcuUctp0GiWVnYfN4tpthC6d4WhBo+VlpHqkbg=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","pkg_version":"v0.0.1","func":"CreateBoard","args":["testboard"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"vzlSxEFh5jOkaSdv3rsV91v/OJKEF2qSuoCpri1u5tRWq62T7xr3KHRCF5qFnn4aQX/yE8g8f/Y//WPOCUGhJw=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","pkg_version":"v0.0.1","func":"CreateThread","args":["1","Hello World","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm \nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n## Starting the `gnoland` node node/validator.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### build gnoland.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake \n```\n\n### add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mnemonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### start gnoland validator node.\n\n```bash\n./build/gnoland\n```\n\n(This can be reset with `make reset`).\n\n### start gnoland web server (optional).\n\n```bash\ngo run ./gnoland/website\n```\n\n## Signing and broadcasting transactions.\n\n### publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100ugnot --gas-fee 1ugnot --gas-wanted 2000000 \u003e addpkg.avl.unsigned.txt\n./build/gnokey query \"auth/accounts/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\"\n./build/gnokey sign test1 --txpath addpkg.avl.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 0 \u003e addpkg.avl.signed.txt\n./build/gnokey broadcast addpkg.avl.signed.txt --remote %%REMOTE%%\n```\n\n### publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100ugnot --gas-fee 1ugnot --gas-wanted 300000000 \u003e addpkg.boards.unsigned.txt\n./build/gnokey sign test1 --txpath addpkg.boards.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 1 \u003e addpkg.boards.signed.txt\n./build/gnokey broadcast addpkg.boards.signed.txt --remote %%REMOTE%%\n```\n\n### create a board with a smart contract call.\n\n```bash\n./build/gnokey maketx call test1 --pkgpath \"gno.land/r/demo/boards\" --func CreateBoard --args \"testboard\" --gas-fee 1ugnot --gas-wanted 2000000 \u003e createboard.unsigned.txt\n./build/gnokey sign test1 --txpath createboard.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 2 \u003e createboard.signed.txt\n./build/gnokey broadcast createboard.signed.txt --remote %%REMOTE%%\n```\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"testboard\\\")\"\n```\n\n### create a post of a board with a smart contract call.\n\n```bash\n./build/gnokey maketx call test1 --pkgpath \"gno.land/r/demo/boards\" --func CreatePost --args 1 --args \"Hello World\" --args#file \"./examples/gno.land/r/demo/boards/README.md\" --gas-fee 1ugnot --gas-wanted 2000000 \u003e createpost.unsigned.txt\n./build/gnokey sign test1 --txpath createpost.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 3 \u003e createpost.signed.txt\n./build/gnokey broadcast createpost.signed.txt --remote %%REMOTE%%\n```\n\n### create a comment to a post.\n\n```bash\n./build/gnokey maketx call test1 --pkgpath \"gno.land/r/demo/boards\" --func CreateReply --args 1 --args 1 --args \"A comment\" --gas-fee 1ugnot --gas-wanted 2000000 \u003e createcomment.unsigned.txt\n./build/gnokey sign test1 --txpath createcomment.unsigned.txt --chainid \"%%CHAINID%%\" --number 0 --sequence 4 \u003e createcomment.signed.txt\n./build/gnokey broadcast createcomment.signed.txt --remote %%REMOTE%%\n```\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ntestboard/1\"\n```\n\n### render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:testboard` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ntestboard\"\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"V43B1waFxhzheW9TfmCpjLdrC4dC1yjUGES5y3J6QsNar6hRpNz4G1thzWmWK7xXhg8u1PCIpxLxGczKQYhuPw=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","pkg_version":"v0.0.1","func":"CreateThread","args":["1","NFT example","NFT's are all the rage these days, for various reasons.\n\nI read over EIP-721 which appears to be the de-facto NFT standard on Ethereum. Then, made a sample implementation of EIP-721 (let's here called GRC-721). The implementation isn't complete, but it demonstrates the main functionality.\n\n - [EIP-721](https://eips.ethereum.org/EIPS/eip-721)\n - [gno.land/r/demo/nft/nft.gno](https://gno.land/r/demo/nft/nft.gno)\n - [zrealm_nft3.gno test](https://github.com/gnolang/gno/blob/master/examples/gno.land/r/demo/nft/z_3_filetest.gno)\n\nIn short, this demonstrates how to implement Ethereum contract interfaces in Gno.land; by using only standard Go language features.\n\nPlease leave a comment ([guide](https://gno.land/r/demo/boards:testboard/1)).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"ZXfrTiHxPFQL8uSm+Tv7WXIHPMca9okhm94RAlC6YgNbB1VHQYYpoP4w+cnL3YskVzGrOZxensXa9CAZ+cNNeg=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","pkg_version":"v0.0.1","func":"CreateThread","args":["1","Simple echo example with coins","This is a simple test realm contract that demonstrates how to use the banker.\n\nSee [gno.land/r/demo/banktest/banktest.gno](/r/banktest/banktest.gno) to see the original contract code.\n\nThis article will go through each line to explain how it works.\n\n```go\npackage banktest\n```\n\nThis package is locally named \"banktest\" (could be anything).\n\n```go\nimport (\n\t\"std\"\n)\n```\n\nThe \"std\" package is defined by the gno code in stdlibs/std/. \u003c/br\u003e\nSelf explanatory; and you'll see more usage from std later.\n\n```go\ntype activity struct {\n\tcaller std.Address\n\tsent std.Coins\n\treturned std.Coins\n\ttime std.Time\n}\n\nfunc (act *activity) String() string {\n\treturn act.caller.String() + \" \" +\n\t\tact.sent.String() + \" sent, \" +\n\t\tact.returned.String() + \" returned, at \" +\n\t\tstd.FormatTimestamp(act.time, \"2006-01-02 3:04pm MST\")\n}\n\nvar latest [10]*activity\n```\n\nThis is just maintaining a list of recent activity to this contract.\nNotice that the \"latest\" variable is defined \"globally\" within\nthe context of the realm with path \"gno.land/r/demo/banktest\".\n\nThis means that calls to functions defined within this package\nare encapsulated within this \"data realm\", where the data is \nmutated based on transactions that can potentially cross many\nrealm and non-realm packge boundaries (in the call stack).\n\n```go\n// Deposit will take the coins (to the realm's pkgaddr) or return them to user.\nfunc Deposit(returnDenom string, returnAmount int64) string {\n\tstd.AssertOriginCall()\n\tcaller := std.GetOrigCaller()\n\tsend := std.Coins{{returnDenom, returnAmount}}\n```\n\nThis is the beginning of the definition of the contract function named\n\"Deposit\". `std.AssertOriginCall() asserts that this function was called by a\ngno transactional Message. The caller is the user who signed off on this\ntransactional message. Send is the amount of deposit sent along with this\nmessage.\n\n```go\n\t// record activity\n\tact := \u0026activity{\n\t\tcaller: caller,\n\t\tsent: std.GetOrigSend(),\n\t\treturned: send,\n\t\ttime: std.GetTimestamp(),\n\t}\n\tfor i := len(latest) - 2; i \u003e= 0; i-- {\n\t\tlatest[i+1] = latest[i] // shift by +1.\n\t}\n\tlatest[0] = act\n```\n\nUpdating the \"latest\" array for viewing at gno.land/r/demo/banktest: (w/ trailing colon).\n\n```go\n\t// return if any.\n\tif returnAmount \u003e 0 {\n```\n\nIf the user requested the return of coins...\n\n```go\n\t\tbanker := std.GetBanker(std.BankerTypeOrigSend)\n```\n\nuse a std.Banker instance to return any deposited coins to the original sender.\n\n```go\n\t\tpkgaddr := std.GetOrigPkgAddr()\n\t\t// TODO: use std.Coins constructors, this isn't generally safe.\n\t\tbanker.SendCoins(pkgaddr, caller, send)\n\t\treturn \"returned!\"\n```\n\nNotice that each realm package has an associated Cosmos address.\n\n\nFinally, the results are rendered via an ABCI query call when you visit [/r/banktest:](/r/banktest:).\n\n```go\nfunc Render(path string) string {\n\t// get realm coins.\n\tbanker := std.GetBanker(std.BankerTypeReadonly)\n\tcoins := banker.GetCoins(std.GetOrigPkgAddr())\n\n\t// render\n\tres := \"\"\n\tres += \"## recent activity\\n\"\n\tres += \"\\n\"\n\tfor _, act := range latest {\n\t\tif act == nil {\n\t\t\tbreak\n\t\t}\n\t\tres += \" * \" + act.String() + \"\\n\"\n\t}\n\tres += \"\\n\"\n\tres += \"## total deposits\\n\"\n\tres += coins.String()\n\treturn res\n}\n```\n\nYou can call this contract yourself, by vistiing [/r/banktest](/r/banktest) and the [quickstart guide](/r/boards:testboard/4).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"iZX/llZlNTdZMLv1goCTgK2bWqzT8enlTq56wMTCpVxJGA0BTvuEM5Nnt9vrnlG6Taqj2GuTrmEnJBkDFTmt9g=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","pkg_version":"v0.0.1","func":"CreateThread","args":["1","TASK: Describe in your words","Describe in an essay (250+ words), on your favorite medium, why you are interested in gno.land and gnolang.\n\nReply here with a URL link to your written piece as a comment, for rewards.\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"4HBNtrta8HdeHj4JTN56PBTRK8GOe31NMRRXDiyYtjozuyRdWfOGEsGjGgHWcoBUJq6DepBgD4FetdqfhZ6TNQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/boards","pkg_version":"v0.0.1","func":"CreateThread","args":["1","Getting Started","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm\nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n\n\n## Build `gnokey`, create your account, and interact with Gno.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### Build `gnokey`.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake\n```\n\n### Generate a seed/mnemonic code.\n\n```bash\n./build/gnokey generate\n```\n\nNOTE: You can generate 24 words with any good bip39 generator.\n\n### Create a new account using your mnemonic.\n\n```bash\n./build/gnokey add KEYNAME --recover\n```\n\nNOTE: `KEYNAME` is your key identifier, and should be changed.\n\n### Verify that you can see your account locally.\n\n```bash\n./build/gnokey list\n```\n\n## Interact with the blockchain:\n\n### Get your current balance, account number, and sequence number.\n\n```bash\n./build/gnokey query auth/accounts/ACCOUNT_ADDR --remote %%REMOTE%%\n```\n\nNOTE: you can retrieve your `ACCOUNT_ADDR` with `./build/gnokey list`.\n\n### Acquire testnet tokens using the official faucet.\n\nGo to https://gno.land/faucet\n\n### Create a board with a smart contract call.\n\nNOTE: `BOARDNAME` will be the slug of the board, and should be changed.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateBoard\" --args \"BOARDNAME\" --gas-fee \"1000000ugnot\" --gas-wanted \"2000000\" --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateBoard\n\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"BOARDNAME\\\")\" --remote %%REMOTE%%\n```\n\n### Create a post of a board with a smart contract call.\n\nNOTE: If a board was created successfully, your SEQUENCE_NUMBER would have increased.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateThread\" --args BOARD_ID --args \"Hello gno.land\" --args\\#file \"./examples/gno.land/r/demo/boards/example_post.md\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateThread\n\n### Create a comment to a post.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateReply\" --args \"BOARD_ID\" --args \"1\" --args \"1\" --args \"Nice to meet you too.\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\nBOARDNAME/1\" --remote %%REMOTE%%\n```\n\n### Render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:gnolang` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ngnolang\"\n```\n\n## Starting a local `gnoland` node:\n\n### Add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mneonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### Start `gnoland` node.\n\n```bash\n./build/gnoland\n```\n\nNOTE: This can be reset with `make reset`\n\n### Publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n\n### Publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 300000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","pkg_version":"v0.0.1","func":"ModAddPost","args":["post1","First post","Lorem Ipsum","2022-03-20T13:17:22Z","moul","tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","pkg_version":"v0.0.1","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum","2022-04-20T13:17:22Z","moul","tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} diff --git a/gno.land/pkg/gnoclient/client_test.go b/gno.land/pkg/gnoclient/client_test.go index 044919173e8..2c39947e047 100644 --- a/gno.land/pkg/gnoclient/client_test.go +++ b/gno.land/pkg/gnoclient/client_test.go @@ -96,10 +96,11 @@ func TestCallSingle(t *testing.T) { msg := []MsgCall{ { - PkgPath: "gno.land/r/demo/deep/very/deep", - FuncName: "Render", - Args: []string{""}, - Send: "100ugnot", + PkgPath: "gno.land/r/demo/deep/very/deep", + PkgVersion: "v0.1.0", + FuncName: "Render", + Args: []string{""}, + Send: "100ugnot", }, } @@ -155,22 +156,25 @@ func TestCallMultiple(t *testing.T) { msg := []MsgCall{ { - PkgPath: "gno.land/r/demo/deep/very/deep", - FuncName: "Render", - Args: []string{""}, - Send: "100ugnot", + PkgPath: "gno.land/r/demo/deep/very/deep", + PkgVersion: "v0.1.0", + FuncName: "Render", + Args: []string{""}, + Send: "100ugnot", }, { - PkgPath: "gno.land/r/demo/wugnot", - FuncName: "Deposit", - Args: []string{""}, - Send: "1000ugnot", + PkgPath: "gno.land/r/demo/wugnot", + PkgVersion: "v0.1.0", + FuncName: "Deposit", + Args: []string{""}, + Send: "1000ugnot", }, { - PkgPath: "gno.land/r/demo/tamagotchi", - FuncName: "Feed", - Args: []string{""}, - Send: "", + PkgPath: "gno.land/r/demo/tamagotchi", + PkgVersion: "v0.1.0", + FuncName: "Feed", + Args: []string{""}, + Send: "", }, } @@ -204,10 +208,11 @@ func TestCallErrors(t *testing.T) { }, msgs: []MsgCall{ { - PkgPath: "random/path", - FuncName: "RandomName", - Send: "", - Args: []string{}, + PkgPath: "random/path", + PkgVersion: "v0.0.0", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, expectedError: ErrMissingSigner, @@ -227,10 +232,11 @@ func TestCallErrors(t *testing.T) { }, msgs: []MsgCall{ { - PkgPath: "random/path", - FuncName: "RandomName", - Send: "", - Args: []string{}, + PkgPath: "random/path", + PkgVersion: "v0.0.0", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, expectedError: ErrMissingRPCClient, @@ -250,8 +256,9 @@ func TestCallErrors(t *testing.T) { }, msgs: []MsgCall{ { - PkgPath: "random/path", - FuncName: "RandomName", + PkgPath: "random/path", + PkgVersion: "v0.0.0", + FuncName: "RandomName", }, }, expectedError: ErrInvalidGasFee, @@ -271,10 +278,11 @@ func TestCallErrors(t *testing.T) { }, msgs: []MsgCall{ { - PkgPath: "random/path", - FuncName: "RandomName", - Send: "", - Args: []string{}, + PkgPath: "random/path", + PkgVersion: "v0.0.0", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, expectedError: ErrInvalidGasWanted, @@ -294,10 +302,11 @@ func TestCallErrors(t *testing.T) { }, msgs: []MsgCall{ { - PkgPath: "random/path", - FuncName: "RandomName", - Send: "", - Args: []string{}, + PkgPath: "random/path", + PkgVersion: "v0.0.0", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, expectedError: ErrInvalidGasWanted, @@ -325,6 +334,30 @@ func TestCallErrors(t *testing.T) { }, expectedError: ErrEmptyPkgPath, }, + { + name: "Invalid PkgVersion", + client: Client{ + Signer: &mockSigner{}, + RPCClient: &mockRPCClient{}, + }, + cfg: BaseTxCfg{ + GasWanted: 100000, + GasFee: "10000ugnot", + AccountNumber: 1, + SequenceNumber: 1, + Memo: "Test memo", + }, + msgs: []MsgCall{ + { + PkgPath: "random/path", + PkgVersion: "", + FuncName: "RandomName", + Send: "", + Args: []string{}, + }, + }, + expectedError: ErrEmptyPkgVersion, + }, { name: "Invalid FuncName", client: Client{ @@ -340,10 +373,11 @@ func TestCallErrors(t *testing.T) { }, msgs: []MsgCall{ { - PkgPath: "random/path", - FuncName: "", - Send: "", - Args: []string{}, + PkgPath: "random/path", + PkgVersion: "v0.0.1", + FuncName: "", + Send: "", + Args: []string{}, }, }, expectedError: ErrEmptyFuncName, @@ -726,7 +760,10 @@ func TestRunErrors(t *testing.T) { { Package: &std.MemPackage{ Name: "", - Path: "", + ModFile: &std.MemMod{ + ImportPath: "", + Version: "", + }, Files: []*std.MemFile{ { Name: "file1.gno", @@ -772,7 +809,10 @@ func TestRunErrors(t *testing.T) { { Package: &std.MemPackage{ Name: "", - Path: "", + ModFile: &std.MemMod{ + ImportPath: "", + Version: "", + }, Files: []*std.MemFile{ { Name: "file1.gno", @@ -802,7 +842,10 @@ func TestRunErrors(t *testing.T) { { Package: &std.MemPackage{ Name: "", - Path: "", + ModFile: &std.MemMod{ + ImportPath: "", + Version: "", + }, Files: []*std.MemFile{ { Name: "file1.gno", @@ -832,7 +875,10 @@ func TestRunErrors(t *testing.T) { { Package: &std.MemPackage{ Name: "", - Path: "", + ModFile: &std.MemMod{ + ImportPath: "", + Version: "", + }, Files: []*std.MemFile{ { Name: "file1.gno", diff --git a/gno.land/pkg/gnoclient/client_txs.go b/gno.land/pkg/gnoclient/client_txs.go index 2a83eef1b79..e8a8f07d416 100644 --- a/gno.land/pkg/gnoclient/client_txs.go +++ b/gno.land/pkg/gnoclient/client_txs.go @@ -14,6 +14,7 @@ import ( var ( ErrEmptyPackage = errors.New("empty package to run") ErrEmptyPkgPath = errors.New("empty pkg path") + ErrEmptyPkgVersion = errors.New("empty pkg version") ErrEmptyFuncName = errors.New("empty function name") ErrInvalidGasWanted = errors.New("invalid gas wanted") ErrInvalidGasFee = errors.New("invalid gas fee") @@ -33,10 +34,11 @@ type BaseTxCfg struct { // MsgCall - syntax sugar for vm.MsgCall type MsgCall struct { - PkgPath string // Package path - FuncName string // Function name - Args []string // Function arguments - Send string // Send amount + PkgPath string // Package path + PkgVersion string // Package version + FuncName string // Function name + Args []string // Function arguments + Send string // Send amount } // MsgSend - syntax sugar for bank.MsgSend minus fields in BaseTxCfg @@ -82,11 +84,12 @@ func (c *Client) Call(cfg BaseTxCfg, msgs ...MsgCall) (*ctypes.ResultBroadcastTx // Unwrap syntax sugar to vm.MsgCall slice vmMsgs = append(vmMsgs, std.Msg(vm.MsgCall{ - Caller: c.Signer.Info().GetAddress(), - PkgPath: msg.PkgPath, - Func: msg.FuncName, - Args: msg.Args, - Send: send, + Caller: c.Signer.Info().GetAddress(), + PkgPath: msg.PkgPath, + PkgVersion: msg.PkgVersion, + Func: msg.FuncName, + Args: msg.Args, + Send: send, })) } @@ -144,7 +147,12 @@ func (c *Client) Run(cfg BaseTxCfg, msgs ...MsgRun) (*ctypes.ResultBroadcastTxCo } msg.Package.Name = "main" - msg.Package.Path = "" + if msg.Package.ModFile == nil { + msg.Package.ModFile = &std.MemMod{ + ImportPath: "", + Version: "", + } + } // Unwrap syntax sugar to vm.MsgCall slice vmMsgs = append(vmMsgs, std.Msg(vm.MsgRun{ diff --git a/gno.land/pkg/gnoclient/integration_test.go b/gno.land/pkg/gnoclient/integration_test.go index 554cba8ecf2..70291b3b998 100644 --- a/gno.land/pkg/gnoclient/integration_test.go +++ b/gno.land/pkg/gnoclient/integration_test.go @@ -42,10 +42,11 @@ func TestCallSingle_Integration(t *testing.T) { // Make Msg config msg := MsgCall{ - PkgPath: "gno.land/r/demo/deep/very/deep", - FuncName: "Render", - Args: []string{"test argument"}, - Send: "", + PkgPath: "gno.land/r/demo/deep/very/deep", + PkgVersion: "v0.1.0", + FuncName: "Render", + Args: []string{"test argument"}, + Send: "", } // Execute call @@ -85,18 +86,20 @@ func TestCallMultiple_Integration(t *testing.T) { // Make Msg configs msg1 := MsgCall{ - PkgPath: "gno.land/r/demo/deep/very/deep", - FuncName: "Render", - Args: []string{""}, - Send: "", + PkgPath: "gno.land/r/demo/deep/very/deep", + PkgVersion: "v0.1.0", + FuncName: "Render", + Args: []string{""}, + Send: "", } // Same call, different argument msg2 := MsgCall{ - PkgPath: "gno.land/r/demo/deep/very/deep", - FuncName: "Render", - Args: []string{"test argument"}, - Send: "", + PkgPath: "gno.land/r/demo/deep/very/deep", + PkgVersion: "v0.1.0", + FuncName: "Render", + Args: []string{"test argument"}, + Send: "", } expected := "(\"it works!\" string)(\"hi test argument\" string)" @@ -254,6 +257,14 @@ func main() { // Make Msg configs msg := MsgRun{ Package: &std.MemPackage{ + ModFile: &std.MemMod{ + ImportPath: "", + Version: "", + Requires: []*std.Requirements{ + {"gno.land/p/demo/ufmt", "v0.1.0"}, + {"gno.land/r/demo/tests", "v0.1.0"}, + }, + }, Files: []*std.MemFile{ { Name: "main.gno", @@ -322,6 +333,14 @@ func main() { // Make Msg configs msg1 := MsgRun{ Package: &std.MemPackage{ + ModFile: &std.MemMod{ + ImportPath: "", + Version: "", + Requires: []*std.Requirements{ + {"gno.land/p/demo/ufmt", "v0.1.0"}, + {"gno.land/r/demo/tests", "v0.1.0"}, + }, + }, Files: []*std.MemFile{ { Name: "main.gno", @@ -333,6 +352,14 @@ func main() { } msg2 := MsgRun{ Package: &std.MemPackage{ + ModFile: &std.MemMod{ + ImportPath: "", + Version: "", + Requires: []*std.Requirements{ + {"gno.land/p/demo/ufmt", "v0.1.0"}, + {"gno.land/r/demo/deep/very/deep", "v0.1.0"}, + }, + }, Files: []*std.MemFile{ { Name: "main.gno", diff --git a/gno.land/pkg/gnoclient/util.go b/gno.land/pkg/gnoclient/util.go index 9860d567f1e..7c652a8ade0 100644 --- a/gno.land/pkg/gnoclient/util.go +++ b/gno.land/pkg/gnoclient/util.go @@ -17,6 +17,9 @@ func (msg MsgCall) validateMsgCall() error { if msg.PkgPath == "" { return ErrEmptyPkgPath } + if msg.PkgVersion == "" { + return ErrEmptyPkgVersion + } if msg.FuncName == "" { return ErrEmptyFuncName } diff --git a/gno.land/pkg/integration/testdata/adduser.txtar b/gno.land/pkg/integration/testdata/adduser.txtar index ebd0e4abb43..382fba6702a 100644 --- a/gno.land/pkg/integration/testdata/adduser.txtar +++ b/gno.land/pkg/integration/testdata/adduser.txtar @@ -4,7 +4,7 @@ adduser test8 gnoland start ## add bar.gno package located in $WORK directory as gno.land/r/foobar/bar -gnokey maketx addpkg -pkgdir $WORK/bar -pkgpath gno.land/r/foobar/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test8 +gnokey maketx addpkg -pkgdir $WORK/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test8 ## execute Render gnokey maketx run -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test8 $WORK/script/script.gno @@ -19,6 +19,9 @@ stdout 'GAS USED: ' ! adduser test5 stderr '"adduser" error: adduser must be used before starting node' +-- bar/gno.mod -- +module gno.land/r/foobar/bar v0.0.0 + -- bar/bar.gno -- package bar @@ -26,6 +29,11 @@ func Render(path string) string { return "hello from foo" } +-- script/gno.mod -- +module gno.land/r/script v0.0.0 + +require gno.land/r/foobar/bar v0.0.0 + -- script/script.gno -- package main import "gno.land/r/foobar/bar" diff --git a/gno.land/pkg/integration/testdata/import.txtar b/gno.land/pkg/integration/testdata/import.txtar index dc286c32eb3..e1032912363 100644 --- a/gno.land/pkg/integration/testdata/import.txtar +++ b/gno.land/pkg/integration/testdata/import.txtar @@ -6,12 +6,14 @@ loadpkg $WORK gnoland start ## execute Render -gnokey maketx call -pkgpath gno.land/r/importtest -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/importtest@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("92054" string)' stdout OK! -- gno.mod -- -module gno.land/r/importtest +module gno.land/r/importtest v0.0.0 + +require gno.land/p/demo/ufmt v0.1.0 -- import.gno -- package importtest diff --git a/gno.land/pkg/integration/testdata/loadpkg_example.txtar b/gno.land/pkg/integration/testdata/loadpkg_example.txtar index d0c95331ff5..27793245c0d 100644 --- a/gno.land/pkg/integration/testdata/loadpkg_example.txtar +++ b/gno.land/pkg/integration/testdata/loadpkg_example.txtar @@ -4,16 +4,18 @@ loadpkg gno.land/p/demo/ufmt ## start a new node gnoland start -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/importtest -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! ## execute Render -gnokey maketx call -pkgpath gno.land/r/importtest -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/importtest@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("92054" string)' stdout OK! -- gno.mod -- -module gno.land/r/importtest +module gno.land/r/importtest v0.0.0 + +require gno.land/p/demo/ufmt v0.1.0 -- import.gno -- package importtest diff --git a/gno.land/pkg/integration/testdata/loadpkg_example_and_work.txtar b/gno.land/pkg/integration/testdata/loadpkg_example_and_work.txtar index 27e357fece4..999e86f80db 100644 --- a/gno.land/pkg/integration/testdata/loadpkg_example_and_work.txtar +++ b/gno.land/pkg/integration/testdata/loadpkg_example_and_work.txtar @@ -6,10 +6,15 @@ loadpkg gno.land/r/importtest $WORK gnoland start ## execute Render -gnokey maketx call -pkgpath gno.land/r/importtest -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/importtest@v0.0.0 -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("92054" string)' stdout OK! +-- gno.mod -- +module gno.land/r/importtest v0.0.0 + +require gno.land/p/demo/ufmt v0.1.0 + -- import.gno -- package importtest diff --git a/gno.land/pkg/integration/testdata/loadpkg_work.txtar b/gno.land/pkg/integration/testdata/loadpkg_work.txtar index 5fb9a07c5de..74074ed82fa 100644 --- a/gno.land/pkg/integration/testdata/loadpkg_work.txtar +++ b/gno.land/pkg/integration/testdata/loadpkg_work.txtar @@ -13,6 +13,9 @@ stdout 'OK!' stdout 'GAS WANTED: 200000' stdout 'GAS USED: ' +-- bar/gno.mod -- +module gno.land/r/foobar/bar v0.0.0 + -- bar/bar.gno -- package bar @@ -20,6 +23,11 @@ func Render(path string) string { return "hello from foo" } +-- script/gno.mod -- +module gno.land/r/script v0.0.0 + +require gno.land/r/foobar/bar v0.0.0 + -- script/script.gno -- package main diff --git a/gno.land/pkg/keyscli/addpkg.go b/gno.land/pkg/keyscli/addpkg.go index b04c39398ce..556b2088eba 100644 --- a/gno.land/pkg/keyscli/addpkg.go +++ b/gno.land/pkg/keyscli/addpkg.go @@ -19,7 +19,6 @@ import ( type MakeAddPkgCfg struct { RootCfg *client.MakeTxCfg - PkgPath string PkgDir string Deposit string } @@ -43,13 +42,6 @@ func NewMakeAddPkgCmd(rootCfg *client.MakeTxCfg, io commands.IO) *commands.Comma } func (c *MakeAddPkgCfg) RegisterFlags(fs *flag.FlagSet) { - fs.StringVar( - &c.PkgPath, - "pkgpath", - "", - "package path (required)", - ) - fs.StringVar( &c.PkgDir, "pkgdir", @@ -66,9 +58,6 @@ func (c *MakeAddPkgCfg) RegisterFlags(fs *flag.FlagSet) { } func execMakeAddPkg(cfg *MakeAddPkgCfg, args []string, io commands.IO) error { - if cfg.PkgPath == "" { - return errors.New("pkgpath not specified") - } if cfg.PkgDir == "" { return errors.New("pkgdir not specified") } @@ -97,9 +86,10 @@ func execMakeAddPkg(cfg *MakeAddPkgCfg, args []string, io commands.IO) error { } // open files in directory as MemPackage. - memPkg := gno.ReadMemPackage(cfg.PkgDir, cfg.PkgPath) + // lazily parse pkgPath from gno.mod + memPkg := gno.ReadMemPackage(cfg.PkgDir, "") if memPkg.IsEmpty() { - panic(fmt.Sprintf("found an empty package %q", cfg.PkgPath)) + panic(fmt.Sprintf("found an empty package ar dir %q", cfg.PkgDir)) } // transpile and validate syntax diff --git a/gno.land/pkg/keyscli/call.go b/gno.land/pkg/keyscli/call.go index 7eb5be7d501..31e1a473640 100644 --- a/gno.land/pkg/keyscli/call.go +++ b/gno.land/pkg/keyscli/call.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "strings" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/gnolang/gno/tm2/pkg/amino" @@ -74,6 +75,13 @@ func execMakeCall(cfg *MakeCallCfg, args []string, io commands.IO) error { if cfg.PkgPath == "" { return errors.New("pkgpath not specified") } + parts := strings.Split(cfg.PkgPath, "@") + if len(parts) != 2 { + return errors.New("expected: module/path@v1.2.3") + } + pkgPath := parts[0] + pkgVersion := parts[1] + if cfg.FuncName == "" { return errors.New("func not specified") } @@ -118,11 +126,12 @@ func execMakeCall(cfg *MakeCallCfg, args []string, io commands.IO) error { // construct msg & tx and marshal. msg := vm.MsgCall{ - Caller: caller, - Send: send, - PkgPath: cfg.PkgPath, - Func: fnc, - Args: cfg.Args, + Caller: caller, + Send: send, + PkgPath: pkgPath, + PkgVersion: pkgVersion, + Func: fnc, + Args: cfg.Args, } tx := std.Tx{ Msgs: []std.Msg{msg}, diff --git a/gno.land/pkg/keyscli/run.go b/gno.land/pkg/keyscli/run.go index dc4c6d1d28d..980e36be8ea 100644 --- a/gno.land/pkg/keyscli/run.go +++ b/gno.land/pkg/keyscli/run.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os" + "path/filepath" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" @@ -98,16 +99,25 @@ func execMakeRun(cfg *MakeRunCfg, args []string, cmdio commands.IO) error { if err != nil { return fmt.Errorf("could not read %q: %w", sourcePath, err) } - memPkg.Files = []*std.MemFile{ - { - Name: info.Name(), - Body: string(b), + + gm := gno.ParseMemMod(filepath.Dir(sourcePath)) + // TODO(hariom): Remove + // if err != nil { + // return fmt.Errorf("error parse gno.mod at: %q", sourcePath) + // } + memPkg = &std.MemPackage{ + ModFile: gm, + Files: []*std.MemFile{ + { + Name: info.Name(), + Body: string(b), + }, }, } } } if memPkg.IsEmpty() { - panic(fmt.Sprintf("found an empty package %q", memPkg.Path)) + panic(fmt.Sprintf("found an empty package %q", memPkg.ModFile.ImportPath)) } // transpile and validate syntax err = transpiler.TranspileAndCheckMempkg(memPkg) @@ -116,7 +126,7 @@ func execMakeRun(cfg *MakeRunCfg, args []string, cmdio commands.IO) error { } memPkg.Name = "main" // Set to empty; this will be automatically set by the VM keeper. - memPkg.Path = "" + memPkg.ModFile.ImportPath = "" // construct msg & tx and marshal. msg := vm.MsgRun{ diff --git a/gno.land/pkg/sdk/vm/errors.go b/gno.land/pkg/sdk/vm/errors.go index 64778f8b467..23722f24591 100644 --- a/gno.land/pkg/sdk/vm/errors.go +++ b/gno.land/pkg/sdk/vm/errors.go @@ -10,19 +10,25 @@ func (abciError) AssertABCIError() {} // declare all script errors. // NOTE: these are meant to be used in conjunction with pkgs/errors. type ( - InvalidPkgPathError struct{ abciError } - InvalidStmtError struct{ abciError } - InvalidExprError struct{ abciError } + InvalidPkgPathError struct{ abciError } + InvalidPkgVersionError struct{ abciError } + InvalidStmtError struct{ abciError } + InvalidExprError struct{ abciError } ) -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 InvalidPkgPathError) Error() string { return "invalid package path" } +func (e InvalidPkgVersionError) Error() string { return "invalid package version" } +func (e InvalidStmtError) Error() string { return "invalid statement" } +func (e InvalidExprError) Error() string { return "invalid expression" } func ErrInvalidPkgPath(msg string) error { return errors.Wrap(InvalidPkgPathError{}, msg) } +func ErrInvalidPkgVersion(msg string) error { + return errors.Wrap(InvalidPkgVersionError{}, msg) +} + func ErrInvalidStmt(msg string) error { return errors.Wrap(InvalidStmtError{}, msg) } diff --git a/gno.land/pkg/sdk/vm/handler.go b/gno.land/pkg/sdk/vm/handler.go index 6c3a97696d6..a90efeb6e09 100644 --- a/gno.land/pkg/sdk/vm/handler.go +++ b/gno.land/pkg/sdk/vm/handler.go @@ -153,10 +153,22 @@ func (vh vmHandler) queryRender(ctx sdk.Context, req abci.RequestQuery) (res abc if len(reqParts) != 2 { panic("expected two lines in query input data") } - pkgPath := reqParts[0] + + pkgPathWithVersion := reqParts[0] path := reqParts[1] + + pkgPathParts := strings.Split(pkgPathWithVersion, "@") + if len(pkgPathParts) != 2 { + panic("expected: package/path@v1.2.3") + } + + // TODO(hariom): validate version? + + pkgPath := pkgPathParts[0] + pkgVersion := pkgPathParts[1] + expr := fmt.Sprintf("Render(%q)", path) - result, err := vh.vm.QueryEvalString(ctx, pkgPath, expr) + result, err := vh.vm.QueryEvalString(ctx, pkgPath, pkgVersion, expr) if err != nil { res = sdk.ABCIResponseQueryFromError(err) return @@ -172,8 +184,20 @@ func (vh vmHandler) queryFuncs(ctx sdk.Context, req abci.RequestQuery) (res abci if len(reqParts) != 1 { panic("expected one line in query input data") } - pkgPath := reqParts[0] - fsigs, err := vh.vm.QueryFuncs(ctx, pkgPath) + + pkgPathWithVersion := reqParts[0] + + pkgPathParts := strings.Split(pkgPathWithVersion, "@") + if len(pkgPathParts) != 2 { + panic("expected: package/path@v1.2.3") + } + + // TODO(hariom): validate version? + + pkgPath := pkgPathParts[0] + pkgVersion := pkgPathParts[1] + + fsigs, err := vh.vm.QueryFuncs(ctx, pkgPath, pkgVersion) if err != nil { res = sdk.ABCIResponseQueryFromError(err) return @@ -189,9 +213,21 @@ func (vh vmHandler) queryEval(ctx sdk.Context, req abci.RequestQuery) (res abci. if len(reqParts) != 2 { panic("expected two lines in query input data") } - pkgPath := reqParts[0] + + pkgPathWithVersion := reqParts[0] expr := reqParts[1] - result, err := vh.vm.QueryEval(ctx, pkgPath, expr) + + pkgPathParts := strings.Split(pkgPathWithVersion, "@") + if len(pkgPathParts) != 2 { + panic("expected: package/path@v1.2.3") + } + + // TODO(hariom): validate version? + + pkgPath := pkgPathParts[0] + pkgVersion := pkgPathParts[1] + + result, err := vh.vm.QueryEval(ctx, pkgPath, pkgVersion, expr) if err != nil { res = sdk.ABCIResponseQueryFromError(err) return @@ -205,7 +241,8 @@ func (vh vmHandler) queryEval(ctx sdk.Context, req abci.RequestQuery) (res abci. // if dir, res.Value is []byte("dir"). func (vh vmHandler) queryFile(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) { filepath := string(req.Data) - result, err := vh.vm.QueryFile(ctx, filepath) + version := "" // TODO(hariom): get version from abci req + result, err := vh.vm.QueryFile(ctx, version, filepath) if err != nil { res = sdk.ABCIResponseQueryFromError(err) return diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 54f424ee058..31e88925b7b 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -136,7 +136,8 @@ var reRunPath = regexp.MustCompile(`gno\.land/r/g[a-z0-9]+/run`) // AddPackage adds a package with given fileset. func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { creator := msg.Creator - pkgPath := msg.Package.Path + pkgPath := msg.Package.ModFile.ImportPath + pkgVersion := msg.Package.ModFile.Version memPkg := msg.Package deposit := msg.Deposit store := vm.getGnoStore(ctx) @@ -152,7 +153,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { if err := msg.Package.Validate(); err != nil { return ErrInvalidPkgPath(err.Error()) } - if pv := store.GetPackage(pkgPath, false); pv != nil { + if pv := store.GetPackage(pkgPath, pkgVersion, false); pv != nil { return ErrInvalidPkgPath("package already exists: " + pkgPath) } @@ -161,7 +162,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { } // Pay deposit from creator. - pkgAddr := gno.DerivePkgAddr(pkgPath) + pkgAddr := gno.DerivePkgAddr(pkgPath, pkgVersion) // TODO: ACLs. // - if r/system/names does not exists -> skip validation. @@ -189,12 +190,13 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { // Parse and run the files, construct *PV. m2 := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: os.Stdout, // XXX - Store: store, - Alloc: store.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, + PkgPath: "", + PkgVersion: pkgVersion, + Output: os.Stdout, // XXX + Store: store, + Alloc: store.GetAllocator(), + Context: msgCtx, + MaxCycles: vm.maxCycles, }) defer m2.Release() m2.RunMemPackage(memPkg, true) @@ -206,15 +208,20 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error { // Calls calls a public Gno function (for delivertx). func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { pkgPath := msg.PkgPath // to import + pkgVersion := msg.PkgVersion fnc := msg.Func store := vm.getGnoStore(ctx) // Get the package and function type. - pv := store.GetPackage(pkgPath, false) - pl := gno.PackageNodeLocation(pkgPath) + pv := store.GetPackage(pkgPath, pkgVersion, false) + pl := gno.PackageNodeLocation(pkgPath, pkgVersion) pn := store.GetBlockNode(pl).(*gno.PackageNode) ft := pn.GetStaticTypeOf(store, gno.Name(fnc)).(*gno.FuncType) // Make main Package with imports. - mpn := gno.NewPackageNode("main", "main", nil) + mpn := gno.NewPackageNode("main", &gno.ModFileNode{ + Path: "main", + Version: pv.ModFile.Version, + Require: pv.ModFile.Require, + }, nil) mpn.Define("pkg", gno.TypedValue{T: &gno.PackageType{}, V: pv}) mpv := mpn.NewPackage() // Parse expression. @@ -228,7 +235,7 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { expr := fmt.Sprintf(`pkg.%s(%s)`, fnc, argslist) xn := gno.MustParseExpr(expr) // Send send-coins to pkg from caller. - pkgAddr := gno.DerivePkgAddr(pkgPath) + pkgAddr := gno.DerivePkgAddr(pkgPath, pkgVersion) caller := msg.Caller send := msg.Send err = vm.bank.SendCoins(ctx, caller, pkgAddr, send) @@ -306,7 +313,7 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { // coerce path to right one. // the path in the message must be "" or the following path. // this is already checked in MsgRun.ValidateBasic - memPkg.Path = "gno.land/r/" + msg.Caller.String() + "/run" + memPkg.ModFile.ImportPath = "gno.land/r/" + msg.Caller.String() + "/run" // Validate arguments. callerAcc := vm.acck.GetAccount(ctx, caller) @@ -377,7 +384,7 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { } // QueryFuncs returns public facing function signatures. -func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionSignatures, err error) { +func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath, pkgVersion string) (fsigs FunctionSignatures, err error) { store := vm.getGnoStore(ctx) // Ensure pkgPath is realm. if !gno.IsRealmPath(pkgPath) { @@ -386,7 +393,7 @@ func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionS return nil, err } // Get Package. - pv := store.GetPackage(pkgPath, false) + pv := store.GetPackage(pkgPath, pkgVersion, false) if pv == nil { err = ErrInvalidPkgPath(fmt.Sprintf( "package not found: %s", pkgPath)) @@ -439,12 +446,12 @@ func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionS // QueryEval evaluates a gno expression (readonly, for ABCI queries). // TODO: modify query protocol to allow MsgEval. // TODO: then, rename to "Eval". -func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res string, err error) { +func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath, pkgVersion string, expr string) (res string, err error) { alloc := gno.NewAllocator(maxAllocQuery) store := vm.getGnoStore(ctx) - pkgAddr := gno.DerivePkgAddr(pkgPath) + pkgAddr := gno.DerivePkgAddr(pkgPath, pkgVersion) // Get Package. - pv := store.GetPackage(pkgPath, false) + pv := store.GetPackage(pkgPath, pkgVersion, false) if pv == nil { err = ErrInvalidPkgPath(fmt.Sprintf( "package not found: %s", pkgPath)) @@ -469,12 +476,13 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res } m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: pkgPath, - Output: os.Stdout, // XXX - Store: store, - Context: msgCtx, - Alloc: alloc, - MaxCycles: vm.maxCycles, + PkgPath: pkgPath, + PkgVersion: "", // TODO(hariom): version? + Output: os.Stdout, // XXX + Store: store, + Context: msgCtx, + Alloc: alloc, + MaxCycles: vm.maxCycles, }) defer func() { if r := recover(); r != nil { @@ -499,12 +507,12 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res // The result is expected to be a single string (not a tuple). // TODO: modify query protocol to allow MsgEval. // TODO: then, rename to "EvalString". -func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string) (res string, err error) { +func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath, pkgVersion string, expr string) (res string, err error) { alloc := gno.NewAllocator(maxAllocQuery) store := vm.getGnoStore(ctx) - pkgAddr := gno.DerivePkgAddr(pkgPath) + pkgAddr := gno.DerivePkgAddr(pkgPath, pkgVersion) // Get Package. - pv := store.GetPackage(pkgPath, false) + pv := store.GetPackage(pkgPath, pkgVersion, false) if pv == nil { err = ErrInvalidPkgPath(fmt.Sprintf( "package not found: %s", pkgPath)) @@ -554,17 +562,17 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string return res, nil } -func (vm *VMKeeper) QueryFile(ctx sdk.Context, filepath string) (res string, err error) { +func (vm *VMKeeper) QueryFile(ctx sdk.Context, version, filepath string) (res string, err error) { store := vm.getGnoStore(ctx) dirpath, filename := std.SplitFilepath(filepath) if filename != "" { - memFile := store.GetMemFile(dirpath, filename) + memFile := store.GetMemFile(dirpath, version, filename) if memFile == nil { return "", fmt.Errorf("file %q is not available", filepath) // TODO: XSS protection } return memFile.Body, nil } else { - memPkg := store.GetMemPackage(dirpath) + memPkg := store.GetMemPackage(dirpath, version) for i, memfile := range memPkg.Files { if i > 0 { res += "\n" diff --git a/gno.land/pkg/sdk/vm/keeper_test.go b/gno.land/pkg/sdk/vm/keeper_test.go index bc6bc285704..c52bf8e776e 100644 --- a/gno.land/pkg/sdk/vm/keeper_test.go +++ b/gno.land/pkg/sdk/vm/keeper_test.go @@ -25,6 +25,8 @@ func TestVMKeeperAddPackage(t *testing.T) { env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + pkgPath := "gno.land/r/test" + // Create test package. files := []*std.MemFile{ { @@ -38,14 +40,18 @@ func Echo() string { }`, }, } - pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) - assert.Nil(t, env.vmk.gnoStore.GetPackage(pkgPath, false)) + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } + + msg1 := NewMsgAddPackage(addr, modfile, files) + assert.Nil(t, env.vmk.gnoStore.GetPackage(pkgPath, modfile.Version, false)) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) - assert.NotNil(t, env.vmk.gnoStore.GetPackage(pkgPath, false)) + assert.NotNil(t, env.vmk.gnoStore.GetPackage(pkgPath, modfile.Version, false)) err = env.vmk.AddPackage(ctx, msg1) @@ -65,6 +71,8 @@ func TestVMKeeperOrigSend1(t *testing.T) { env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + pkgPath := "gno.land/r/test" + // Create test package. files := []*std.MemFile{ {"init.gno", ` @@ -84,14 +92,18 @@ func Echo(msg string) string { return "echo:"+msg }`}, } - pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } + + msg1 := NewMsgAddPackage(addr, modfile, files) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) // Run Echo function. coins := std.MustParseCoins("10000000ugnot") - msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) + msg2 := NewMsgCall(addr, coins, pkgPath, modfile.Version, "Echo", []string{"hello world"}) res, err := env.vmk.Call(ctx, msg2) assert.NoError(t, err) assert.Equal(t, res, `("echo:hello world" string)`) @@ -110,6 +122,8 @@ func TestVMKeeperOrigSend2(t *testing.T) { env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + pkgPath := "gno.land/r/test" + // Create test package. files := []*std.MemFile{ {"init.gno", ` @@ -137,14 +151,18 @@ func GetAdmin() string { } `}, } - pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } + + msg1 := NewMsgAddPackage(addr, modfile, files) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) // Run Echo function. coins := std.MustParseCoins("11000000ugnot") - msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) + msg2 := NewMsgCall(addr, coins, pkgPath, modfile.Version, "Echo", []string{"hello world"}) res, err := env.vmk.Call(ctx, msg2) assert.Error(t, err) assert.Equal(t, res, "") @@ -164,6 +182,8 @@ func TestVMKeeperOrigSend3(t *testing.T) { env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + pkgPath := "gno.land/r/test" + // Create test package. files := []*std.MemFile{ {"init.gno", ` @@ -183,14 +203,18 @@ func Echo(msg string) string { return "echo:"+msg }`}, } - pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } + + msg1 := NewMsgAddPackage(addr, modfile, files) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) // Run Echo function. coins := std.MustParseCoins("9000000ugnot") - msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) + msg2 := NewMsgCall(addr, coins, pkgPath, modfile.Version, "Echo", []string{"hello world"}) // XXX change this into an error and make sure error message is descriptive. _, err = env.vmk.Call(ctx, msg2) assert.Error(t, err) @@ -208,6 +232,8 @@ func TestVMKeeperRealmSend1(t *testing.T) { env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + pkgPath := "gno.land/r/test" + // Create test package. files := []*std.MemFile{ {"init.gno", ` @@ -227,14 +253,18 @@ func Echo(msg string) string { return "echo:"+msg }`}, } - pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } + + msg1 := NewMsgAddPackage(addr, modfile, files) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) // Run Echo function. coins := std.MustParseCoins("10000000ugnot") - msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) + msg2 := NewMsgCall(addr, coins, pkgPath, modfile.Version, "Echo", []string{"hello world"}) res, err := env.vmk.Call(ctx, msg2) assert.NoError(t, err) assert.Equal(t, res, `("echo:hello world" string)`) @@ -252,6 +282,8 @@ func TestVMKeeperRealmSend2(t *testing.T) { env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + pkgPath := "gno.land/r/test" + // Create test package. files := []*std.MemFile{ {"init.gno", ` @@ -271,14 +303,18 @@ func Echo(msg string) string { return "echo:"+msg }`}, } - pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } + + msg1 := NewMsgAddPackage(addr, modfile, files) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) // Run Echo function. coins := std.MustParseCoins("9000000ugnot") - msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) + msg2 := NewMsgCall(addr, coins, pkgPath, modfile.Version, "Echo", []string{"hello world"}) // XXX change this into an error and make sure error message is descriptive. _, err = env.vmk.Call(ctx, msg2) assert.Error(t, err) @@ -296,6 +332,8 @@ func TestVMKeeperOrigCallerInit(t *testing.T) { env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + pkgPath := "gno.land/r/test" + // Create test package. files := []*std.MemFile{ {"init.gno", ` @@ -324,14 +362,18 @@ func GetAdmin() string { `}, } - pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } + + msg1 := NewMsgAddPackage(addr, modfile, files) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) // Run GetAdmin() coins := std.MustParseCoins("") - msg2 := NewMsgCall(addr, coins, pkgPath, "GetAdmin", []string{}) + msg2 := NewMsgCall(addr, coins, pkgPath, modfile.Version, "GetAdmin", []string{}) res, err := env.vmk.Call(ctx, msg2) addrString := fmt.Sprintf("(\"%s\" string)", addr.String()) assert.NoError(t, err) @@ -348,6 +390,7 @@ func TestVMKeeperRunSimple(t *testing.T) { acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) + pkgPath := "gno.land/r/test" files := []*std.MemFile{ {"script.gno", ` package main @@ -357,9 +400,13 @@ func main() { } `}, } + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } coins := std.MustParseCoins("") - msg2 := NewMsgRun(addr, coins, files) + msg2 := NewMsgRun(addr, coins, modfile, files) res, err := env.vmk.Run(ctx, msg2) assert.NoError(t, err) assert.Equal(t, res, "hello world!\n") @@ -375,6 +422,7 @@ func TestVMKeeperRunImportStdlibs(t *testing.T) { acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) + pkgPath := "gno.land/r/test" files := []*std.MemFile{ {"script.gno", ` package main @@ -387,9 +435,13 @@ func main() { } `}, } + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } coins := std.MustParseCoins("") - msg2 := NewMsgRun(addr, coins, files) + msg2 := NewMsgRun(addr, coins, modfile, files) res, err := env.vmk.Run(ctx, msg2) assert.NoError(t, err) expectedString := fmt.Sprintf("hello world! %s\n", addr.String()) @@ -421,13 +473,17 @@ func Echo(msg string) string { }, } pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) + modfile := &std.MemMod{ + ImportPath: pkgPath, + Version: "v0.0.0", + } + msg1 := NewMsgAddPackage(addr, modfile, files) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) // Call Echo function with wrong number of arguments coins := std.MustParseCoins("1ugnot") - msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world", "extra arg"}) + msg2 := NewMsgCall(addr, coins, pkgPath, modfile.Version, "Echo", []string{"hello world", "extra arg"}) assert.PanicsWithValue( t, func() { diff --git a/gno.land/pkg/sdk/vm/msgs.go b/gno.land/pkg/sdk/vm/msgs.go index e42babe1510..75e449c6390 100644 --- a/gno.land/pkg/sdk/vm/msgs.go +++ b/gno.land/pkg/sdk/vm/msgs.go @@ -9,6 +9,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/sdk" "github.com/gnolang/gno/tm2/pkg/std" + "golang.org/x/mod/semver" ) //---------------------------------------- @@ -24,7 +25,7 @@ type MsgAddPackage struct { var _ std.Msg = MsgAddPackage{} // NewMsgAddPackage - upload a package with files. -func NewMsgAddPackage(creator crypto.Address, pkgPath string, files []*std.MemFile) MsgAddPackage { +func NewMsgAddPackage(creator crypto.Address, modfile *std.MemMod, files []*std.MemFile) MsgAddPackage { var pkgName string for _, file := range files { if strings.HasSuffix(file.Name, ".gno") { @@ -35,9 +36,9 @@ func NewMsgAddPackage(creator crypto.Address, pkgPath string, files []*std.MemFi return MsgAddPackage{ Creator: creator, Package: &std.MemPackage{ - Name: pkgName, - Path: pkgPath, - Files: files, + Name: pkgName, + ModFile: modfile, + Files: files, }, } } @@ -53,9 +54,13 @@ func (msg MsgAddPackage) ValidateBasic() error { if msg.Creator.IsZero() { return std.ErrInvalidAddress("missing creator address") } - if msg.Package.Path == "" { // XXX + if msg.Package.ModFile.ImportPath == "" { // XXX return ErrInvalidPkgPath("missing package path") } + if !semver.IsValid(msg.Package.ModFile.Version) { + // TODO(hariom): Only allow MAJOR.MINOR.PATCH, don't allow metadata? + return ErrInvalidPkgVersion("") + } if !msg.Deposit.IsValid() { return std.ErrTxDecode("invalid deposit") } @@ -83,22 +88,24 @@ func (msg MsgAddPackage) GetReceived() std.Coins { // MsgCall - executes a Gno statement. type MsgCall struct { - Caller crypto.Address `json:"caller" yaml:"caller"` - Send std.Coins `json:"send" yaml:"send"` - PkgPath string `json:"pkg_path" yaml:"pkg_path"` - Func string `json:"func" yaml:"func"` - Args []string `json:"args" yaml:"args"` + Caller crypto.Address `json:"caller" yaml:"caller"` + Send std.Coins `json:"send" yaml:"send"` + PkgPath string `json:"pkg_path" yaml:"pkg_path"` + PkgVersion string `json:"pkg_version" yaml:"pkg_version"` + Func string `json:"func" yaml:"func"` + Args []string `json:"args" yaml:"args"` } var _ std.Msg = MsgCall{} -func NewMsgCall(caller crypto.Address, send sdk.Coins, pkgPath, fnc string, args []string) MsgCall { +func NewMsgCall(caller crypto.Address, send sdk.Coins, pkgPath, pkgVersion, fnc string, args []string) MsgCall { return MsgCall{ - Caller: caller, - Send: send, - PkgPath: pkgPath, - Func: fnc, - Args: args, + Caller: caller, + Send: send, + PkgPath: pkgPath, + PkgVersion: pkgVersion, + Func: fnc, + Args: args, } } @@ -116,6 +123,10 @@ func (msg MsgCall) ValidateBasic() error { if msg.PkgPath == "" { // XXX return ErrInvalidPkgPath("missing package path") } + if !semver.IsValid(msg.PkgVersion) { + // TODO(hariom): Only allow MAJOR.MINOR.PATCH, don't allow metadata? + return ErrInvalidPkgVersion("") + } if msg.Func == "" { // XXX return ErrInvalidExpr("missing function to call") } @@ -149,7 +160,7 @@ type MsgRun struct { var _ std.Msg = MsgRun{} -func NewMsgRun(caller crypto.Address, send std.Coins, files []*std.MemFile) MsgRun { +func NewMsgRun(caller crypto.Address, send std.Coins, modfile *std.MemMod, files []*std.MemFile) MsgRun { for _, file := range files { if strings.HasSuffix(file.Name, ".gno") { pkgName := string(gno.PackageNameFromFileBody(file.Name, file.Body)) @@ -162,8 +173,11 @@ func NewMsgRun(caller crypto.Address, send std.Coins, files []*std.MemFile) MsgR Caller: caller, Send: send, Package: &std.MemPackage{ - Name: "main", - Path: "", // auto set by the handler + Name: "main", + ModFile: &std.MemMod{ // TODO(hariom): use arg `modfile` + ImportPath: "", // auto set by the handler + Version: "", + }, Files: files, }, } @@ -183,7 +197,7 @@ func (msg MsgRun) ValidateBasic() error { // Force memPkg path to the reserved run path. wantPath := "gno.land/r/" + msg.Caller.String() + "/run" - if path := msg.Package.Path; path != "" && path != wantPath { + if path := msg.Package.ModFile.ImportPath; path != "" && path != wantPath { return ErrInvalidPkgPath(fmt.Sprintf("invalid pkgpath for MsgRun: %q", path)) } diff --git a/gnovm/cmd/gno/lint.go b/gnovm/cmd/gno/lint.go index e2a7e53fb69..d643aa33371 100644 --- a/gnovm/cmd/gno/lint.go +++ b/gnovm/cmd/gno/lint.go @@ -129,6 +129,7 @@ func execLint(cfg *lintCfg, args []string, io commands.IO) error { } } + // TODO(hariom): gno lint is failing because of this? tm.RunFiles(testfiles.Files...) }) diff --git a/gnovm/cmd/gno/mod.go b/gnovm/cmd/gno/mod.go index 6c310cd7425..75dfa11f339 100644 --- a/gnovm/cmd/gno/mod.go +++ b/gnovm/cmd/gno/mod.go @@ -11,9 +11,11 @@ import ( "sort" "strings" + "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/errors" + "golang.org/x/mod/module" ) type modDownloadCfg struct { @@ -204,13 +206,70 @@ func execModInit(args []string) error { if err != nil { return err } - if err := gnomod.CreateGnoModFile(dir, modPath); err != nil { + if err := CreateGnoModFile(dir, modPath); err != nil { return fmt.Errorf("create gno.mod file: %w", err) } return nil } +func CreateGnoModFile(rootDir, modPath string) error { + if !filepath.IsAbs(rootDir) { + return fmt.Errorf("dir %q is not absolute", rootDir) + } + + modFilePath := filepath.Join(rootDir, "gno.mod") + if _, err := os.Stat(modFilePath); err == nil { + return errors.New("gno.mod file already exists") + } + + if modPath == "" { + // Check .gno files for package name + // and use it as modPath + files, err := os.ReadDir(rootDir) + if err != nil { + return fmt.Errorf("read dir %q: %w", rootDir, err) + } + + var pkgName gnolang.Name + for _, file := range files { + if file.IsDir() || !strings.HasSuffix(file.Name(), ".gno") || strings.HasSuffix(file.Name(), "_filetest.gno") { + continue + } + + fpath := filepath.Join(rootDir, file.Name()) + bz, err := os.ReadFile(fpath) + if err != nil { + return fmt.Errorf("read file %q: %w", fpath, err) + } + + pn := gnolang.PackageNameFromFileBody(file.Name(), string(bz)) + if strings.HasSuffix(string(pkgName), "_test") { + pkgName = pkgName[:len(pkgName)-len("_test")] + } + if pkgName == "" { + pkgName = pn + } + if pkgName != pn { + return fmt.Errorf("package name mismatch: [%q] and [%q]", pkgName, pn) + } + } + if pkgName == "" { + return errors.New("cannot determine package name") + } + modPath = string(pkgName) + } + if err := module.CheckImportPath(modPath); err != nil { + return err + } + + modfile := new(gnomod.File) + modfile.AddModuleStmt(modPath) + modfile.Write(filepath.Join(rootDir, "gno.mod")) + + return nil +} + func execModTidy(args []string, io commands.IO) error { if len(args) > 0 { return flag.ErrHelp @@ -240,7 +299,7 @@ func execModTidy(args []string, io commands.IO) error { if im == gm.Module.Mod.Path { continue } - gm.AddRequire(im, "v0.0.0-latest") + gm.AddRequire(im, "v0.0.0") } gm.Write(fname) diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index bff6faac0bd..f223ddc9ff1 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -378,7 +378,7 @@ func gnoTestPkg( memPkg.Files = memFiles memPkg.Name = testPkgName - memPkg.Path = memPkg.Path + "_test" + memPkg.ModFile.ImportPath = memPkg.ModFile.ImportPath + "_test" m.RunMemPackage(memPkg, true) err := runTestFiles(m, ifiles, testPkgName, verbose, printRuntimeMetrics, runFlag, io) diff --git a/gnovm/pkg/doc/testdata/dirsmod/gno.mod b/gnovm/pkg/doc/testdata/dirsmod/gno.mod index 6c8008b958c..ae0f196e5eb 100644 --- a/gnovm/pkg/doc/testdata/dirsmod/gno.mod +++ b/gnovm/pkg/doc/testdata/dirsmod/gno.mod @@ -1,5 +1,5 @@ module dirs.mod/prefix require ( - dirs.mod/dep v0.0.0 + dirs.mod/dep v0.1.0 ) diff --git a/gnovm/pkg/gnolang/frame.go b/gnovm/pkg/gnolang/frame.go index 7f87fa26097..79d1c41faa9 100644 --- a/gnovm/pkg/gnolang/frame.go +++ b/gnovm/pkg/gnolang/frame.go @@ -39,7 +39,7 @@ func (fr Frame) String() string { fr.NumExprs, fr.NumStmts, fr.NumBlocks, - fr.LastPackage.PkgPath, + fr.LastPackage.ModFile.Path, fr.LastRealm) } else if fr.GoFunc != nil { return fmt.Sprintf("[FRAME GOFUNC:%v RECV:%s (%d args) %d/%d/%d/%d/%d]", diff --git a/gnovm/pkg/gnolang/gno_test.go b/gnovm/pkg/gnolang/gno_test.go index d8bdcdfd4a0..6a11fbe7d76 100644 --- a/gnovm/pkg/gnolang/gno_test.go +++ b/gnovm/pkg/gnolang/gno_test.go @@ -21,7 +21,7 @@ import ( func TestRunEmptyMain(t *testing.T) { t.Parallel() - m := NewMachine("test", nil) + m := NewMachine("test", "", nil) // []Stmt{} != nil, as nil means that in the source code not even the // brackets are present and is reserved for external (ie. native) functions. main := FuncD("main", nil, nil, []Stmt{}) @@ -33,7 +33,7 @@ func TestRunEmptyMain(t *testing.T) { func TestRunLoopyMain(t *testing.T) { t.Parallel() - m := NewMachine("test", nil) + m := NewMachine("test", "", nil) c := `package test func main() { for i:=0; i<1000; i++ { @@ -48,7 +48,7 @@ func main() { } func TestDoOpEvalBaseConversion(t *testing.T) { - m := NewMachine("test", nil) + m := NewMachine("test", "", nil) type testCase struct { input string @@ -119,7 +119,7 @@ func TestDoOpEvalBaseConversion(t *testing.T) { func TestEval(t *testing.T) { t.Parallel() - m := NewMachine("test", nil) + m := NewMachine("test", "", nil) c := `package test func next(i int) int { return i+1 @@ -200,7 +200,9 @@ func main() { func BenchmarkPreprocess(b *testing.B) { pkg := &PackageNode{ PkgName: "main", - PkgPath: ".main", + ModFile: &ModFileNode{ + Path: ".main", + }, FileSet: nil, } pkg.InitStaticBlock(pkg, nil) diff --git a/gnovm/pkg/gnolang/gonative_test.go b/gnovm/pkg/gnolang/gonative_test.go index e348ffe9c22..6ef6e35ad2e 100644 --- a/gnovm/pkg/gnolang/gonative_test.go +++ b/gnovm/pkg/gnolang/gonative_test.go @@ -19,7 +19,7 @@ func gonativeTestStore(args ...interface{}) Store { for i := 0; i < len(args)/2; i++ { pn := args[i*2].(*PackageNode) pv := args[i*2+1].(*PackageValue) - if pkgPath == pv.PkgPath { + if pkgPath == pv.ModFile.Path { return pn, pv } } @@ -38,7 +38,7 @@ type Foo struct { func TestGoNativeDefine(t *testing.T) { // Create package foo and define Foo. - pkg := NewPackageNode("foo", "test.foo", nil) + pkg := NewPackageNode("foo", &ModFileNode{Path: "test.gno"}, nil) rt := reflect.TypeOf(Foo{}) pkg.DefineGoNativeType(rt) nt := pkg.GetValueRef(nil, Name("Foo")).GetType().(*NativeType) @@ -64,7 +64,7 @@ func TestGoNativeDefine(t *testing.T) { func TestGoNativeDefine2(t *testing.T) { // Create package foo and define Foo. - pkg := NewPackageNode("foo", "test.foo", nil) + pkg := NewPackageNode("foo", &ModFileNode{Path: "test.gno"}, nil) rt := reflect.TypeOf(Foo{}) pkg.DefineGoNativeType(rt) pv := pkg.NewPackage() @@ -102,7 +102,7 @@ func TestGoNativeDefine3(t *testing.T) { // Create package foo and define Foo. out := new(bytes.Buffer) - pkg := NewPackageNode("foo", "test.foo", nil) + pkg := NewPackageNode("foo", &ModFileNode{Path: "test.gno"}, nil) pkg.DefineGoNativeType(reflect.TypeOf(Foo{})) pkg.DefineGoNativeValue("PrintFoo", func(f Foo) { out.Write([]byte(fmt.Sprintf("A: %v\n", f.A))) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index e9e8eba8adc..6f1eb3b9a7b 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -14,6 +14,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/std" + "golang.org/x/mod/semver" ) //---------------------------------------- @@ -55,11 +56,12 @@ type Machine struct { // // Like for [NewMachineWithOptions], Machines initialized through this // constructor must be finalized with [Machine.Release]. -func NewMachine(pkgPath string, store Store) *Machine { +func NewMachine(pkgPath, pkgVersion string, store Store) *Machine { return NewMachineWithOptions( MachineOptions{ - PkgPath: pkgPath, - Store: store, + PkgPath: pkgPath, + PkgVersion: pkgVersion, + Store: store, }) } @@ -67,6 +69,7 @@ func NewMachine(pkgPath string, store Store) *Machine { type MachineOptions struct { // Active package of the given machine; must be set before execution. PkgPath string + PkgVersion string CheckTypes bool // not yet used ReadOnly bool Output io.Writer // default os.Stdout @@ -114,10 +117,13 @@ func NewMachineWithOptions(opts MachineOptions) *Machine { } pv := (*PackageValue)(nil) if opts.PkgPath != "" { - pv = store.GetPackage(opts.PkgPath, false) + pv = store.GetPackage(opts.PkgPath, opts.PkgVersion, false) if pv == nil { pkgName := defaultPkgName(opts.PkgPath) - pn := NewPackageNode(pkgName, opts.PkgPath, &FileSet{}) + pn := NewPackageNode(pkgName, &ModFileNode{ + Path: opts.PkgPath, + Version: opts.PkgVersion, + }, &FileSet{}) pv = pn.NewPackage() store.SetBlockNode(pn) store.SetCachePackage(pv) @@ -186,28 +192,35 @@ func (m *Machine) SetActivePackage(pv *PackageValue) { // NOTE: package paths not beginning with gno.land will be allowed to override, // to support cases of stdlibs processed through [RunMemPackagesWithOverrides]. func (m *Machine) PreprocessAllFilesAndSaveBlockNodes() { - ch := m.Store.IterMemPackage() - for memPkg := range ch { - fset := ParseMemPackage(memPkg) - pn := NewPackageNode(Name(memPkg.Name), memPkg.Path, fset) - m.Store.SetBlockNode(pn) - PredefineFileSet(m.Store, pn, fset) - for _, fn := range fset.Files { - // Save Types to m.Store (while preprocessing). - fn = Preprocess(m.Store, pn, fn).(*FileNode) - // Save BlockNodes to m.Store. - SaveBlockNodes(m.Store, fn) - } - // Normally, the fileset would be added onto the - // package node only after runFiles(), but we cannot - // run files upon restart (only preprocess them). - // So, add them here instead. - // TODO: is this right? - if pn.FileSet == nil { - pn.FileSet = fset - } else { - // This happens for non-realm file tests. - // TODO ensure the files are the same. + ch := m.Store.IterMemPackageInfo() + for memPkgInfo := range ch { + for _, ver := range memPkgInfo.Versions { + fset := ParseMemPackage(ver) + mfn := &ModFileNode{ + Path: ver.ModFile.ImportPath, + Version: ver.ModFile.Version, + Require: ver.ModFile.Requires, + } + pn := NewPackageNode(Name(ver.Name), mfn, fset) + m.Store.SetBlockNode(pn) + PredefineFileSet(m.Store, pn, fset) + for _, fn := range fset.Files { + // Save Types to m.Store (while preprocessing). + fn = Preprocess(m.Store, pn, fn).(*FileNode) + // Save BlockNodes to m.Store. + SaveBlockNodes(m.Store, fn) + } + // Normally, the fileset would be added onto the + // package node only after runFiles(), but we cannot + // run files upon restart (only preprocess them). + // So, add them here instead. + // TODO: is this right? + if pn.FileSet == nil { + pn.FileSet = fset + } else { + // This happens for non-realm file tests. + // TODO ensure the files are the same. + } } } } @@ -234,17 +247,26 @@ func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (* // parse files. files := ParseMemPackage(memPkg) if !overrides && checkDuplicates(files) { - panic(fmt.Errorf("running package %q: duplicate declarations not allowed", memPkg.Path)) + panic(fmt.Errorf("running package %q: duplicate declarations not allowed", memPkg.ModFile.ImportPath)) } // make and set package if doesn't exist. pn := (*PackageNode)(nil) pv := (*PackageValue)(nil) - if m.Package != nil && m.Package.PkgPath == memPkg.Path { + // panic("stop: " + memPkg.ModFile.ImportPath + " " + memPkg.ModFile.Version) + if m.Package != nil && + m.Package.ModFile.Path == memPkg.ModFile.ImportPath { + // m.Package.ModFile.Version == memPkg.ModFile.Version { + fmt.Println() pv = m.Package - loc := PackageNodeLocation(memPkg.Path) + loc := PackageNodeLocation(memPkg.ModFile.ImportPath, memPkg.ModFile.Version) pn = m.Store.GetBlockNode(loc).(*PackageNode) } else { - pn = NewPackageNode(Name(memPkg.Name), memPkg.Path, &FileSet{}) + mfn := &ModFileNode{ + Path: memPkg.ModFile.ImportPath, + Version: memPkg.ModFile.Version, + Require: memPkg.ModFile.Requires, + } + pn = NewPackageNode(Name(memPkg.Name), mfn, &FileSet{}) pv = pn.NewPackage() m.Store.SetBlockNode(pn) m.Store.SetCachePackage(pv) @@ -254,10 +276,31 @@ func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (* m.RunFiles(files.Files...) // maybe save package value and mempackage. if save { + memPkgInfo, err := m.Store.GetMemPackageInfo(memPkg.ModFile.ImportPath) + if err != nil { + memPkgInfo = &std.MemPackageInfo{ + Name: memPkg.Name, + Path: memPkg.ModFile.ImportPath, + Versions: []*std.MemPackage{memPkg}, + } + } else { + versionCount := len(memPkgInfo.Versions) + if versionCount < 1 { + panic("empty memPackageInfo") + } + latest := memPkgInfo.Versions[versionCount-1] + if semver.Compare(memPkg.ModFile.Version, latest.ModFile.Version) <= 0 { + panic(fmt.Sprintf("version should be greater then %q", latest.ModFile.Version)) + } + memPkgInfo.Versions = append(memPkgInfo.Versions, memPkg) + } + // store package values and types m.savePackageValuesAndTypes() // store mempackage - m.Store.AddMemPackage(memPkg) + // TODO(hariom): Maintain 2 separate entries? to save gas cost? + // MemPackageInfo and Mempackage? + m.Store.AddMemPackageInfo(memPkgInfo) } return pn, pv } @@ -324,7 +367,7 @@ func (m *Machine) TestMemPackage(t *testing.T, memPkg *std.MemPackage) { // parse test files. tfiles, itfiles := ParseMemPackageTests(memPkg) { // first, tfiles which run in the same package. - pv := m.Store.GetPackage(memPkg.Path, false) + pv := m.Store.GetPackage(memPkg.ModFile.ImportPath, memPkg.ModFile.Version, false) pvBlock := pv.GetBlock(m.Store) pvSize := len(pvBlock.Values) m.SetActivePackage(pv) @@ -337,7 +380,12 @@ func (m *Machine) TestMemPackage(t *testing.T, memPkg *std.MemPackage) { } } { // run all (import) tests in test files. - pn := NewPackageNode(Name(memPkg.Name+"_test"), memPkg.Path+"_test", itfiles) + mfn := &ModFileNode{ + Path: memPkg.ModFile.ImportPath + "_test", + Version: memPkg.ModFile.Version, + Require: memPkg.ModFile.Requires, + } + pn := NewPackageNode(Name(memPkg.Name+"_test"), mfn, itfiles) pv := pn.NewPackage() m.Store.SetBlockNode(pn) m.Store.SetCachePackage(pv) @@ -364,7 +412,7 @@ func (m *Machine) TestFunc(t *testing.T, tv TypedValue) { // XXX ensure correct func type. name := string(tv.V.(*FuncValue).Name) // prefetch the testing package. - testingpv := m.Store.GetPackage("testing", false) + testingpv := m.Store.GetPackage("testing", "", false) testingtv := TypedValue{T: gPackageType, V: testingpv} testingcx := &ConstExpr{TypedValue: testingtv} @@ -494,6 +542,7 @@ func (m *Machine) runFiles(fns ...*FileNode) { } // Predefine declarations across all files. + // TODO(hariom): Resolve import version PredefineFileSet(m.Store, pn, fs) // Preprocess each new file. @@ -624,7 +673,7 @@ func (m *Machine) savePackageValuesAndTypes() { // save package realm info. m.Store.SetPackageRealm(rlm) } else { // use a throwaway realm. - rlm := NewRealm(pv.PkgPath) + rlm := NewRealm(pv.ModFile.Path, pv.ModFile.Version) rlm.MarkNewReal(pv) rlm.FinalizeRealmTransaction(m.ReadOnly, m.Store) } @@ -1688,7 +1737,7 @@ func (m *Machine) PushFrameCall(cx *CallExpr, fv *FuncValue, recv TypedValue) { m.Frames = append(m.Frames, fr) pv := fv.GetPackage(m.Store) if pv == nil { - panic(fmt.Sprintf("package value missing in store: %s", fv.PkgPath)) + panic(fmt.Sprintf("package value missing in store: %s(%s)", fv.PkgPath, fv.PkgVersion)) } m.Package = pv rlm := pv.GetRealm() @@ -1976,7 +2025,7 @@ func (m *Machine) String() string { if pv, ok := b.Source.(*PackageNode); ok { // package blocks have too much, so just // print the pkgpath. - bs = append(bs, fmt.Sprintf(" %s(%d) %s", gens, gen, pv.PkgPath)) + bs = append(bs, fmt.Sprintf(" %s(%d) %s", gens, gen, pv.ModFile.Path)) } else { bsi := b.StringIndented(" ") bs = append(bs, fmt.Sprintf(" %s(%d) %s", gens, gen, bsi)) diff --git a/gnovm/pkg/gnolang/machine_test.go b/gnovm/pkg/gnolang/machine_test.go index c9f1f9ba10d..3668a6cc739 100644 --- a/gnovm/pkg/gnolang/machine_test.go +++ b/gnovm/pkg/gnolang/machine_test.go @@ -26,10 +26,12 @@ func TestRunMemPackageWithOverrides_revertToOld(t *testing.T) { baseStore := dbadapter.StoreConstructor(db, stypes.StoreOptions{}) iavlStore := iavl.StoreConstructor(db, stypes.StoreOptions{}) store := NewStore(nil, baseStore, iavlStore) - m := NewMachine("std", store) + m := NewMachine("std", "", store) m.RunMemPackageWithOverrides(&std.MemPackage{ Name: "std", - Path: "std", + ModFile: &std.MemMod{ + ImportPath: "std", + }, Files: []*std.MemFile{ {Name: "a.gno", Body: `package std; func Redecl(x int) string { return "1" }`}, }, @@ -40,7 +42,9 @@ func TestRunMemPackageWithOverrides_revertToOld(t *testing.T) { }() m.RunMemPackageWithOverrides(&std.MemPackage{ Name: "std", - Path: "std", + ModFile: &std.MemMod{ + ImportPath: "std", + }, Files: []*std.MemFile{ {Name: "b.gno", Body: `package std; func Redecl(x int) string { var y string; _, _ = y; return "2" }`}, }, diff --git a/gnovm/pkg/gnolang/misc.go b/gnovm/pkg/gnolang/misc.go index a05de8c74aa..dcaef1413f5 100644 --- a/gnovm/pkg/gnolang/misc.go +++ b/gnovm/pkg/gnolang/misc.go @@ -163,7 +163,7 @@ func isUverseName(n Name) bool { // other // For keeping record of package & realm coins. -func DerivePkgAddr(pkgPath string) crypto.Address { +func DerivePkgAddr(pkgPath, pkgVersion string) crypto.Address { // NOTE: must not collide with pubkey addrs. - return crypto.AddressFromPreimage([]byte("pkgPath:" + pkgPath)) + return crypto.AddressFromPreimage([]byte("pkgPath:" + pkgPath + "@" + pkgVersion)) } diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 8f2c5054a8a..c72952afa38 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -116,6 +116,7 @@ type Name string type Location struct { PkgPath string + Version string File string Line int Nonce int @@ -123,14 +124,16 @@ type Location struct { func (loc Location) String() string { if loc.Nonce == 0 { - return fmt.Sprintf("%s/%s:%d", + return fmt.Sprintf("%s@%s/%s:%d", loc.PkgPath, + loc.Version, loc.File, loc.Line, ) } else { - return fmt.Sprintf("%s/%s:%d#%d", + return fmt.Sprintf("%s@%s/%s:%d#%d", loc.PkgPath, + loc.Version, loc.File, loc.Line, loc.Nonce, @@ -140,6 +143,7 @@ func (loc Location) String() string { func (loc Location) IsZero() bool { return loc.PkgPath == "" && + loc.Version == "" && loc.File == "" && loc.Line == 0 && loc.Nonce == 0 @@ -1134,8 +1138,22 @@ func ReadMemPackage(dir string, pkgPath string) *std.MemPackage { // NOTE: panics if package name is invalid (characters must be alphanumeric or _, // lowercase, and must start with a letter). func ReadMemPackageFromList(list []string, pkgPath string) *std.MemPackage { - memPkg := &std.MemPackage{Path: pkgPath} + memPkg := &std.MemPackage{ModFile: &std.MemMod{ + ImportPath: pkgPath, + }} var pkgName Name + // read modfile + // TODO(hariom): improve + if len(list) < 1 { + panic("requires alteast 1 file") + } + dir := filepath.Dir(list[0]) + // skip stdlibs, as they dont contains gno.mod file + if !strings.Contains(dir, "/stdlibs/") { // TODO(hariom): find a better way + gm := ParseMemMod(dir) + memPkg.ModFile = gm + } + for _, fpath := range list { fname := filepath.Base(fpath) bz, err := os.ReadFile(fpath) @@ -1149,6 +1167,7 @@ func ReadMemPackageFromList(list []string, pkgPath string) *std.MemPackage { pkgName = pkgName[:len(pkgName)-len("_test")] } } + memPkg.Files = append(memPkg.Files, &std.MemFile{ Name: fname, @@ -1161,6 +1180,9 @@ func ReadMemPackageFromList(list []string, pkgPath string) *std.MemPackage { validatePkgName(string(pkgName)) memPkg.Name = string(pkgName) } + if memPkg.ModFile.ImportPath == "" { + panic("empty importpath") + } return memPkg } @@ -1294,29 +1316,36 @@ type FileNode struct { Decls } +type ModFileNode struct { + Path string + Version string + Require []*std.Requirements +} + type PackageNode struct { Attributes StaticBlock - PkgPath string PkgName Name + ModFile *ModFileNode *FileSet } -func PackageNodeLocation(path string) Location { +func PackageNodeLocation(path, version string) Location { return Location{ PkgPath: path, + Version: version, File: "", Line: 0, } } -func NewPackageNode(name Name, path string, fset *FileSet) *PackageNode { +func NewPackageNode(name Name, modFile *ModFileNode, fset *FileSet) *PackageNode { pn := &PackageNode{ - PkgPath: path, PkgName: name, + ModFile: modFile, FileSet: fset, } - pn.SetLocation(PackageNodeLocation(path)) + pn.SetLocation(PackageNodeLocation(modFile.Path, modFile.Version)) pn.InitStaticBlock(pn, nil) return pn } @@ -1327,13 +1356,13 @@ func (x *PackageNode) NewPackage() *PackageValue { Source: x, }, PkgName: x.PkgName, - PkgPath: x.PkgPath, + ModFile: x.ModFile.Copy(), FNames: nil, FBlocks: nil, fBlocksMap: make(map[Name]*Block), } - if IsRealmPath(x.PkgPath) { - rlm := NewRealm(x.PkgPath) + if IsRealmPath(x.ModFile.Path) { + rlm := NewRealm(x.ModFile.Path, x.ModFile.Version) pv.SetRealm(rlm) } pv.IncRefCount() // all package values have starting ref count of 1. @@ -1348,7 +1377,7 @@ func (x *PackageNode) NewPackage() *PackageValue { // NOTE: declared methods do not get their closures set here. See // *DeclaredType.GetValueAt() which returns a filled copy. func (x *PackageNode) PrepareNewValues(pv *PackageValue) []TypedValue { - if pv.PkgPath == "" { + if pv.ModFile.Path == "" { // nothing to prepare for throwaway packages. // TODO: double check to see if still relevant. return nil @@ -1357,7 +1386,7 @@ func (x *PackageNode) PrepareNewValues(pv *PackageValue) []TypedValue { block := pv.Block.(*Block) if block.Source != x { // special case if block.Source is ref node - if ref, ok := block.Source.(RefNode); ok && ref.Location == PackageNodeLocation(pv.PkgPath) { + if ref, ok := block.Source.(RefNode); ok && ref.Location == PackageNodeLocation(pv.ModFile.Path, pv.ModFile.Version) { // this is fine } else { panic("PackageNode.PrepareNewValues() package mismatch") diff --git a/gnovm/pkg/gnolang/nodes_copy.go b/gnovm/pkg/gnolang/nodes_copy.go index e8d7dbb31ec..d8da9541142 100644 --- a/gnovm/pkg/gnolang/nodes_copy.go +++ b/gnovm/pkg/gnolang/nodes_copy.go @@ -1,5 +1,7 @@ package gnolang +import "github.com/gnolang/gno/tm2/pkg/std" + // Copy should happen before any preprocessing. // * Attributes are not copied. // * Paths are not copied. @@ -369,12 +371,27 @@ func (x *FileNode) Copy() Node { func (x *PackageNode) Copy() Node { return &PackageNode{ - PkgPath: x.PkgPath, PkgName: x.PkgName, + ModFile: x.ModFile.Copy(), FileSet: x.FileSet.CopyFileSet(), } } +func (x *ModFileNode) Copy() *ModFileNode { + req := make([]*std.Requirements, 0) + for _, r := range x.Require { + req = append(req, &std.Requirements{ + Path: r.Path, + Version: r.Version, + }) + } + return &ModFileNode{ + Path: x.Path, + Version: x.Version, + Require: req, + } +} + // ---------------------------------------- // misc diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index b3bf240aea1..bb9d2c1b027 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -621,10 +621,10 @@ func (m *Machine) doOpStructLit() { // package doesn't match, we cannot use this // method to initialize the struct. if FieldTypeList(st.Fields).HasUnexported() && - st.PkgPath != m.Package.PkgPath { + st.PkgPath != m.Package.ModFile.Path { panic(fmt.Sprintf( "Cannot initialize imported struct %s.%s with nameless composite lit expression (has unexported fields) from package %s", - st.PkgPath, st.String(), m.Package.PkgPath)) + st.PkgPath, st.String(), m.Package.ModFile.Path)) } else { // this is fine. } @@ -690,7 +690,8 @@ func (m *Machine) doOpFuncLit() { Source: x, Name: "", Closure: lb, - PkgPath: m.Package.PkgPath, + PkgPath: m.Package.ModFile.Path, + PkgVersion: m.Package.ModFile.Version, body: x.Body, nativeBody: nil, }, diff --git a/gnovm/pkg/gnolang/op_types.go b/gnovm/pkg/gnolang/op_types.go index a38010bac4e..247c3b83007 100644 --- a/gnovm/pkg/gnolang/op_types.go +++ b/gnovm/pkg/gnolang/op_types.go @@ -121,7 +121,7 @@ func (m *Machine) doOpStructType() { } // push struct type st := &StructType{ - PkgPath: m.Package.PkgPath, + PkgPath: m.Package.ModFile.Path, Fields: fields, } m.PushValue(TypedValue{ @@ -142,7 +142,7 @@ func (m *Machine) doOpInterfaceType() { } // push interface type it := &InterfaceType{ - PkgPath: m.Package.PkgPath, + PkgPath: m.Package.ModFile.Path, Methods: methods, Generic: x.Generic, } diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index ca58071331e..63ed0819638 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" "reflect" + "strings" "github.com/gnolang/gno/tm2/pkg/errors" ) @@ -15,7 +16,7 @@ import ( func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { // First, initialize all file nodes and connect to package node. for _, fn := range fset.Files { - SetNodeLocations(pn.PkgPath, string(fn.Name), fn) + SetNodeLocations(pn.ModFile.Path, pn.ModFile.Version, string(fn.Name), fn) fn.InitStaticBlock(fn, pn) } // NOTE: much of what follows is duplicated for a single *FileNode @@ -133,9 +134,11 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // if n is file node, set node locations recursively. if fn, ok := n.(*FileNode); ok { - pkgPath := ctx.(*PackageNode).PkgPath + pn := ctx.(*PackageNode) + pkgPath := pn.ModFile.Path + pkgVersion := pn.ModFile.Version fileName := string(fn.Name) - SetNodeLocations(pkgPath, fileName, fn) + SetNodeLocations(pkgPath, pkgVersion, fileName, fn) } // create stack of BlockNodes. @@ -1345,10 +1348,10 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // Set selector path based on xt's type. switch cxt := xt.(type) { case *PointerType, *DeclaredType, *StructType, *InterfaceType: - tr, _, rcvr, _, aerr := findEmbeddedFieldType(lastpn.PkgPath, cxt, n.Sel, nil) + tr, _, rcvr, _, aerr := findEmbeddedFieldType(lastpn.ModFile.Path, cxt, n.Sel, nil) if aerr { panic(fmt.Sprintf("cannot access %s.%s from %s", - cxt.String(), n.Sel, lastpn.PkgPath)) + cxt.String(), n.Sel, lastpn.ModFile.Path)) } else if tr == nil { panic(fmt.Sprintf("missing field %s in %s", n.Sel, cxt.String())) @@ -1444,9 +1447,9 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { } pn := pv.GetPackageNode(store) // ensure exposed or package path match. - if !isUpper(string(n.Sel)) && lastpn.PkgPath != pv.PkgPath { + if !isUpper(string(n.Sel)) && lastpn.ModFile.Path != pv.ModFile.Path { panic(fmt.Sprintf("cannot access %s.%s from %s", - pv.PkgPath, n.Sel, lastpn.PkgPath)) + pv.ModFile.Path, n.Sel, lastpn.ModFile.Path)) } else { // NOTE: this can happen with software upgrades, // with multiple versions of the same package path. @@ -1927,7 +1930,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { *dst = *(tmp.(*StructType)) case *DeclaredType: // if store has this type, use that. - tid := DeclaredTypeID(lastpn.PkgPath, n.Name) + tid := DeclaredTypeID(lastpn.ModFile.Path, n.Name) exists := false if dt := store.GetTypeSafe(tid); dt != nil { dst = dt.(*DeclaredType) @@ -1939,7 +1942,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: this is where declared types are // actually instantiated, not in // machine.go:runDeclaration(). - dt2 := declareWith(lastpn.PkgPath, n.Name, tmp) + dt2 := declareWith(lastpn.ModFile.Path, n.Name, tmp) // if !n.IsAlias { // not sure why this was here. dt2.Seal() // } @@ -2020,12 +2023,12 @@ func evalStaticType(store Store, last BlockNode, x Expr) Type { } pn := packageOf(last) // See comment in evalStaticTypeOfRaw. - if store != nil && pn.PkgPath != uversePkgPath { + if store != nil && pn.ModFile.Path != uversePkgPath { pv := pn.NewPackage() // temporary store = store.Fork() store.SetCachePackage(pv) } - m := NewMachine(pn.PkgPath, store) + m := NewMachine(pn.ModFile.Path, pn.ModFile.Version, store) tv := m.EvalStatic(last, x) m.Release() if _, ok := tv.V.(TypeValue); !ok { @@ -2094,12 +2097,12 @@ func evalStaticTypeOfRaw(store Store, last BlockNode, x Expr) (t Type) { // and the preprocessor will panic when // package values are already there that weren't // yet predefined this time around. - if store != nil && pn.PkgPath != uversePkgPath { + if store != nil && pn.ModFile.Path != uversePkgPath { pv := pn.NewPackage() // temporary store = store.Fork() store.SetCachePackage(pv) } - m := NewMachine(pn.PkgPath, store) + m := NewMachine(pn.ModFile.Path, pn.ModFile.Version, store) t = m.EvalStaticTypeOf(last, x) m.Release() x.SetAttribute(ATTR_TYPEOF_VALUE, t) @@ -2195,7 +2198,7 @@ func getResultTypedValues(cx *CallExpr) []TypedValue { func evalConst(store Store, last BlockNode, x Expr) *ConstExpr { // TODO: some check or verification for ensuring x // is constant? From the machine? - cv := NewMachine(".dontcare", store) + cv := NewMachine(".dontcare", "", store) tv := cv.EvalStatic(last, x) cv.Release() cx := &ConstExpr{ @@ -2965,7 +2968,8 @@ func predefineNow2(store Store, last BlockNode, d Decl, m map[Name]struct{}) (De Name: cd.Name, Closure: nil, // set lazily. FileName: fileNameOf(last), - PkgPath: pkg.PkgPath, + PkgPath: pkg.ModFile.Path, + PkgVersion: pkg.ModFile.Version, body: cd.Body, nativeBody: nil, }) { @@ -3031,11 +3035,32 @@ func tryPredefine(store Store, last BlockNode, d Decl) (un Name) { // so value paths cannot be used here. switch d := d.(type) { case *ImportDecl: - pv := store.GetPackage(d.PkgPath, true) + pn := packageOf(last) + var version string + if strings.HasPrefix(d.PkgPath, "gno.land") { + for _, req := range pn.ModFile.Require { + if req.Path == d.PkgPath { + version = req.Version + break + } + } + // TODO(hariom): uncomment? + // It may cause problems in few cases + // - If package doen't contain gno.mod + // - Testing _filetest. Currently imports are covered by gno.mod + // if version == "" { + // panic(fmt.Sprintf( + // "cannot get version for package %s", + // d.PkgPath)) + // } + } + + // TODO(hariom): create helper + pv := store.GetPackage(d.PkgPath, version, true) // TODO(hariom): temp; fix if pv == nil { panic(fmt.Sprintf( - "unknown import path %s", - d.PkgPath)) + "unknown import path %s (%s)", + d.PkgPath, version)) } if d.Name == "" { // use default d.Name = pv.PkgName @@ -3150,7 +3175,7 @@ func tryPredefine(store Store, last BlockNode, d Decl) (un Name) { } else { // create new declared type. pn := packageOf(last) - t = declareWith(pn.PkgPath, d.Name, t) + t = declareWith(pn.ModFile.Path, d.Name, t) } // fill in later. last2.Define(d.Name, asValue(t)) @@ -3196,18 +3221,19 @@ func tryPredefine(store Store, last BlockNode, d Decl) (un Name) { Name: d.Name, Closure: nil, // set lazily. FileName: fileNameOf(last), - PkgPath: pkg.PkgPath, + PkgPath: pkg.ModFile.Path, + PkgVersion: pkg.ModFile.Version, body: d.Body, nativeBody: nil, } // NOTE: fv.body == nil means no body (ie. not even curly braces) // len(fv.body) == 0 could mean also {} (ie. no statements inside) if fv.body == nil && store != nil { - fv.nativeBody = store.GetNative(pkg.PkgPath, d.Name) + fv.nativeBody = store.GetNative(pkg.ModFile.Path, d.Name) if fv.nativeBody == nil { panic(fmt.Sprintf("function %s does not have a body but is not natively defined", d.Name)) } - fv.NativePkg = pkg.PkgPath + fv.NativePkg = pkg.ModFile.Path fv.NativeName = d.Name } pkg.Define(d.Name, TypedValue{ @@ -3571,12 +3597,13 @@ func findDependentNames(n Node, dst map[Name]struct{}) { // Iterate over all block nodes recursively and sets location information // based on sparse expectations, and ensures uniqueness of BlockNode.Locations. // Ensures uniqueness of BlockNode.Locations. -func SetNodeLocations(pkgPath string, fileName string, n Node) { +func SetNodeLocations(pkgPath, pkgVersion string, fileName string, n Node) { if n.GetAttribute(ATTR_LOCATIONED) == true { return // locations already set (typically n is a filenode). } - if pkgPath == "" || fileName == "" { - panic("missing package path or file name") + if pkgPath == "" || fileName == "" { // TODO(hariom): assert empty pkgVersion if not stdlib + panic(fmt.Sprintf("missing package path: %q(%q) or file name(%q)", + pkgPath, pkgVersion, fileName)) // TODO(hariom): better error } lastLine := 0 nextNonce := 0 @@ -3595,6 +3622,7 @@ func SetNodeLocations(pkgPath string, fileName string, n Node) { } loc := Location{ PkgPath: pkgPath, + Version: pkgVersion, File: fileName, Line: line, Nonce: nextNonce, @@ -3614,9 +3642,10 @@ func SaveBlockNodes(store Store, fn *FileNode) { // First, get the package and file names. pn := packageOf(fn) store.SetBlockNode(pn) - pkgPath := pn.PkgPath + pkgPath := pn.ModFile.Path + pkgVersion := pn.ModFile.Version fileName := string(fn.Name) - if pkgPath == "" || fileName == "" { + if pkgPath == "" || fileName == "" { // TODO(hariom): assert empty pkgVersion if not stdlib panic("missing package path or file name") } Transcribe(fn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { @@ -3633,6 +3662,9 @@ func SaveBlockNodes(store Store, fn *FileNode) { if loc.PkgPath != pkgPath { panic("unexpected pkg path in node location") } + if loc.Version != pkgVersion { + panic("unexpected pkg version in node location") + } if loc.File != fileName { panic("unexpected file name in node location") } diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 39fe8546c3d..4f54541711e 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -69,13 +69,13 @@ func (pid PkgID) Bytes() []byte { return pid.Hashlet[:] } -func PkgIDFromPkgPath(path string) PkgID { - return PkgID{HashBytes([]byte(path))} +func PkgIDFromPkgPath(path, version string) PkgID { + return PkgID{HashBytes([]byte(path + "@" + version))} } -func ObjectIDFromPkgPath(path string) ObjectID { +func ObjectIDFromPkgPath(path, version string) ObjectID { return ObjectID{ - PkgID: PkgIDFromPkgPath(path), + PkgID: PkgIDFromPkgPath(path, version), NewTime: 1, // by realm logic. } } @@ -84,9 +84,10 @@ func ObjectIDFromPkgPath(path string) ObjectID { // support methods that don't require persistence. This is the default realm // when a machine starts with a non-realm package. type Realm struct { - ID PkgID - Path string - Time uint64 + ID PkgID + Path string + Version string + Time uint64 newCreated []Object newEscaped []Object @@ -99,12 +100,13 @@ type Realm struct { } // Creates a blank new realm with counter 0. -func NewRealm(path string) *Realm { - id := PkgIDFromPkgPath(path) +func NewRealm(path, version string) *Realm { + id := PkgIDFromPkgPath(path, version) return &Realm{ - ID: id, - Path: path, - Time: 0, + ID: id, + Path: path, + Version: version, + Time: 0, } } @@ -114,7 +116,7 @@ func (rlm *Realm) String() string { } else { return fmt.Sprintf( "Realm{Path:%q,Time:%d}#%X", - rlm.Path, rlm.Time, rlm.ID.Bytes()) + rlm.Path+"@"+rlm.Version, rlm.Time, rlm.ID.Bytes()) } } @@ -906,7 +908,7 @@ func getUnsavedChildObjects(val Value) []Object { // sanity check: if pv, ok := val.(*PackageValue); ok { if !pv.IsRealm() && pv.GetIsDirty() { - panic("unexpected dirty non-realm package " + pv.PkgPath) + panic("unexpected dirty non-realm package " + pv.ModFile.Path) } } // ... @@ -1146,6 +1148,7 @@ func copyValueWithRefs(parent Object, val Value) Value { Closure: closure, FileName: cv.FileName, PkgPath: cv.PkgPath, + PkgVersion: cv.PkgVersion, NativePkg: cv.NativePkg, NativeName: cv.NativeName, } @@ -1180,7 +1183,7 @@ func copyValueWithRefs(parent Object, val Value) Value { ObjectInfo: cv.ObjectInfo.Copy(), Block: block, PkgName: cv.PkgName, - PkgPath: cv.PkgPath, + ModFile: cv.ModFile, FNames: cv.FNames, // no copy FBlocks: fblocks, Realm: cv.Realm, @@ -1430,10 +1433,11 @@ func toRefValue(parent Object, val Value) RefValue { } else if oo, ok := val.(Object); ok { if pv, ok := val.(*PackageValue); ok { if pv.GetIsDirty() { - panic("unexpected dirty package " + pv.PkgPath) + panic("unexpected dirty package " + pv.ModFile.Path) } return RefValue{ - PkgPath: pv.PkgPath, + PkgPath: pv.ModFile.Path, + PkgVersion: pv.ModFile.Version, } } else if !oo.GetIsReal() { panic("unexpected unreal object") diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index d15976ec262..90826b09e87 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -23,9 +23,10 @@ type NativeStore func(pkgName string, name Name) func(m *Machine) type Store interface { // STABLE SetPackageGetter(PackageGetter) - GetPackage(pkgPath string, isImport bool) *PackageValue + GetPackage(pkgPath, version string, isImport bool) *PackageValue + // GetPackageInfo(pkgPath string, isImport bool) *std.MemPackageInfo SetCachePackage(*PackageValue) - GetPackageRealm(pkgPath string) *Realm + GetPackageRealm(pkgPath, pkgVersion string) *Realm SetPackageRealm(*Realm) GetObject(oid ObjectID) Object GetObjectSafe(oid ObjectID) Object @@ -46,10 +47,11 @@ type Store interface { // Upon restart, all packages will be re-preprocessed; This // loads BlockNodes and Types onto the store for persistence // version 1. - AddMemPackage(memPkg *std.MemPackage) - GetMemPackage(path string) *std.MemPackage - GetMemFile(path string, name string) *std.MemFile - IterMemPackage() <-chan *std.MemPackage + AddMemPackageInfo(memPkg *std.MemPackageInfo) + GetMemPackage(path, version string) *std.MemPackage + GetMemPackageInfo(path string) (*std.MemPackageInfo, error) + GetMemFile(path, version, name string) *std.MemFile + IterMemPackageInfo() <-chan *std.MemPackageInfo ClearObjectCache() // for each delivertx. Fork() Store // for checktx, simulate, and queries. SwapStores(baseStore, iavlStore store.Store) // for gas wrappers. @@ -108,7 +110,8 @@ func (ds *defaultStore) SetPackageGetter(pg PackageGetter) { } // Gets package from cache, or loads it from baseStore, or gets it from package getter. -func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue { +func (ds *defaultStore) GetPackage(pkgPath, version string, isImport bool) *PackageValue { + // fmt.Println("GetPackage:", pkgPath, version, isImport) // detect circular imports if isImport { if _, exists := ds.current[pkgPath]; exists { @@ -118,7 +121,7 @@ func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue defer delete(ds.current, pkgPath) } // first, check cache. - oid := ObjectIDFromPkgPath(pkgPath) + oid := ObjectIDFromPkgPath(pkgPath, version) if oo, exists := ds.cacheObjects[oid]; exists { pv := oo.(*PackageValue) return pv @@ -130,11 +133,11 @@ func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue _ = pv.GetBlock(ds) // preload // get package associated realm if nil. if pv.IsRealm() && pv.Realm == nil { - rlm := ds.GetPackageRealm(pkgPath) + rlm := ds.GetPackageRealm(pkgPath, version) pv.Realm = rlm } // get package node. - pl := PackageNodeLocation(pkgPath) + pl := PackageNodeLocation(pkgPath, version) pn, ok := ds.GetBlockNodeSafe(pl).(*PackageNode) if !ok { // Do not inject packages from packageGetter @@ -203,16 +206,17 @@ func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue // Used to set throwaway packages. func (ds *defaultStore) SetCachePackage(pv *PackageValue) { - oid := ObjectIDFromPkgPath(pv.PkgPath) + oid := ObjectIDFromPkgPath(pv.ModFile.Path, pv.ModFile.Version) if _, exists := ds.cacheObjects[oid]; exists { - panic(fmt.Sprintf("package %s already exists in cache", pv.PkgPath)) + panic(fmt.Sprintf("package %s(%s) already exists in cache", + pv.ModFile.Path, pv.ModFile.Version)) } ds.cacheObjects[oid] = pv } // Some atomic operation. -func (ds *defaultStore) GetPackageRealm(pkgPath string) (rlm *Realm) { - oid := ObjectIDFromPkgPath(pkgPath) +func (ds *defaultStore) GetPackageRealm(pkgPath, pkgVersion string) (rlm *Realm) { + oid := ObjectIDFromPkgPath(pkgPath, pkgVersion) key := backendRealmKey(oid) bz := ds.baseStore.Get([]byte(key)) if bz == nil { @@ -230,7 +234,7 @@ func (ds *defaultStore) GetPackageRealm(pkgPath string) (rlm *Realm) { // An atomic operation to set the package realm info (id counter etc). func (ds *defaultStore) SetPackageRealm(rlm *Realm) { - oid := ObjectIDFromPkgPath(rlm.Path) + oid := ObjectIDFromPkgPath(rlm.Path, rlm.Version) key := backendRealmKey(oid) bz := amino.MustMarshal(rlm) ds.baseStore.Set([]byte(key), bz) @@ -522,35 +526,57 @@ func (ds *defaultStore) incGetPackageIndexCounter() uint64 { } } -func (ds *defaultStore) AddMemPackage(memPkg *std.MemPackage) { - memPkg.Validate() // NOTE: duplicate validation. +func (ds *defaultStore) AddMemPackageInfo(memPkgInfo *std.MemPackageInfo) { + memPkgInfo.Validate() // NOTE: duplicate validation. ctr := ds.incGetPackageIndexCounter() idxkey := []byte(backendPackageIndexKey(ctr)) - bz := amino.MustMarshal(memPkg) - ds.baseStore.Set(idxkey, []byte(memPkg.Path)) - pathkey := []byte(backendPackagePathKey(memPkg.Path)) + bz := amino.MustMarshal(memPkgInfo) + ds.baseStore.Set(idxkey, []byte(memPkgInfo.Path)) + pathkey := []byte(backendPackagePathKey(memPkgInfo.Path)) ds.iavlStore.Set(pathkey, bz) } -func (ds *defaultStore) GetMemPackage(path string) *std.MemPackage { +func (ds *defaultStore) GetMemPackageInfo(path string) (*std.MemPackageInfo, error) { + pathkey := []byte(backendPackagePathKey(path)) + bz := ds.iavlStore.Get(pathkey) + if bz == nil { + return nil, fmt.Errorf("missing package at path %s", string(pathkey)) + } + var memPkgInfo *std.MemPackageInfo + amino.MustUnmarshal(bz, &memPkgInfo) + return memPkgInfo, nil +} + +func (ds *defaultStore) GetMemPackage(path, version string) *std.MemPackage { pathkey := []byte(backendPackagePathKey(path)) bz := ds.iavlStore.Get(pathkey) if bz == nil { panic(fmt.Sprintf( "missing package at path %s", string(pathkey))) } + var memPkgInfo *std.MemPackageInfo + amino.MustUnmarshal(bz, &memPkgInfo) var memPkg *std.MemPackage - amino.MustUnmarshal(bz, &memPkg) + for _, ver := range memPkgInfo.Versions { + if ver.ModFile.Version == version { + memPkg = ver + break + } + } + if memPkg == nil { + panic(fmt.Sprintf( + "missing package version %s at path %s", version, string(pathkey))) + } return memPkg } -func (ds *defaultStore) GetMemFile(path string, name string) *std.MemFile { - memPkg := ds.GetMemPackage(path) +func (ds *defaultStore) GetMemFile(path, version, name string) *std.MemFile { + memPkg := ds.GetMemPackage(path, version) memFile := memPkg.GetFile(name) return memFile } -func (ds *defaultStore) IterMemPackage() <-chan *std.MemPackage { +func (ds *defaultStore) IterMemPackageInfo() <-chan *std.MemPackageInfo { ctrkey := []byte(backendPackageIndexCtrKey()) ctrbz := ds.baseStore.Get(ctrkey) if ctrbz == nil { @@ -560,7 +586,7 @@ func (ds *defaultStore) IterMemPackage() <-chan *std.MemPackage { if err != nil { panic(err) } - ch := make(chan *std.MemPackage, 0) + ch := make(chan *std.MemPackageInfo, 0) go func() { for i := uint64(1); i <= uint64(ctr); i++ { idxkey := []byte(backendPackageIndexKey(i)) @@ -569,8 +595,11 @@ func (ds *defaultStore) IterMemPackage() <-chan *std.MemPackage { panic(fmt.Sprintf( "missing package index %d", i)) } - memPkg := ds.GetMemPackage(string(path)) - ch <- memPkg + memPkgInfo, err := ds.GetMemPackageInfo(string(path)) + if err != nil { + panic(err) + } + ch <- memPkgInfo } close(ch) }() @@ -764,7 +793,7 @@ func backendPackageIndexKey(index uint64) string { } func backendPackagePathKey(path string) string { - return fmt.Sprintf("pkg:" + path) + return fmt.Sprintf("pkg:%s", path) } // ---------------------------------------- diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index 34565b7a1b6..4f7a7c0b46b 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -1434,7 +1434,7 @@ func (dt *DeclaredType) TypeID() TypeID { return dt.typeid } -func DeclaredTypeID(pkgPath string, name Name) TypeID { +func DeclaredTypeID(pkgPath string, name Name) TypeID { // TODO(hariom): include version? return typeid("%s.%s", pkgPath, name) } @@ -2520,7 +2520,7 @@ func applySpecifics(lookup map[Name]Type, tmpl Type) (Type, bool) { // Construct BlockStmt from map. // TODO: make arg type be this // to reduce redundant steps. - pn := NewPackageNode("", "", nil) + pn := NewPackageNode("", &ModFileNode{}, nil) bs := new(BlockStmt) bs.InitStaticBlock(bs, pn) for n, t := range lookup { @@ -2530,7 +2530,7 @@ func applySpecifics(lookup map[Name]Type, tmpl Type) (Type, bool) { gx := MustParseExpr(string(generic)) gx = Preprocess(nil, bs, gx).(Expr) // Evaluate type from generic expression. - m := NewMachine("", nil) + m := NewMachine("", "", nil) tv := m.EvalStatic(bs, gx) m.Release() if isElem { diff --git a/gnovm/pkg/gnolang/utils.go b/gnovm/pkg/gnolang/utils.go index 96a3610b5d3..a33530ecd07 100644 --- a/gnovm/pkg/gnolang/utils.go +++ b/gnovm/pkg/gnolang/utils.go @@ -1,6 +1,12 @@ package gnolang -import "strings" +import ( + "fmt" + "strings" + + "github.com/gnolang/gno/gnovm/pkg/gnomod" + "github.com/gnolang/gno/tm2/pkg/std" +) func contains(list []string, item string) bool { for _, i := range list { @@ -19,3 +25,27 @@ func endsWith(item string, suffixes []string) bool { } return false } + +// TODO(hariom): move to better place +func ParseMemMod(dir string) *std.MemMod { + var memMod std.MemMod + gm, err := gnomod.ParseAt(dir) + if err != nil { + // TODO(hariom): return error instead + panic(fmt.Sprintf("error parsing gno.mod at: %q", dir)) + } + // TODO(hariom): make sure requires are accurate in gno.mod + var requires []*std.Requirements + for _, req := range gm.Require { + requires = append(requires, &std.Requirements{ + Path: req.Mod.Path, + Version: req.Mod.Version, + }) + } + + memMod.Requires = requires + memMod.ImportPath = gm.Module.Mod.Path + memMod.Version = gm.Module.Mod.Version + + return &memMod +} diff --git a/gnovm/pkg/gnolang/uverse.go b/gnovm/pkg/gnolang/uverse.go index a0e9913eaad..18f32760661 100644 --- a/gnovm/pkg/gnolang/uverse.go +++ b/gnovm/pkg/gnolang/uverse.go @@ -4,6 +4,8 @@ import ( "fmt" "reflect" "strings" + + "github.com/gnolang/gno/tm2/pkg/std" ) // ---------------------------------------- @@ -64,6 +66,7 @@ var ( ) const uversePkgPath = ".uverse" +const uversePkgVersion = "v0.1.0" // Always returns a new copy from the latest state of source. func Uverse() *PackageValue { @@ -82,7 +85,11 @@ func UverseNode() *PackageNode { } // NOTE: uverse node is hidden, thus the leading dot in pkgPath=".uverse". - uverseNode = NewPackageNode("uverse", uversePkgPath, nil) + uverseNode = NewPackageNode("uverse", &ModFileNode{ + Path: uversePkgPath, + Version: uversePkgVersion, + Require: make([]*std.Requirements, 0), + }, nil) // temporary convenience functions. def := func(n Name, tv TypedValue) { diff --git a/gnovm/pkg/gnolang/uverse_test.go b/gnovm/pkg/gnolang/uverse_test.go index 7280d131ec5..1090f0c7b25 100644 --- a/gnovm/pkg/gnolang/uverse_test.go +++ b/gnovm/pkg/gnolang/uverse_test.go @@ -150,7 +150,7 @@ func TestIssue1337PrintNilSliceAsUndefined(t *testing.T) { for _, tc := range test { t.Run(tc.name, func(t *testing.T) { - m := NewMachine("test", nil) + m := NewMachine("test", "", nil) n := MustParseFile("main.go", tc.code) m.RunFiles(n) m.RunMain() diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 85e6562eca6..406da6a8f0b 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -534,6 +534,7 @@ type FuncValue struct { Closure Value // *Block or RefValue to closure (may be nil for file blocks; lazy) FileName Name // file name where declared PkgPath string + PkgVersion string NativePkg string // for native bindings through NativeStore NativeName Name // not redundant with Name; this cannot be changed in userspace @@ -563,6 +564,7 @@ func (fv *FuncValue) Copy(alloc *Allocator) *FuncValue { Closure: fv.Closure, FileName: fv.FileName, PkgPath: fv.PkgPath, + PkgVersion: fv.PkgVersion, NativePkg: fv.NativePkg, NativeName: fv.NativeName, body: fv.body, @@ -604,7 +606,7 @@ func (fv *FuncValue) GetSource(store Store) BlockNode { } func (fv *FuncValue) GetPackage(store Store) *PackageValue { - pv := store.GetPackage(fv.PkgPath, false) + pv := store.GetPackage(fv.PkgPath, fv.PkgVersion, false) return pv } @@ -807,7 +809,7 @@ type PackageValue struct { ObjectInfo // is a separate object from .Block. Block Value PkgName Name - PkgPath string + ModFile *ModFileNode FNames []Name FBlocks []Value Realm *Realm `json:"-"` // if IsRealmPath(PkgPath), otherwise nil. @@ -817,7 +819,7 @@ type PackageValue struct { } func (pv *PackageValue) IsRealm() bool { - return IsRealmPath(pv.PkgPath) + return IsRealmPath(pv.ModFile.Path) } func (pv *PackageValue) getFBlocksMap() map[Name]*Block { @@ -916,7 +918,7 @@ func (pv *PackageValue) GetPackageNode(store Store) *PackageNode { // Convenience func (pv *PackageValue) GetPkgAddr() crypto.Address { - return DerivePkgAddr(pv.PkgPath) + return DerivePkgAddr(pv.ModFile.Path, pv.ModFile.Version) } // ---------------------------------------- @@ -1558,7 +1560,7 @@ func (tv *TypedValue) ComputeMapKey(store Store, omitType bool) MapKey { panic("should not happen") case *PackageType: pv := tv.V.(*PackageValue) - bz = append(bz, []byte(strconv.Quote(pv.PkgPath))...) + bz = append(bz, []byte(strconv.Quote(pv.ModFile.Path))...) case *ChanType: panic("not yet implemented") case *NativeType: @@ -2412,10 +2414,11 @@ func (b *Block) ExpandToSize(alloc *Allocator, size uint16) { // NOTE: RefValue Object methods declared in ownership.go type RefValue struct { - ObjectID ObjectID `json:",omitempty"` - Escaped bool `json:",omitempty"` - PkgPath string `json:",omitempty"` - Hash ValueHash `json:",omitempty"` + ObjectID ObjectID `json:",omitempty"` + Escaped bool `json:",omitempty"` + PkgPath string `json:",omitempty"` + PkgVersion string `json:",omitempty"` + Hash ValueHash `json:",omitempty"` } // ---------------------------------------- @@ -2516,7 +2519,7 @@ func fillValueTV(store Store, tv *TypedValue) *TypedValue { switch cv := tv.V.(type) { case RefValue: if cv.PkgPath != "" { // load package - tv.V = store.GetPackage(cv.PkgPath, false) + tv.V = store.GetPackage(cv.PkgPath, cv.PkgVersion, false) } else { // load object // XXX XXX allocate object. tv.V = store.GetObject(cv.ObjectID) diff --git a/gnovm/pkg/gnolang/values_string.go b/gnovm/pkg/gnolang/values_string.go index 34187e32879..f024ebca402 100644 --- a/gnovm/pkg/gnolang/values_string.go +++ b/gnovm/pkg/gnolang/values_string.go @@ -235,7 +235,7 @@ func (v TypeValue) String() string { } func (pv *PackageValue) String() string { - return fmt.Sprintf("package(%s %s)", pv.PkgName, pv.PkgPath) + return fmt.Sprintf("package(%s %s)", pv.PkgName, pv.ModFile.Path) } func (nv *NativeValue) String() string { diff --git a/gnovm/pkg/gnomod/file.go b/gnovm/pkg/gnomod/file.go index fda9263914e..1db4ccc70de 100644 --- a/gnovm/pkg/gnomod/file.go +++ b/gnovm/pkg/gnomod/file.go @@ -22,6 +22,18 @@ import ( "golang.org/x/mod/module" ) +// TODO(hariom): temporarily copied from pkg/gnolang to avoid import cycle +const ( + GnoRealmPkgsPrefixBefore = "gno.land/r/" + GnoRealmPkgsPrefixAfter = "github.com/gnolang/gno/examples/gno.land/r/" + GnoPackagePrefixBefore = "gno.land/p/demo/" + GnoPackagePrefixAfter = "github.com/gnolang/gno/examples/gno.land/p/demo/" + GnoStdPkgBefore = "std" + GnoStdPkgAfter = "github.com/gnolang/gno/gnovm/stdlibs/stdshim" + + ImportPrefix = "github.com/gnolang/gno" +) + // Parsed gno.mod file. type File struct { Draft bool diff --git a/gnovm/pkg/gnomod/gnomod.go b/gnovm/pkg/gnomod/gnomod.go index af946f2bf39..724712e88c7 100644 --- a/gnovm/pkg/gnomod/gnomod.go +++ b/gnovm/pkg/gnomod/gnomod.go @@ -1,16 +1,15 @@ package gnomod import ( - "errors" "fmt" "os" "path/filepath" "strings" "github.com/gnolang/gno/gnovm/pkg/gnoenv" - "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/transpiler" "github.com/gnolang/gno/tm2/pkg/std" + "golang.org/x/mod/modfile" "golang.org/x/mod/module" ) @@ -159,63 +158,6 @@ func GnoToGoMod(f File) (*File, error) { return &f, nil } -func CreateGnoModFile(rootDir, modPath string) error { - if !filepath.IsAbs(rootDir) { - return fmt.Errorf("dir %q is not absolute", rootDir) - } - - modFilePath := filepath.Join(rootDir, "gno.mod") - if _, err := os.Stat(modFilePath); err == nil { - return errors.New("gno.mod file already exists") - } - - if modPath == "" { - // Check .gno files for package name - // and use it as modPath - files, err := os.ReadDir(rootDir) - if err != nil { - return fmt.Errorf("read dir %q: %w", rootDir, err) - } - - var pkgName gnolang.Name - for _, file := range files { - if file.IsDir() || !strings.HasSuffix(file.Name(), ".gno") || strings.HasSuffix(file.Name(), "_filetest.gno") { - continue - } - - fpath := filepath.Join(rootDir, file.Name()) - bz, err := os.ReadFile(fpath) - if err != nil { - return fmt.Errorf("read file %q: %w", fpath, err) - } - - pn := gnolang.PackageNameFromFileBody(file.Name(), string(bz)) - if strings.HasSuffix(string(pkgName), "_test") { - pkgName = pkgName[:len(pkgName)-len("_test")] - } - if pkgName == "" { - pkgName = pn - } - if pkgName != pn { - return fmt.Errorf("package name mismatch: [%q] and [%q]", pkgName, pn) - } - } - if pkgName == "" { - return errors.New("cannot determine package name") - } - modPath = string(pkgName) - } - if err := module.CheckImportPath(modPath); err != nil { - return err - } - - modfile := new(File) - modfile.AddModuleStmt(modPath) - modfile.Write(filepath.Join(rootDir, "gno.mod")) - - return nil -} - func isReplaced(mod module.Version, repl []*modfile.Replace) (module.Version, bool) { for _, r := range repl { hasNoVersion := r.Old.Path == mod.Path && r.Old.Version == "" diff --git a/gnovm/pkg/gnomod/gnomod_test.go b/gnovm/pkg/gnomod/gnomod_test.go index 76c9a96c4e8..243c13ff1ce 100644 --- a/gnovm/pkg/gnomod/gnomod_test.go +++ b/gnovm/pkg/gnomod/gnomod_test.go @@ -1,151 +1,151 @@ package gnomod -import ( - "os" - "path/filepath" - "testing" +// import ( +// "os" +// "path/filepath" +// "testing" - "github.com/gnolang/gno/tm2/pkg/testutils" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) +// "github.com/gnolang/gno/tm2/pkg/testutils" +// "github.com/stretchr/testify/assert" +// "github.com/stretchr/testify/require" +// ) -func TestCreateGnoModFile(t *testing.T) { - t.Parallel() +// func TestCreateGnoModFile(t *testing.T) { +// t.Parallel() - for _, tc := range []struct { - desc string - in []struct{ filename, content string } - inModPath string - out string - errShouldContain string - }{ - { - desc: "empty directory", - inModPath: "gno.land/p/demo/foo", - out: "module gno.land/p/demo/foo\n", - }, - { - desc: "empty directory (without modPath)", - errShouldContain: "cannot determine package name", - }, - { - desc: "invalid modPath 1", - inModPath: " ", - errShouldContain: "malformed import path", - }, - { - desc: "invalid modPath 2", - inModPath: "\"", - errShouldContain: "malformed import path", - }, - { - desc: "valid package", - in: []struct{ filename, content string }{ - { - "foo.gno", - `package foo`, - }, - }, - inModPath: "gno.land/p/demo/foo", - out: "module gno.land/p/demo/foo\n", - }, - { - desc: "valid package (without modPath)", - in: []struct{ filename, content string }{ - { - "foo.gno", - `package foo`, - }, - }, - out: "module foo\n", - }, - { - desc: "ambigious package names", - in: []struct{ filename, content string }{ - { - "foo.gno", - `package foo`, - }, - { - "bar.gno", - `package bar`, - }, - }, - inModPath: "gno.land/p/demo/foo", - out: "module gno.land/p/demo/foo\n", - }, - { - desc: "ambigious package names (without modPath)", - in: []struct{ filename, content string }{ - { - "foo.gno", - `package foo`, - }, - { - "bar.gno", - `package bar`, - }, - }, - errShouldContain: "package name mismatch:", - }, - { - desc: "valid package with gno.mod file", - in: []struct{ filename, content string }{ - { - "foo.gno", - `package foo`, - }, - { - "gno.mod", - `module gno.land/p/demo/foo`, - }, - }, - inModPath: "gno.land/p/demo/foo", - errShouldContain: "gno.mod file already exists", - }, - { - desc: "valid package with gno.mod file (without modPath)", - in: []struct{ filename, content string }{ - { - "foo.gno", - `package foo`, - }, - { - "gno.mod", - `module gno.land/p/demo/foo`, - }, - }, - errShouldContain: "gno.mod file already exists", - }, - } { - tc := tc - t.Run(tc.desc, func(t *testing.T) { - t.Parallel() +// for _, tc := range []struct { +// desc string +// in []struct{ filename, content string } +// inModPath string +// out string +// errShouldContain string +// }{ +// { +// desc: "empty directory", +// inModPath: "gno.land/p/demo/foo", +// out: "module gno.land/p/demo/foo\n", +// }, +// { +// desc: "empty directory (without modPath)", +// errShouldContain: "cannot determine package name", +// }, +// { +// desc: "invalid modPath 1", +// inModPath: " ", +// errShouldContain: "malformed import path", +// }, +// { +// desc: "invalid modPath 2", +// inModPath: "\"", +// errShouldContain: "malformed import path", +// }, +// { +// desc: "valid package", +// in: []struct{ filename, content string }{ +// { +// "foo.gno", +// `package foo`, +// }, +// }, +// inModPath: "gno.land/p/demo/foo", +// out: "module gno.land/p/demo/foo\n", +// }, +// { +// desc: "valid package (without modPath)", +// in: []struct{ filename, content string }{ +// { +// "foo.gno", +// `package foo`, +// }, +// }, +// out: "module foo\n", +// }, +// { +// desc: "ambigious package names", +// in: []struct{ filename, content string }{ +// { +// "foo.gno", +// `package foo`, +// }, +// { +// "bar.gno", +// `package bar`, +// }, +// }, +// inModPath: "gno.land/p/demo/foo", +// out: "module gno.land/p/demo/foo\n", +// }, +// { +// desc: "ambigious package names (without modPath)", +// in: []struct{ filename, content string }{ +// { +// "foo.gno", +// `package foo`, +// }, +// { +// "bar.gno", +// `package bar`, +// }, +// }, +// errShouldContain: "package name mismatch:", +// }, +// { +// desc: "valid package with gno.mod file", +// in: []struct{ filename, content string }{ +// { +// "foo.gno", +// `package foo`, +// }, +// { +// "gno.mod", +// `module gno.land/p/demo/foo`, +// }, +// }, +// inModPath: "gno.land/p/demo/foo", +// errShouldContain: "gno.mod file already exists", +// }, +// { +// desc: "valid package with gno.mod file (without modPath)", +// in: []struct{ filename, content string }{ +// { +// "foo.gno", +// `package foo`, +// }, +// { +// "gno.mod", +// `module gno.land/p/demo/foo`, +// }, +// }, +// errShouldContain: "gno.mod file already exists", +// }, +// } { +// tc := tc +// t.Run(tc.desc, func(t *testing.T) { +// t.Parallel() - // Create test dir - dirPath, cleanUpFn := testutils.NewTestCaseDir(t) - require.NotNil(t, dirPath) - defer cleanUpFn() +// // Create test dir +// dirPath, cleanUpFn := testutils.NewTestCaseDir(t) +// require.NotNil(t, dirPath) +// defer cleanUpFn() - // Create files - for _, f := range tc.in { - err := os.WriteFile(filepath.Join(dirPath, f.filename), []byte(f.content), 0o644) - require.NoError(t, err) - } +// // Create files +// for _, f := range tc.in { +// err := os.WriteFile(filepath.Join(dirPath, f.filename), []byte(f.content), 0o644) +// require.NoError(t, err) +// } - err := CreateGnoModFile(dirPath, tc.inModPath) - if tc.errShouldContain != "" { - assert.Error(t, err) - assert.Contains(t, err.Error(), tc.errShouldContain) - return - } - assert.NoError(t, err) +// err := CreateGnoModFile(dirPath, tc.inModPath) +// if tc.errShouldContain != "" { +// assert.Error(t, err) +// assert.Contains(t, err.Error(), tc.errShouldContain) +// return +// } +// assert.NoError(t, err) - // Verify gno.mod file - bz, err := os.ReadFile(filepath.Join(dirPath, "gno.mod")) - assert.NoError(t, err) - assert.Equal(t, tc.out, string(bz)) - }) - } -} +// // Verify gno.mod file +// bz, err := os.ReadFile(filepath.Join(dirPath, "gno.mod")) +// assert.NoError(t, err) +// assert.Equal(t, tc.out, string(bz)) +// }) +// } +// } diff --git a/gnovm/pkg/gnomod/parse.go b/gnovm/pkg/gnomod/parse.go index a6314d5729f..2df61365ef3 100644 --- a/gnovm/pkg/gnomod/parse.go +++ b/gnovm/pkg/gnomod/parse.go @@ -169,8 +169,8 @@ func (f *File) add(errs *modfile.ErrorList, block *modfile.LineBlock, line *modf Syntax: line, Deprecated: deprecated, } - if len(args) != 1 { - errorf("usage: module module/path") + if len(args) != 2 { + errorf("usage: %s module/path v1.2.3", verb) return } s, err := parseString(&args[0]) @@ -178,7 +178,12 @@ func (f *File) add(errs *modfile.ErrorList, block *modfile.LineBlock, line *modf errorf("invalid quoted string: %v", err) return } - f.Module.Mod = module.Version{Path: s} + v, err := parseVersion(verb, s, &args[1]) + if err != nil { + wrapError(err) + return + } + f.Module.Mod = module.Version{Path: s, Version: v} case "require": if len(args) != 2 { diff --git a/gnovm/pkg/transpiler/transpiler.go b/gnovm/pkg/transpiler/transpiler.go index a5e1e068ba5..881a2fdc2d2 100644 --- a/gnovm/pkg/transpiler/transpiler.go +++ b/gnovm/pkg/transpiler/transpiler.go @@ -25,7 +25,7 @@ import ( const ( GnoRealmPkgsPrefixBefore = "gno.land/r/" GnoRealmPkgsPrefixAfter = "github.com/gnolang/gno/examples/gno.land/r/" - GnoPackagePrefixBefore = "gno.land/p/demo/" + GnoPackagePrefixBefore = "gno.land/p/" GnoPackagePrefixAfter = "github.com/gnolang/gno/examples/gno.land/p/demo/" GnoStdPkgBefore = "std" GnoStdPkgAfter = "github.com/gnolang/gno/gnovm/stdlibs/stdshim" diff --git a/gnovm/stdlibs/native.go b/gnovm/stdlibs/native.go index 0cb7d9a7859..291ed764bd7 100644 --- a/gnovm/stdlibs/native.go +++ b/gnovm/stdlibs/native.go @@ -566,7 +566,7 @@ var nativeFuncs = [...]nativeFunc{ gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - r0 := libs_std.X_derivePkgAddr(p0) + r0 := libs_std.X_derivePkgAddr(p0, "") m.PushValue(gno.Go2GnoValue( m.Alloc, diff --git a/gnovm/stdlibs/std/native.gno b/gnovm/stdlibs/std/native.gno index 8043df49882..52c48909558 100644 --- a/gnovm/stdlibs/std/native.gno +++ b/gnovm/stdlibs/std/native.gno @@ -37,8 +37,8 @@ func GetCallerAt(n int) Address { return Address(callerAt(n)) } -func DerivePkgAddr(pkgPath string) Address { - return Address(derivePkgAddr(pkgPath)) +func DerivePkgAddr(pkgPath, pkgVersion string) Address { + return Address(derivePkgAddr(pkgPath, pkgVersion)) } func EncodeBech32(prefix string, bz [20]byte) Address { @@ -55,6 +55,6 @@ func origCaller() string func origPkgAddr() string func callerAt(n int) string func getRealm(height int) (address string, pkgPath string) -func derivePkgAddr(pkgPath string) string +func derivePkgAddr(pkgPath, pkgVersion string) string func encodeBech32(prefix string, bz [20]byte) string func decodeBech32(addr string) (prefix string, bz [20]byte, ok bool) diff --git a/gnovm/stdlibs/std/native.go b/gnovm/stdlibs/std/native.go index 0965ef74277..c8afb365b16 100644 --- a/gnovm/stdlibs/std/native.go +++ b/gnovm/stdlibs/std/native.go @@ -85,7 +85,7 @@ func X_getRealm(m *gno.Machine, height int) (address string, pkgPath string) { // LastPackage is a realm. Get caller and pkgPath, and compare against // current* values. caller := fr.LastPackage.GetPkgAddr().Bech32() - pkgPath := fr.LastPackage.PkgPath + pkgPath := fr.LastPackage.ModFile.Path if caller != currentCaller { if changes == height { return string(caller), pkgPath @@ -99,8 +99,8 @@ func X_getRealm(m *gno.Machine, height int) (address string, pkgPath string) { return string(ctx.OrigCaller), "" } -func X_derivePkgAddr(pkgPath string) string { - return string(gno.DerivePkgAddr(pkgPath).Bech32()) +func X_derivePkgAddr(pkgPath, pkgVersion string) string { + return string(gno.DerivePkgAddr(pkgPath, pkgVersion).Bech32()) } func X_encodeBech32(prefix string, bytes [20]byte) string { diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index 70bed4eda50..eb18b36767a 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -35,8 +35,8 @@ func TestMachine(store gno.Store, stdout io.Writer, pkgPath string) *gno.Machine func testMachineCustom(store gno.Store, pkgPath string, stdout io.Writer, maxAlloc int64, send std.Coins) *gno.Machine { // FIXME: create a better package to manage this, with custom constructors - pkgAddr := gno.DerivePkgAddr(pkgPath) // the addr of the pkgPath called. - caller := gno.DerivePkgAddr("user1.gno") + pkgAddr := gno.DerivePkgAddr(pkgPath, "") // the addr of the pkgPath called. + caller := gno.DerivePkgAddr("user1.gno", "") // TODO: verision?? pkgCoins := std.MustParseCoins("200000000ugnot").Add(send) // >= send. banker := newTestBanker(pkgAddr.Bech32(), pkgCoins) @@ -97,7 +97,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { opt(&f) } - directives, pkgPath, resWanted, errWanted, rops, maxAlloc, send := wantedFromComment(path) + directives, pkgPath, pkgVersion, resWanted, errWanted, rops, maxAlloc, send := wantedFromComment(path) if pkgPath == "" { pkgPath = "main" } @@ -150,7 +150,10 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { } if !gno.IsRealmPath(pkgPath) { // simple case. - pn := gno.NewPackageNode(pkgName, pkgPath, &gno.FileSet{}) + pn := gno.NewPackageNode(pkgName, &gno.ModFileNode{ + Path: pkgPath, + Version: pkgVersion, + }, &gno.FileSet{}) pv := pn.NewPackage() store.SetBlockNode(pn) store.SetCachePackage(pv) @@ -175,7 +178,10 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { // save package using realm crawl procedure. memPkg := &std.MemPackage{ Name: string(pkgName), - Path: pkgPath, + ModFile: &std.MemMod{ + ImportPath: pkgPath, + Version: pkgVersion, + }, Files: []*std.MemFile{ { Name: "main.gno", // dontcare @@ -216,7 +222,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { f.logger("========================================") store.Print() } - pv2 := store.GetPackage(pkgPath, false) + pv2 := store.GetPackage(pkgPath, pkgVersion, false) m.SetActivePackage(pv2) gno.EnableDebug() if rops != "" { @@ -364,7 +370,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { return nil } -func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops string, maxAlloc int64, send std.Coins) { +func wantedFromComment(p string) (directives []string, pkgPath, pkgVersion, res, err, rops string, maxAlloc int64, send std.Coins) { fset := token.NewFileSet() f, err2 := parser.ParseFile(fset, p, nil, parser.ParseComments) if err2 != nil { @@ -378,6 +384,9 @@ func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops s if strings.HasPrefix(text, "PKGPATH:") { line := strings.SplitN(text, "\n", 2)[0] pkgPath = strings.TrimSpace(strings.TrimPrefix(line, "PKGPATH:")) + } else if strings.HasPrefix(text, "VERSION:") { + line := strings.SplitN(text, "\n", 2)[0] + pkgVersion = strings.TrimSpace(strings.TrimPrefix(line, "VERSION:")) } else if strings.HasPrefix(text, "MAXALLOC:") { line := strings.SplitN(text, "\n", 2)[0] maxstr := strings.TrimSpace(strings.TrimPrefix(line, "MAXALLOC:")) diff --git a/gnovm/tests/imports.go b/gnovm/tests/imports.go index 9c48b4132cf..a77e7837435 100644 --- a/gnovm/tests/imports.go +++ b/gnovm/tests/imports.go @@ -116,13 +116,17 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri mode == ImportModeNativePreferred { switch pkgPath { case "os": - pkg := gno.NewPackageNode("os", pkgPath, nil) + pkg := gno.NewPackageNode("os", &gno.ModFileNode{ + Path: pkgPath, + }, nil) // TODO(hariom): needs version? (look at other occurances in the file too) pkg.DefineGoNativeValue("Stdin", stdin) pkg.DefineGoNativeValue("Stdout", stdout) pkg.DefineGoNativeValue("Stderr", stderr) return pkg, pkg.NewPackage() case "fmt": - pkg := gno.NewPackageNode("fmt", pkgPath, nil) + pkg := gno.NewPackageNode("fmt", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf((*fmt.Stringer)(nil)).Elem()) pkg.DefineGoNativeType(reflect.TypeOf((*fmt.Formatter)(nil)).Elem()) pkg.DefineGoNativeValue("Println", func(a ...interface{}) (n int, err error) { @@ -149,28 +153,38 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg.DefineGoNativeValue("Fprint", fmt.Fprint) return pkg, pkg.NewPackage() case "encoding/base64": - pkg := gno.NewPackageNode("base64", pkgPath, nil) + pkg := gno.NewPackageNode("base64", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("RawStdEncoding", base64.RawStdEncoding) pkg.DefineGoNativeValue("StdEncoding", base64.StdEncoding) pkg.DefineGoNativeValue("NewDecoder", base64.NewDecoder) return pkg, pkg.NewPackage() case "encoding/binary": - pkg := gno.NewPackageNode("binary", pkgPath, nil) + pkg := gno.NewPackageNode("binary", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("LittleEndian", binary.LittleEndian) pkg.DefineGoNativeValue("BigEndian", binary.BigEndian) pkg.DefineGoNativeValue("Write", binary.BigEndian) // warn: use reflection return pkg, pkg.NewPackage() case "encoding/json": - pkg := gno.NewPackageNode("json", pkgPath, nil) + pkg := gno.NewPackageNode("json", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Unmarshal", json.Unmarshal) pkg.DefineGoNativeValue("Marshal", json.Marshal) return pkg, pkg.NewPackage() case "encoding/xml": - pkg := gno.NewPackageNode("xml", pkgPath, nil) + pkg := gno.NewPackageNode("xml", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Unmarshal", xml.Unmarshal) return pkg, pkg.NewPackage() case "internal/os_test": - pkg := gno.NewPackageNode("os_test", pkgPath, nil) + pkg := gno.NewPackageNode("os_test", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineNative("Sleep", gno.Flds( // params "d", gno.AnyT(), // NOTE: should be time.Duration @@ -195,21 +209,29 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri ) return pkg, pkg.NewPackage() case "net": - pkg := gno.NewPackageNode("net", pkgPath, nil) + pkg := gno.NewPackageNode("net", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(net.TCPAddr{})) pkg.DefineGoNativeValue("IPv4", net.IPv4) return pkg, pkg.NewPackage() case "net/url": - pkg := gno.NewPackageNode("url", pkgPath, nil) + pkg := gno.NewPackageNode("url", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(url.Values{})) return pkg, pkg.NewPackage() case "bufio": - pkg := gno.NewPackageNode("bufio", pkgPath, nil) + pkg := gno.NewPackageNode("bufio", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("NewScanner", bufio.NewScanner) pkg.DefineGoNativeType(reflect.TypeOf(bufio.SplitFunc(nil))) return pkg, pkg.NewPackage() case "bytes": - pkg := gno.NewPackageNode("bytes", pkgPath, nil) + pkg := gno.NewPackageNode("bytes", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Equal", bytes.Equal) pkg.DefineGoNativeValue("Compare", bytes.Compare) pkg.DefineGoNativeValue("NewReader", bytes.NewReader) @@ -218,7 +240,9 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg.DefineGoNativeType(reflect.TypeOf(bytes.Buffer{})) return pkg, pkg.NewPackage() case "time": - pkg := gno.NewPackageNode("time", pkgPath, nil) + pkg := gno.NewPackageNode("time", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Millisecond", time.Millisecond) pkg.DefineGoNativeValue("Second", time.Second) pkg.DefineGoNativeValue("Minute", time.Minute) @@ -233,7 +257,9 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg.DefineGoNativeType(reflect.TypeOf(time.Month(0))) return pkg, pkg.NewPackage() case "strings": - pkg := gno.NewPackageNode("strings", pkgPath, nil) + pkg := gno.NewPackageNode("strings", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Split", strings.Split) pkg.DefineGoNativeValue("SplitN", strings.SplitN) pkg.DefineGoNativeValue("Contains", strings.Contains) @@ -246,7 +272,9 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg.DefineGoNativeType(reflect.TypeOf(strings.Builder{})) return pkg, pkg.NewPackage() case "math": - pkg := gno.NewPackageNode("math", pkgPath, nil) + pkg := gno.NewPackageNode("math", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Abs", math.Abs) pkg.DefineGoNativeValue("Cos", math.Cos) pkg.DefineGoNativeValue("Pi", math.Pi) @@ -257,7 +285,9 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri return pkg, pkg.NewPackage() case "math/rand": // XXX only expose for tests. - pkg := gno.NewPackageNode("rand", pkgPath, nil) + pkg := gno.NewPackageNode("rand", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Intn", rand.Intn) pkg.DefineGoNativeValue("Uint32", rand.Uint32) pkg.DefineGoNativeValue("Seed", rand.Seed) @@ -266,69 +296,97 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg.DefineGoNativeType(reflect.TypeOf(rand.Rand{})) return pkg, pkg.NewPackage() case "crypto/rand": - pkg := gno.NewPackageNode("rand", pkgPath, nil) + pkg := gno.NewPackageNode("rand", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Prime", crand.Prime) // for determinism: // pkg.DefineGoNativeValue("Reader", crand.Reader) pkg.DefineGoNativeValue("Reader", &dummyReader{}) return pkg, pkg.NewPackage() case "crypto/md5": - pkg := gno.NewPackageNode("md5", pkgPath, nil) + pkg := gno.NewPackageNode("md5", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("New", md5.New) return pkg, pkg.NewPackage() case "crypto/sha1": - pkg := gno.NewPackageNode("sha1", pkgPath, nil) + pkg := gno.NewPackageNode("sha1", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("New", sha1.New) return pkg, pkg.NewPackage() case "image": - pkg := gno.NewPackageNode("image", pkgPath, nil) + pkg := gno.NewPackageNode("image", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(image.Point{})) return pkg, pkg.NewPackage() case "image/color": - pkg := gno.NewPackageNode("color", pkgPath, nil) + pkg := gno.NewPackageNode("color", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(color.NRGBA64{})) return pkg, pkg.NewPackage() case "compress/flate": - pkg := gno.NewPackageNode("flate", pkgPath, nil) + pkg := gno.NewPackageNode("flate", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("BestSpeed", flate.BestSpeed) return pkg, pkg.NewPackage() case "compress/gzip": - pkg := gno.NewPackageNode("gzip", pkgPath, nil) + pkg := gno.NewPackageNode("gzip", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(gzip.Writer{})) pkg.DefineGoNativeValue("BestCompression", gzip.BestCompression) pkg.DefineGoNativeValue("BestSpeed", gzip.BestSpeed) return pkg, pkg.NewPackage() case "context": - pkg := gno.NewPackageNode("context", pkgPath, nil) + pkg := gno.NewPackageNode("context", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf((*context.Context)(nil)).Elem()) pkg.DefineGoNativeValue("WithValue", context.WithValue) pkg.DefineGoNativeValue("Background", context.Background) return pkg, pkg.NewPackage() case "sync": - pkg := gno.NewPackageNode("sync", pkgPath, nil) + pkg := gno.NewPackageNode("sync", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(sync.Mutex{})) pkg.DefineGoNativeType(reflect.TypeOf(sync.RWMutex{})) pkg.DefineGoNativeType(reflect.TypeOf(sync.Pool{})) return pkg, pkg.NewPackage() case "sync/atomic": - pkg := gno.NewPackageNode("atomic", pkgPath, nil) + pkg := gno.NewPackageNode("atomic", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(atomic.Value{})) return pkg, pkg.NewPackage() case "math/big": - pkg := gno.NewPackageNode("big", pkgPath, nil) + pkg := gno.NewPackageNode("big", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("NewInt", big.NewInt) return pkg, pkg.NewPackage() case "sort": - pkg := gno.NewPackageNode("sort", pkgPath, nil) + pkg := gno.NewPackageNode("sort", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Strings", sort.Strings) // pkg.DefineGoNativeValue("Sort", sort.Sort) return pkg, pkg.NewPackage() case "flag": - pkg := gno.NewPackageNode("flag", pkgPath, nil) + pkg := gno.NewPackageNode("flag", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(flag.Flag{})) return pkg, pkg.NewPackage() case "io": - pkg := gno.NewPackageNode("io", pkgPath, nil) + pkg := gno.NewPackageNode("io", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("EOF", io.EOF) pkg.DefineGoNativeValue("NopCloser", io.NopCloser) pkg.DefineGoNativeValue("ReadFull", io.ReadFull) @@ -338,26 +396,36 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg.DefineGoNativeType(reflect.TypeOf((*io.Reader)(nil)).Elem()) return pkg, pkg.NewPackage() case "log": - pkg := gno.NewPackageNode("log", pkgPath, nil) + pkg := gno.NewPackageNode("log", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("Fatal", log.Fatal) return pkg, pkg.NewPackage() case "text/template": - pkg := gno.NewPackageNode("template", pkgPath, nil) + pkg := gno.NewPackageNode("template", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeType(reflect.TypeOf(template.FuncMap{})) return pkg, pkg.NewPackage() case "unicode/utf8": - pkg := gno.NewPackageNode("utf8", pkgPath, nil) + pkg := gno.NewPackageNode("utf8", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("DecodeRuneInString", utf8.DecodeRuneInString) tv := gno.TypedValue{T: gno.UntypedRuneType} // TODO dry tv.SetInt32(utf8.RuneSelf) // .. pkg.Define("RuneSelf", tv) // .. return pkg, pkg.NewPackage() case "errors": - pkg := gno.NewPackageNode("errors", pkgPath, nil) + pkg := gno.NewPackageNode("errors", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("New", errors.New) return pkg, pkg.NewPackage() case "hash/fnv": - pkg := gno.NewPackageNode("fnv", pkgPath, nil) + pkg := gno.NewPackageNode("fnv", &gno.ModFileNode{ + Path: pkgPath, + }, nil) pkg.DefineGoNativeValue("New32a", fnv.New32a) return pkg, pkg.NewPackage() default: @@ -447,7 +515,7 @@ func loadStdlib(rootDir, pkgPath string, store gno.Store, stdout io.Writer) (*gn func testPackageInjector(store gno.Store, pn *gno.PackageNode) { // Test specific injections: - switch pn.PkgPath { + switch pn.ModFile.Path { case "strconv": // NOTE: Itoa and Atoi are already injected // from stdlibs.InjectNatives. diff --git a/gnovm/tests/integ/hello-world/gno.mod b/gnovm/tests/integ/hello-world/gno.mod new file mode 100644 index 00000000000..15910973b4d --- /dev/null +++ b/gnovm/tests/integ/hello-world/gno.mod @@ -0,0 +1 @@ +module gno.land/r/helloworld/hello v1.0.0 diff --git a/gnovm/tests/integ/hello-world/hello.gno b/gnovm/tests/integ/hello-world/hello.gno new file mode 100644 index 00000000000..815ef73f04e --- /dev/null +++ b/gnovm/tests/integ/hello-world/hello.gno @@ -0,0 +1,5 @@ +package hello + +func SayHello() string { + return "hello from v1" +} diff --git a/gnovm/tests/integ/replace-with-dir/gno.mod b/gnovm/tests/integ/replace-with-dir/gno.mod index 6a7b1b664c8..94c5f6a6c14 100644 --- a/gnovm/tests/integ/replace-with-dir/gno.mod +++ b/gnovm/tests/integ/replace-with-dir/gno.mod @@ -1,7 +1,7 @@ module gno.land/tests/replaceavl require ( - "gno.land/p/demo/notexists" v0.0.0 + "gno.land/p/demo/notexists" v0.1.0 ) replace ( diff --git a/gnovm/tests/integ/replace-with-invalid-module/gno.mod b/gnovm/tests/integ/replace-with-invalid-module/gno.mod index ee90787ff0e..6905095563f 100644 --- a/gnovm/tests/integ/replace-with-invalid-module/gno.mod +++ b/gnovm/tests/integ/replace-with-invalid-module/gno.mod @@ -1,9 +1,9 @@ module gno.land/tests/replaceavl require ( - "gno.land/p/demo/avl" v0.0.0 + "gno.land/p/demo/avl" v0.1.0 ) replace ( - "gno.land/p/demo/avl" => "gno.land/p/demo/avlll" v0.0.0 + "gno.land/p/demo/avl" => "gno.land/p/demo/avlll" v0.1.0 ) diff --git a/gnovm/tests/integ/require-remote-module/gno.mod b/gnovm/tests/integ/require-remote-module/gno.mod index 4823c72585d..8a55aa42b6f 100644 --- a/gnovm/tests/integ/require-remote-module/gno.mod +++ b/gnovm/tests/integ/require-remote-module/gno.mod @@ -1,5 +1,5 @@ module gno.land/tests/importavl require ( - "gno.land/p/demo/avl" v0.0.0 + "gno.land/p/demo/avl" v0.1.0 ) diff --git a/gnovm/tests/integ/valid2/gno.mod b/gnovm/tests/integ/valid2/gno.mod index 98a5a0dacc1..dc9fffecd45 100644 --- a/gnovm/tests/integ/valid2/gno.mod +++ b/gnovm/tests/integ/valid2/gno.mod @@ -1,3 +1,3 @@ module gno.land/p/integ/valid -require gno.land/p/demo/avl v0.0.0-latest +require gno.land/p/demo/avl v0.1.0 diff --git a/misc/docker-integration/integration_test.go b/misc/docker-integration/integration_test.go index 1142709cc16..b7556fc1e73 100644 --- a/misc/docker-integration/integration_test.go +++ b/misc/docker-integration/integration_test.go @@ -59,27 +59,26 @@ func runSuite(t *testing.T, tempdir string) { require.True(t, acc.Coins.IsAllGTE(minCoins), "test1 account coins expected at least %s, got %s", minCoins, acc.Coins) - // add gno.land/r/demo/tests package as tests_copy + // add gno.land/p/helloworld/hello v1.0.0 dockerExec(t, `echo 'pass' | gnokey maketx addpkg -insecure-password-stdin \ -gas-fee 1000000ugnot -gas-wanted 2000000 \ -broadcast -chainid dev \ - -pkgdir /opt/gno/src/examples/gno.land/r/demo/tests/ \ - -pkgpath gno.land/r/demo/tests_copy \ + -pkgdir /opt/gno/src/gnovm/tests/integ/hello-world \ -deposit 100000000ugnot \ test1`, ) - // assert gno.land/r/demo/tests_copy has been added + // assert gno.land/p/helloworld/hello has been added var qfuncs vm.FunctionSignatures - dockerExec_gnokeyQuery(t, `-data "gno.land/r/demo/tests_copy" vm/qfuncs`, &qfuncs) - require.True(t, len(qfuncs) > 0, "gno.land/r/demo/tests_copy not added") + dockerExec_gnokeyQuery(t, `-data "gno.land/r/helloworld/hello@v1.0.0" vm/qfuncs`, &qfuncs) + require.True(t, len(qfuncs) > 0, "gno.land/r/helloworld/hello@v1.0.0 not added") // broadcast a package TX dockerExec(t, `echo 'pass' | gnokey maketx call -insecure-password-stdin \ -gas-fee 1000000ugnot -gas-wanted 2000000 \ -broadcast -chainid dev \ - -pkgpath "gno.land/r/demo/tests_copy" -func "InitTestNodes" \ + -pkgpath "gno.land/r/helloworld/hello@v1.0.0" -func "SayHello" \ test1`, ) } diff --git a/tm2/pkg/amino/binary_decode.go b/tm2/pkg/amino/binary_decode.go index 333994d60b0..0952be80d4e 100644 --- a/tm2/pkg/amino/binary_decode.go +++ b/tm2/pkg/amino/binary_decode.go @@ -955,7 +955,7 @@ func (cdc *Codec) decodeReflectBinaryStruct(bz []byte, info *TypeInfo, rv reflec // Validate fnum and typ. if fnum <= lastFieldNum { - err = fmt.Errorf("encountered fieldNum: %v, but we have already seen fnum: %v\nbytes:%X", + err = fmt.Errorf("encountered fieldNum: %v, but we have already seen fnum: %v\nbytes:%s", fnum, lastFieldNum, bz) return } diff --git a/tm2/pkg/std/memfile.go b/tm2/pkg/std/memfile.go index 599e9a59cc5..8e6f2667f9d 100644 --- a/tm2/pkg/std/memfile.go +++ b/tm2/pkg/std/memfile.go @@ -13,16 +13,49 @@ type MemFile struct { Body string } -// MemPackage represents the information and files of a package which will be +type MemMod struct { + ImportPath string + Version string + Requires []*Requirements +} + +type Requirements struct { + Path string + Version string +} + +// MemPackageInfo represents the information and versions of a package +type MemPackageInfo struct { + Name string // package name as declared by `package` + Path string // import path + Versions []*MemPackage +} + +func (mempkgInfo *MemPackageInfo) Validate() error { + if !rePkgName.MatchString(mempkgInfo.Name) { + return errors.New(fmt.Sprintf("invalid package name %q", mempkgInfo.Name)) + } + if !rePkgOrRlmPath.MatchString(mempkgInfo.Path) { + return errors.New(fmt.Sprintf("invalid package/realm path %q", mempkgInfo.Path)) + } + for _, version := range mempkgInfo.Versions { + if err := version.Validate(); err != nil { + return errors.New("error validating version") + } + } + return nil +} + +// MemPackage represents the single version and files of a package which will be // stored in memory. It will generally be initialized by package gnolang's // ReadMemPackage. // // NOTE: in the future, a MemPackage may represent // updates/additional-files for an existing package. type MemPackage struct { - Name string // package name as declared by `package` - Path string // import path - Files []*MemFile + Name string + ModFile *MemMod + Files []*MemFile } func (mempkg *MemPackage) GetFile(name string) *MemFile { @@ -53,8 +86,9 @@ func (mempkg *MemPackage) Validate() error { if !rePkgName.MatchString(mempkg.Name) { return errors.New(fmt.Sprintf("invalid package name %q, failed to match %q", mempkg.Name, rePkgName)) } - if !rePkgOrRlmPath.MatchString(mempkg.Path) { - return errors.New(fmt.Sprintf("invalid package/realm path %q, failed to match %q", mempkg.Path, rePkgOrRlmPath)) + + if !rePkgOrRlmPath.MatchString(mempkg.ModFile.ImportPath) { + return errors.New(fmt.Sprintf("invalid package/realm path %q, failed to match %q", mempkg.ModFile.ImportPath, rePkgOrRlmPath)) } fnames := map[string]struct{}{} for _, memfile := range mempkg.Files {