From 2f162b44143ce6aebb8f17a57bc3a66ad2ad4829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20=C5=BDivkovi=C4=87?= Date: Mon, 25 Nov 2024 03:58:54 +0100 Subject: [PATCH 1/4] chore: remove ancient docker integration in `misc` (#3172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR removes the ancient docker integration test contained in `misc` that fails, and a random docker compose, also in `misc`. This test package is actually never even run on `master`, because it requires a specific build flag `docker` 🤷‍♂️ Closes #3161
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--- .github/workflows/misc.yml | 20 +- go.mod | 2 +- misc/docker-compose/docker-compose.yml | 25 --- misc/docker-integration/Makefile | 2 - misc/docker-integration/README.md | 5 - misc/docker-integration/integration.go | 1 - misc/docker-integration/integration_test.go | 191 -------------------- 7 files changed, 10 insertions(+), 236 deletions(-) delete mode 100644 misc/docker-compose/docker-compose.yml delete mode 100644 misc/docker-integration/Makefile delete mode 100644 misc/docker-integration/README.md delete mode 100644 misc/docker-integration/integration.go delete mode 100644 misc/docker-integration/integration_test.go diff --git a/.github/workflows/misc.yml b/.github/workflows/misc.yml index 859e1429983..ad2c886e2ac 100644 --- a/.github/workflows/misc.yml +++ b/.github/workflows/misc.yml @@ -12,17 +12,15 @@ on: jobs: main: strategy: - fail-fast: false - matrix: - # fixed list because we have some non go programs on that misc folder - program: - - autocounterd - # - devdeps - - docker-integration - - genproto - - genstd - - goscan - - loop + fail-fast: false + matrix: + # fixed list because we have some non go programs on that misc folder + program: + - autocounterd + - genproto + - genstd + - goscan + - loop name: Run Main uses: ./.github/workflows/main_template.yml with: diff --git a/go.mod b/go.mod index 24d09a87236..f73ba1926e6 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,6 @@ require ( golang.org/x/term v0.23.0 golang.org/x/tools v0.24.0 google.golang.org/protobuf v1.35.1 - gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -69,4 +68,5 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/grpc v1.65.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/misc/docker-compose/docker-compose.yml b/misc/docker-compose/docker-compose.yml deleted file mode 100644 index 470aeaf3127..00000000000 --- a/misc/docker-compose/docker-compose.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: "3.7" -services: - gnonode: - container_name: gnoland-node - build: - context: . - dockerfile: ../..Dockerfile - environment: - - LOG_LEVEL=4 - command: [ "gnoland", "start" ] - volumes: - - "gnonode:/opt/gno/src/gnoland-data" - networks: - - gnonode - restart: on-failure - logging: - driver: "json-file" - options: - max-file: "10" - max-size: "100m" - -networks: - gnonode: {} -volumes: - gnonode: {} diff --git a/misc/docker-integration/Makefile b/misc/docker-integration/Makefile deleted file mode 100644 index cd620d9be9f..00000000000 --- a/misc/docker-integration/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -test: - go test --tags=docker -v . diff --git a/misc/docker-integration/README.md b/misc/docker-integration/README.md deleted file mode 100644 index 21138ed033b..00000000000 --- a/misc/docker-integration/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# docker-integration - -This folder contains tests that runs integration tests inside Docker, using the CLIs. - -We encourage to keep the tests simple and focusing on cross-component testing. diff --git a/misc/docker-integration/integration.go b/misc/docker-integration/integration.go deleted file mode 100644 index 76ab1b7282d..00000000000 --- a/misc/docker-integration/integration.go +++ /dev/null @@ -1 +0,0 @@ -package integration diff --git a/misc/docker-integration/integration_test.go b/misc/docker-integration/integration_test.go deleted file mode 100644 index 973cb386e9b..00000000000 --- a/misc/docker-integration/integration_test.go +++ /dev/null @@ -1,191 +0,0 @@ -//go:build docker - -package integration - -import ( - "encoding/json" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" - "github.com/gnolang/gno/tm2/pkg/amino" - "github.com/gnolang/gno/tm2/pkg/std" - "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" -) - -const ( - gnolandContainerName = "int_gnoland" - - test1Addr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" - test1Seed = "source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast" - dockerWaitTimeout = 30 -) - -func TestDockerIntegration(t *testing.T) { - t.Parallel() - - tmpdir, err := os.MkdirTemp(os.TempDir(), "*-gnoland-integration") - require.NoError(t, err) - - checkDocker(t) - cleanupGnoland(t) - buildDockerImage(t) - startGnoland(t) - waitGnoland(t) - - runSuite(t, tmpdir) -} - -func runSuite(t *testing.T, tempdir string) { - t.Helper() - - // add test1 account to docker container keys with "pass" password - dockerExec(t, fmt.Sprintf( - `echo "pass\npass\n%s\n" | gnokey add -recover -insecure-password-stdin test1`, - test1Seed, - )) - // assert test1 account exists - var acc gnoland.GnoAccount - dockerExec_gnokeyQuery(t, "auth/accounts/"+test1Addr, &acc) - require.Equal(t, test1Addr, acc.Address.String(), "test1 account not found") - - // This value is chosen arbitrarily and may not be optimal. - // Feel free to update it to a more suitable amount. - minCoins := std.MustParseCoins(ugnot.ValueString(9990000000000)) - 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 - 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 \ - -deposit 100000000ugnot \ - test1`, - ) - // assert gno.land/r/demo/tests_copy 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") - - // 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" \ - test1`, - ) -} - -func checkDocker(t *testing.T) { - t.Helper() - output, err := createCommand(t, []string{"docker", "info"}).CombinedOutput() - require.NoError(t, err, "docker daemon not running: %s", string(output)) -} - -func buildDockerImage(t *testing.T) { - t.Helper() - - cmd := createCommand(t, []string{ - "docker", - "build", - "-t", "gno:integration", - filepath.Join("..", ".."), - }) - output, err := cmd.CombinedOutput() - require.NoError(t, err, string(output)) -} - -// dockerExec runs docker exec with cmd as argument -func dockerExec(t *testing.T, cmd string) []byte { - t.Helper() - - cmds := append( - []string{"docker", "exec", gnolandContainerName, "sh", "-c"}, - cmd, - ) - bz, err := createCommand(t, cmds).CombinedOutput() - require.NoError(t, err, string(bz)) - return bz -} - -// dockerExec_gnokeyQuery runs dockerExec with gnokey query prefix and parses -// the command output to out. -func dockerExec_gnokeyQuery(t *testing.T, cmd string, out any) { - t.Helper() - - output := dockerExec(t, "gnokey query "+cmd) - // parses the output of gnokey query: - // height: h - // data: { JSON } - var resp struct { - Height int64 `yaml:"height"` - Data any `yaml:"data"` - } - err := yaml.Unmarshal(output, &resp) - require.NoError(t, err) - bz, err := json.Marshal(resp.Data) - require.NoError(t, err) - err = amino.UnmarshalJSON(bz, out) - require.NoError(t, err) -} - -func createCommand(t *testing.T, args []string) *exec.Cmd { - t.Helper() - msg := strings.Join(args, " ") - t.Log(msg) - return exec.Command(args[0], args[1:]...) -} - -func startGnoland(t *testing.T) { - t.Helper() - - cmd := createCommand(t, []string{ - "docker", "run", - "-d", - "--name", gnolandContainerName, - "-w", "/opt/gno/src/gno.land", - "gno:integration", - "gnoland", - "start", - }) - output, err := cmd.CombinedOutput() - require.NoError(t, err) - require.NotEmpty(t, string(output)) // should be the hash of the container. - - // t.Cleanup(func() { cleanupGnoland(t) }) -} - -func waitGnoland(t *testing.T) { - t.Helper() - t.Log("waiting...") - for i := 0; i < dockerWaitTimeout; i++ { - output, _ := createCommand(t, - []string{"docker", "logs", gnolandContainerName}, - ).CombinedOutput() - if strings.Contains(string(output), "Committed state") { - // ok blockchain is ready - t.Log("gnoland ready") - return - } - time.Sleep(time.Second) - } - // cleanupGnoland(t) - panic("gnoland start timeout") -} - -func cleanupGnoland(t *testing.T) { - t.Helper() - createCommand(t, []string{"docker", "rm", "-f", gnolandContainerName}).Run() -} From a723673b115221f426b34ae51b794995a156933d Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Mon, 25 Nov 2024 06:47:54 +0100 Subject: [PATCH 2/4] chore: revert "fix(portal-loop): hotfix revert "chore: rename r/manfred -> r/moul (#2820)" (#2865)" (#3024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 69400d468d7bf82ce359eaf7cb092ac545785b10. Revertception.
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--------- Signed-off-by: moul <94029+moul@users.noreply.github.com> Co-authored-by: Miloš Živković --- examples/gno.land/r/demo/foo20/foo20.gno | 2 +- examples/gno.land/r/demo/foo20/foo20_test.gno | 4 +- .../gno.land/r/demo/groups/z_1_a_filetest.gno | 2 +- .../gno.land/r/demo/groups/z_2_a_filetest.gno | 2 +- examples/gno.land/r/demo/users/users.gno | 2 +- .../gno.land/r/demo/users/z_10_filetest.gno | 2 +- .../gno.land/r/demo/users/z_11_filetest.gno | 2 +- .../gno.land/r/demo/users/z_11b_filetest.gno | 2 +- .../gno.land/r/demo/users/z_2_filetest.gno | 2 +- .../gno.land/r/demo/users/z_3_filetest.gno | 2 +- .../gno.land/r/demo/users/z_4_filetest.gno | 2 +- .../gno.land/r/demo/users/z_5_filetest.gno | 2 +- .../gno.land/r/demo/users/z_6_filetest.gno | 2 +- .../gno.land/r/demo/users/z_7_filetest.gno | 2 +- .../gno.land/r/demo/users/z_7b_filetest.gno | 2 +- .../gno.land/r/demo/users/z_8_filetest.gno | 2 +- .../gno.land/r/demo/users/z_9_filetest.gno | 2 +- examples/gno.land/r/gnoland/blog/admin.gno | 2 +- .../gno.land/r/gnoland/blog/gnoblog_test.gno | 16 ++--- examples/gno.land/r/gnoland/home/home.gno | 2 +- .../r/gnoland/home/overide_filetest.gno | 2 +- examples/gno.land/r/gnoland/pages/admin.gno | 2 +- examples/gno.land/r/manfred/config/gno.mod | 1 - examples/gno.land/r/manfred/home/gno.mod | 5 -- examples/gno.land/r/manfred/home/home.gno | 57 +----------------- .../gno.land/r/{manfred => moul}/README.md | 0 .../r/{manfred => moul}/config/config.gno | 2 +- examples/gno.land/r/moul/config/gno.mod | 1 + examples/gno.land/r/moul/home/gno.mod | 6 ++ examples/gno.land/r/moul/home/home.gno | 60 +++++++++++++++++++ .../r/{manfred => moul}/home/z1_filetest.gno | 2 +- .../r/{manfred => moul}/home/z2_filetest.gno | 4 +- .../r/{manfred => moul}/present/admin.gno | 2 +- .../r/{manfred => moul}/present/gno.mod | 2 +- .../present/present_miami23.gno | 0 .../present/present_miami23_filetest.gno | 2 +- .../present/presentations.gno | 2 +- examples/gno.land/r/sys/users/verify.gno | 2 +- .../gnoland/testdata/addpkg_namespace.txtar | 2 +- gno.land/genesis/genesis_balances.txt | 3 +- gno.land/genesis/genesis_txs.jsonl | 16 ++--- gno.land/pkg/gnoweb/gnoweb_test.go | 2 +- .../integration/testdata/adduserfrom.txtar | 4 +- 43 files changed, 121 insertions(+), 114 deletions(-) delete mode 100644 examples/gno.land/r/manfred/config/gno.mod mode change 100644 => 100755 examples/gno.land/r/manfred/home/home.gno rename examples/gno.land/r/{manfred => moul}/README.md (100%) rename examples/gno.land/r/{manfred => moul}/config/config.gno (75%) create mode 100644 examples/gno.land/r/moul/config/gno.mod create mode 100644 examples/gno.land/r/moul/home/gno.mod create mode 100644 examples/gno.land/r/moul/home/home.gno rename examples/gno.land/r/{manfred => moul}/home/z1_filetest.gno (88%) rename examples/gno.land/r/{manfred => moul}/home/z2_filetest.gno (84%) rename examples/gno.land/r/{manfred => moul}/present/admin.gno (97%) rename examples/gno.land/r/{manfred => moul}/present/gno.mod (71%) rename examples/gno.land/r/{manfred => moul}/present/present_miami23.gno (100%) rename examples/gno.land/r/{manfred => moul}/present/present_miami23_filetest.gno (84%) rename examples/gno.land/r/{manfred => moul}/present/presentations.gno (86%) diff --git a/examples/gno.land/r/demo/foo20/foo20.gno b/examples/gno.land/r/demo/foo20/foo20.gno index fe099117215..31fa577c515 100644 --- a/examples/gno.land/r/demo/foo20/foo20.gno +++ b/examples/gno.land/r/demo/foo20/foo20.gno @@ -16,7 +16,7 @@ import ( var ( Token, privateLedger = grc20.NewToken("Foo", "FOO", 4) UserTeller = Token.CallerTeller() - owner = ownable.NewWithAddress("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") // @manfred + owner = ownable.NewWithAddress("g1manfred47kzduec920z88wfr64ylksmdcedlf5") // @manfred ) func init() { diff --git a/examples/gno.land/r/demo/foo20/foo20_test.gno b/examples/gno.land/r/demo/foo20/foo20_test.gno index b3346296b04..b9e80fbb476 100644 --- a/examples/gno.land/r/demo/foo20/foo20_test.gno +++ b/examples/gno.land/r/demo/foo20/foo20_test.gno @@ -12,7 +12,7 @@ import ( func TestReadOnlyPublicMethods(t *testing.T) { var ( - admin = pusers.AddressOrName("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") + admin = pusers.AddressOrName("g1manfred47kzduec920z88wfr64ylksmdcedlf5") alice = pusers.AddressOrName(testutils.TestAddress("alice")) bob = pusers.AddressOrName(testutils.TestAddress("bob")) ) @@ -60,7 +60,7 @@ func TestReadOnlyPublicMethods(t *testing.T) { func TestErrConditions(t *testing.T) { var ( - admin = pusers.AddressOrName("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") + admin = pusers.AddressOrName("g1manfred47kzduec920z88wfr64ylksmdcedlf5") alice = pusers.AddressOrName(testutils.TestAddress("alice")) empty = pusers.AddressOrName("") ) diff --git a/examples/gno.land/r/demo/groups/z_1_a_filetest.gno b/examples/gno.land/r/demo/groups/z_1_a_filetest.gno index aeff9ab7774..18799e31a67 100644 --- a/examples/gno.land/r/demo/groups/z_1_a_filetest.gno +++ b/examples/gno.land/r/demo/groups/z_1_a_filetest.gno @@ -13,7 +13,7 @@ import ( var gid groups.GroupID -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/groups/z_2_a_filetest.gno b/examples/gno.land/r/demo/groups/z_2_a_filetest.gno index d1cc53d612f..7c97b01ccf5 100644 --- a/examples/gno.land/r/demo/groups/z_2_a_filetest.gno +++ b/examples/gno.land/r/demo/groups/z_2_a_filetest.gno @@ -13,7 +13,7 @@ import ( var gid groups.GroupID -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/users.gno b/examples/gno.land/r/demo/users/users.gno index daad2e7fc18..1f08c9ae08c 100644 --- a/examples/gno.land/r/demo/users/users.gno +++ b/examples/gno.land/r/demo/users/users.gno @@ -16,7 +16,7 @@ import ( // State var ( - admin std.Address = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" // @moul + admin std.Address = "g1manfred47kzduec920z88wfr64ylksmdcedlf5" // @moul restricted avl.Tree // Name -> true - restricted name name2User avl.Tree // Name -> *users.User diff --git a/examples/gno.land/r/demo/users/z_10_filetest.gno b/examples/gno.land/r/demo/users/z_10_filetest.gno index 078058c0703..afeecffcc42 100644 --- a/examples/gno.land/r/demo/users/z_10_filetest.gno +++ b/examples/gno.land/r/demo/users/z_10_filetest.gno @@ -8,7 +8,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func init() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_11_filetest.gno b/examples/gno.land/r/demo/users/z_11_filetest.gno index 603d63f371d..27c7e9813da 100644 --- a/examples/gno.land/r/demo/users/z_11_filetest.gno +++ b/examples/gno.land/r/demo/users/z_11_filetest.gno @@ -8,7 +8,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_11b_filetest.gno b/examples/gno.land/r/demo/users/z_11b_filetest.gno index 5e661e8f8c1..be508963911 100644 --- a/examples/gno.land/r/demo/users/z_11b_filetest.gno +++ b/examples/gno.land/r/demo/users/z_11b_filetest.gno @@ -8,7 +8,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_2_filetest.gno b/examples/gno.land/r/demo/users/z_2_filetest.gno index 84b62a7e483..c1b92790f8b 100644 --- a/examples/gno.land/r/demo/users/z_2_filetest.gno +++ b/examples/gno.land/r/demo/users/z_2_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_3_filetest.gno b/examples/gno.land/r/demo/users/z_3_filetest.gno index ce34c6bba66..5402235e03d 100644 --- a/examples/gno.land/r/demo/users/z_3_filetest.gno +++ b/examples/gno.land/r/demo/users/z_3_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_4_filetest.gno b/examples/gno.land/r/demo/users/z_4_filetest.gno index 1a46d915c96..613fadf9625 100644 --- a/examples/gno.land/r/demo/users/z_4_filetest.gno +++ b/examples/gno.land/r/demo/users/z_4_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_5_filetest.gno b/examples/gno.land/r/demo/users/z_5_filetest.gno index 2b3e1b17b5c..dcb957f2155 100644 --- a/examples/gno.land/r/demo/users/z_5_filetest.gno +++ b/examples/gno.land/r/demo/users/z_5_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_6_filetest.gno b/examples/gno.land/r/demo/users/z_6_filetest.gno index 85305fff1ad..919088088a2 100644 --- a/examples/gno.land/r/demo/users/z_6_filetest.gno +++ b/examples/gno.land/r/demo/users/z_6_filetest.gno @@ -6,7 +6,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() diff --git a/examples/gno.land/r/demo/users/z_7_filetest.gno b/examples/gno.land/r/demo/users/z_7_filetest.gno index 3332ab49af4..1d3c9e3a917 100644 --- a/examples/gno.land/r/demo/users/z_7_filetest.gno +++ b/examples/gno.land/r/demo/users/z_7_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_7b_filetest.gno b/examples/gno.land/r/demo/users/z_7b_filetest.gno index 60a397abe79..09c15bb135d 100644 --- a/examples/gno.land/r/demo/users/z_7b_filetest.gno +++ b/examples/gno.land/r/demo/users/z_7b_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_8_filetest.gno b/examples/gno.land/r/demo/users/z_8_filetest.gno index 1eaa017b7d2..78fada74a71 100644 --- a/examples/gno.land/r/demo/users/z_8_filetest.gno +++ b/examples/gno.land/r/demo/users/z_8_filetest.gno @@ -9,7 +9,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/demo/users/z_9_filetest.gno b/examples/gno.land/r/demo/users/z_9_filetest.gno index 2bd9bf555dc..c73c685aebd 100644 --- a/examples/gno.land/r/demo/users/z_9_filetest.gno +++ b/examples/gno.land/r/demo/users/z_9_filetest.gno @@ -7,7 +7,7 @@ import ( "gno.land/r/demo/users" ) -const admin = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +const admin = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") func main() { caller := std.GetOrigCaller() // main diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 9c94a265fca..87d465449f3 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -18,7 +18,7 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. - adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" + adminAddr = "g1manfred47kzduec920z88wfr64ylksmdcedlf5" // @moul } func AdminSetAdminAddr(addr std.Address) { diff --git a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno index 15688ca4bc7..328fbe2baa4 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno @@ -7,7 +7,7 @@ import ( ) func TestPackage(t *testing.T) { - std.TestSetOrigCaller(std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq")) + std.TestSetOrigCaller(std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5")) author := std.GetOrigCaller() @@ -59,7 +59,7 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) Written by moul on 20 May 2022 -Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog +Published by g1manfred47kzduec920z88wfr64ylksmdcedlf5 to Gnoland's Blog ---
Comment section @@ -110,20 +110,20 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) Written by moul on 20 May 2022 -Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog +Published by g1manfred47kzduec920z88wfr64ylksmdcedlf5 to Gnoland's Blog ---
Comment section
comment4 -
by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 13 Feb 09 23:31 UTC
+
by g1manfred47kzduec920z88wfr64ylksmdcedlf5 on 13 Feb 09 23:31 UTC
---
comment2 -
by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 13 Feb 09 23:31 UTC
+
by g1manfred47kzduec920z88wfr64ylksmdcedlf5 on 13 Feb 09 23:31 UTC
--- @@ -152,20 +152,20 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag4](/r/gnoland/blog:t/tag4) Written by manfred on 20 May 2022 -Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog +Published by g1manfred47kzduec920z88wfr64ylksmdcedlf5 to Gnoland's Blog ---
Comment section
comment4 -
by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 13 Feb 09 23:31 UTC
+
by g1manfred47kzduec920z88wfr64ylksmdcedlf5 on 13 Feb 09 23:31 UTC
---
comment2 -
by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 13 Feb 09 23:31 UTC
+
by g1manfred47kzduec920z88wfr64ylksmdcedlf5 on 13 Feb 09 23:31 UTC
--- diff --git a/examples/gno.land/r/gnoland/home/home.gno b/examples/gno.land/r/gnoland/home/home.gno index 04c549a0d27..6a520dba394 100644 --- a/examples/gno.land/r/gnoland/home/home.gno +++ b/examples/gno.land/r/gnoland/home/home.gno @@ -17,7 +17,7 @@ import ( var ( override string - admin = ownable.NewWithAddress("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") // @manfred by default + admin = ownable.NewWithAddress("g1manfred47kzduec920z88wfr64ylksmdcedlf5") // @moul ) func Render(_ string) string { diff --git a/examples/gno.land/r/gnoland/home/overide_filetest.gno b/examples/gno.land/r/gnoland/home/overide_filetest.gno index 4f21b90a3c2..be7e33501d6 100644 --- a/examples/gno.land/r/gnoland/home/overide_filetest.gno +++ b/examples/gno.land/r/gnoland/home/overide_filetest.gno @@ -8,7 +8,7 @@ import ( ) func main() { - std.TestSetOrigCaller("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") + std.TestSetOrigCaller("g1manfred47kzduec920z88wfr64ylksmdcedlf5") home.AdminSetOverride("Hello World!") println(home.Render("")) home.AdminTransferOwnership(testutils.TestAddress("newAdmin")) diff --git a/examples/gno.land/r/gnoland/pages/admin.gno b/examples/gno.land/r/gnoland/pages/admin.gno index ab447e8f604..71050f4ef57 100644 --- a/examples/gno.land/r/gnoland/pages/admin.gno +++ b/examples/gno.land/r/gnoland/pages/admin.gno @@ -15,7 +15,7 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. - adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" + adminAddr = "g1manfred47kzduec920z88wfr64ylksmdcedlf5" // @moul } func AdminSetAdminAddr(addr std.Address) { diff --git a/examples/gno.land/r/manfred/config/gno.mod b/examples/gno.land/r/manfred/config/gno.mod deleted file mode 100644 index 516bf38528e..00000000000 --- a/examples/gno.land/r/manfred/config/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/manfred/config diff --git a/examples/gno.land/r/manfred/home/gno.mod b/examples/gno.land/r/manfred/home/gno.mod index 0ef23834fb5..2efefe1824f 100644 --- a/examples/gno.land/r/manfred/home/gno.mod +++ b/examples/gno.land/r/manfred/home/gno.mod @@ -1,6 +1 @@ module gno.land/r/manfred/home - -require ( - gno.land/r/leon/hof v0.0.0-latest - gno.land/r/manfred/config v0.0.0-latest -) diff --git a/examples/gno.land/r/manfred/home/home.gno b/examples/gno.land/r/manfred/home/home.gno old mode 100644 new mode 100755 index 3e29636439d..56caf30d9fd --- a/examples/gno.land/r/manfred/home/home.gno +++ b/examples/gno.land/r/manfred/home/home.gno @@ -1,60 +1,5 @@ package home -import ( - "gno.land/r/leon/hof" - "gno.land/r/manfred/config" -) - -var ( - todos []string - status string - memeImgURL string -) - -func init() { - todos = append(todos, "fill this todo list...") - status = "Online" // Initial status set to "Online" - memeImgURL = "https://i.imgflip.com/7ze8dc.jpg" - hof.Register() -} - func Render(path string) string { - content := "# Manfred's (gn)home Dashboard\n\n" - - content += "## Meme\n" - content += "![](" + memeImgURL + ")\n\n" - - content += "## Status\n" - content += status + "\n\n" - - content += "## Personal ToDo List\n" - for _, todo := range todos { - content += "- [ ] " + todo + "\n" - } - content += "\n" - - // TODO: Implement a feature to list replies on r/boards on my posts - // TODO: Maybe integrate a calendar feature for upcoming events? - - return content -} - -func AddNewTodo(todo string) { - config.AssertIsAdmin() - todos = append(todos, todo) -} - -func DeleteTodo(todoIndex int) { - config.AssertIsAdmin() - if todoIndex >= 0 && todoIndex < len(todos) { - // Remove the todo from the list by merging slices from before and after the todo - todos = append(todos[:todoIndex], todos[todoIndex+1:]...) - } else { - panic("Invalid todo index") - } -} - -func UpdateStatus(newStatus string) { - config.AssertIsAdmin() - status = newStatus + return "Moved to r/moul" } diff --git a/examples/gno.land/r/manfred/README.md b/examples/gno.land/r/moul/README.md similarity index 100% rename from examples/gno.land/r/manfred/README.md rename to examples/gno.land/r/moul/README.md diff --git a/examples/gno.land/r/manfred/config/config.gno b/examples/gno.land/r/moul/config/config.gno similarity index 75% rename from examples/gno.land/r/manfred/config/config.gno rename to examples/gno.land/r/moul/config/config.gno index 23e90df50ff..a4f24411747 100644 --- a/examples/gno.land/r/manfred/config/config.gno +++ b/examples/gno.land/r/moul/config/config.gno @@ -2,7 +2,7 @@ package config import "std" -var addr = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") +var addr = std.Address("g1manfred47kzduec920z88wfr64ylksmdcedlf5") // @moul func Addr() std.Address { return addr diff --git a/examples/gno.land/r/moul/config/gno.mod b/examples/gno.land/r/moul/config/gno.mod new file mode 100644 index 00000000000..2029efc8fcb --- /dev/null +++ b/examples/gno.land/r/moul/config/gno.mod @@ -0,0 +1 @@ +module gno.land/r/moul/config diff --git a/examples/gno.land/r/moul/home/gno.mod b/examples/gno.land/r/moul/home/gno.mod new file mode 100644 index 00000000000..f42a2c2ced8 --- /dev/null +++ b/examples/gno.land/r/moul/home/gno.mod @@ -0,0 +1,6 @@ +module gno.land/r/moul/home + +require ( + gno.land/r/leon/hof v0.0.0-latest + gno.land/r/moul/config v0.0.0-latest +) diff --git a/examples/gno.land/r/moul/home/home.gno b/examples/gno.land/r/moul/home/home.gno new file mode 100644 index 00000000000..140e7b5e0c8 --- /dev/null +++ b/examples/gno.land/r/moul/home/home.gno @@ -0,0 +1,60 @@ +package home + +import ( + "gno.land/r/leon/hof" + "gno.land/r/moul/config" +) + +var ( + todos []string + status string + memeImgURL string +) + +func init() { + todos = append(todos, "fill this todo list...") + status = "Online" // Initial status set to "Online" + memeImgURL = "https://i.imgflip.com/7ze8dc.jpg" + hof.Register() +} + +func Render(path string) string { + content := "# Manfred's (gn)home Dashboard\n\n" + + content += "## Meme\n" + content += "![](" + memeImgURL + ")\n\n" + + content += "## Status\n" + content += status + "\n\n" + + content += "## Personal ToDo List\n" + for _, todo := range todos { + content += "- [ ] " + todo + "\n" + } + content += "\n" + + // TODO: Implement a feature to list replies on r/boards on my posts + // TODO: Maybe integrate a calendar feature for upcoming events? + + return content +} + +func AddNewTodo(todo string) { + config.AssertIsAdmin() + todos = append(todos, todo) +} + +func DeleteTodo(todoIndex int) { + config.AssertIsAdmin() + if todoIndex >= 0 && todoIndex < len(todos) { + // Remove the todo from the list by merging slices from before and after the todo + todos = append(todos[:todoIndex], todos[todoIndex+1:]...) + } else { + panic("Invalid todo index") + } +} + +func UpdateStatus(newStatus string) { + config.AssertIsAdmin() + status = newStatus +} diff --git a/examples/gno.land/r/manfred/home/z1_filetest.gno b/examples/gno.land/r/moul/home/z1_filetest.gno similarity index 88% rename from examples/gno.land/r/manfred/home/z1_filetest.gno rename to examples/gno.land/r/moul/home/z1_filetest.gno index 801efedb306..5203e07ada7 100644 --- a/examples/gno.land/r/manfred/home/z1_filetest.gno +++ b/examples/gno.land/r/moul/home/z1_filetest.gno @@ -1,6 +1,6 @@ package main -import "gno.land/r/manfred/home" +import "gno.land/r/moul/home" func main() { println(home.Render("")) diff --git a/examples/gno.land/r/manfred/home/z2_filetest.gno b/examples/gno.land/r/moul/home/z2_filetest.gno similarity index 84% rename from examples/gno.land/r/manfred/home/z2_filetest.gno rename to examples/gno.land/r/moul/home/z2_filetest.gno index 316fd400867..02d08cd591e 100644 --- a/examples/gno.land/r/manfred/home/z2_filetest.gno +++ b/examples/gno.land/r/moul/home/z2_filetest.gno @@ -3,11 +3,11 @@ package main import ( "std" - "gno.land/r/manfred/home" + "gno.land/r/moul/home" ) func main() { - std.TestSetOrigCaller("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") + std.TestSetOrigCaller("g1manfred47kzduec920z88wfr64ylksmdcedlf5") home.AddNewTodo("aaa") home.AddNewTodo("bbb") home.AddNewTodo("ccc") diff --git a/examples/gno.land/r/manfred/present/admin.gno b/examples/gno.land/r/moul/present/admin.gno similarity index 97% rename from examples/gno.land/r/manfred/present/admin.gno rename to examples/gno.land/r/moul/present/admin.gno index 60af578b54f..ab99b1725c5 100644 --- a/examples/gno.land/r/manfred/present/admin.gno +++ b/examples/gno.land/r/moul/present/admin.gno @@ -15,7 +15,7 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. - adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" + adminAddr = "g1manfred47kzduec920z88wfr64ylksmdcedlf5" } func AdminSetAdminAddr(addr std.Address) { diff --git a/examples/gno.land/r/manfred/present/gno.mod b/examples/gno.land/r/moul/present/gno.mod similarity index 71% rename from examples/gno.land/r/manfred/present/gno.mod rename to examples/gno.land/r/moul/present/gno.mod index 5d50447e0e0..3ae0bf2e64d 100644 --- a/examples/gno.land/r/manfred/present/gno.mod +++ b/examples/gno.land/r/moul/present/gno.mod @@ -1,4 +1,4 @@ -module gno.land/r/manfred/present +module gno.land/r/moul/present require ( gno.land/p/demo/avl v0.0.0-latest diff --git a/examples/gno.land/r/manfred/present/present_miami23.gno b/examples/gno.land/r/moul/present/present_miami23.gno similarity index 100% rename from examples/gno.land/r/manfred/present/present_miami23.gno rename to examples/gno.land/r/moul/present/present_miami23.gno diff --git a/examples/gno.land/r/manfred/present/present_miami23_filetest.gno b/examples/gno.land/r/moul/present/present_miami23_filetest.gno similarity index 84% rename from examples/gno.land/r/manfred/present/present_miami23_filetest.gno rename to examples/gno.land/r/moul/present/present_miami23_filetest.gno index ac19d83ade4..09d332ec6e4 100644 --- a/examples/gno.land/r/manfred/present/present_miami23_filetest.gno +++ b/examples/gno.land/r/moul/present/present_miami23_filetest.gno @@ -1,7 +1,7 @@ package main import ( - "gno.land/r/manfred/present" + "gno.land/r/moul/present" ) func main() { diff --git a/examples/gno.land/r/manfred/present/presentations.gno b/examples/gno.land/r/moul/present/presentations.gno similarity index 86% rename from examples/gno.land/r/manfred/present/presentations.gno rename to examples/gno.land/r/moul/present/presentations.gno index 8a99f502e86..c5529804751 100644 --- a/examples/gno.land/r/manfred/present/presentations.gno +++ b/examples/gno.land/r/moul/present/presentations.gno @@ -8,7 +8,7 @@ import ( var b = &blog.Blog{ Title: "Manfred's Presentations", - Prefix: "/r/manfred/present:", + Prefix: "/r/moul/present:", NoBreadcrumb: true, } diff --git a/examples/gno.land/r/sys/users/verify.gno b/examples/gno.land/r/sys/users/verify.gno index 852626622e4..a836e84683d 100644 --- a/examples/gno.land/r/sys/users/verify.gno +++ b/examples/gno.land/r/sys/users/verify.gno @@ -7,7 +7,7 @@ import ( "gno.land/r/demo/users" ) -const admin = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" // @moul +const admin = "g1manfred47kzduec920z88wfr64ylksmdcedlf5" // @moul type VerifyNameFunc func(enabled bool, address std.Address, name string) bool diff --git a/gno.land/cmd/gnoland/testdata/addpkg_namespace.txtar b/gno.land/cmd/gnoland/testdata/addpkg_namespace.txtar index 5a88fd6d603..d207289e0ff 100644 --- a/gno.land/cmd/gnoland/testdata/addpkg_namespace.txtar +++ b/gno.land/cmd/gnoland/testdata/addpkg_namespace.txtar @@ -4,7 +4,7 @@ loadpkg gno.land/r/sys/users adduser admin adduser gui -patchpkg "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" $USER_ADDR_admin # use our custom admin +patchpkg "g1manfred47kzduec920z88wfr64ylksmdcedlf5" $USER_ADDR_admin # use our custom admin gnoland start diff --git a/gno.land/genesis/genesis_balances.txt b/gno.land/genesis/genesis_balances.txt index fa3232149c1..c372d7f9fd7 100644 --- a/gno.land/genesis/genesis_balances.txt +++ b/gno.land/genesis/genesis_balances.txt @@ -16,7 +16,8 @@ g13d7jc32adhc39erm5me38w5v7ej7lpvlnqjk73=1000000000000ugnot # faucet3 (devx) g18l9us6trqaljw39j94wzf5ftxmd9qqkvrxghd2=1000000000000ugnot # faucet4 (adena) # Contributors premine & GitHub requests (closed). -g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq=10000000000ugnot # @moul +g1manfred47kzduec920z88wfr64ylksmdcedlf5=10000000000ugnot # @moul +g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq=10000000000ugnot # @manfred g14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa=10000000000ugnot # @piux2 g15gdm49ktawvkrl88jadqpucng37yxutucuwaef=10000000000ugnot # @chadwick g1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s=10000000000ugnot # @mefodica #83 diff --git a/gno.land/genesis/genesis_txs.jsonl b/gno.land/genesis/genesis_txs.jsonl index fa2c9e83fbd..9027d51c0ac 100644 --- a/gno.land/genesis/genesis_txs.jsonl +++ b/gno.land/genesis/genesis_txs.jsonl @@ -1,17 +1,17 @@ -{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj:10\ng1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s: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\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa:10\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t:5\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"S8iMMzlOMK8dmox78R9Z8+pSsS8YaTCXrIcaHDpiOgkOy7gqoQJ0oftM0zf8zAz4xpezK8Lzg8Q0fCdXJxV76w=="}],"memo":""}} -{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","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":""}} -{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","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":""}} +{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1manfred47kzduec920z88wfr64ylksmdcedlf5","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj:10\ng1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s: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\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa:10\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t:5\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"S8iMMzlOMK8dmox78R9Z8+pSsS8YaTCXrIcaHDpiOgkOy7gqoQJ0oftM0zf8zAz4xpezK8Lzg8Q0fCdXJxV76w=="}],"memo":""}} +{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1manfred47kzduec920z88wfr64ylksmdcedlf5","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1thlf3yct7n7ex70k0p62user0kn6mj6d3s0cg3\ng1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\ng1manfred47kzduec920z88wfr64ylksmdcedlf5\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":""}} +{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1manfred47kzduec920z88wfr64ylksmdcedlf5","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\ng1manfred47kzduec920z88wfr64ylksmdcedlf5\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t\n"]}],"fee":{"gas_wanted":"4000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"7AmlhZhsVkxCUl0bbpvpPMnIKihwtG7A5IFR6Tg4xStWLgaUr05XmWRKlO2xjstTtwbVKQT5mFL4h5wyX4SQzw=="}],"memo":""}} {"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"200000000ugnot","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":""}} {"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt","send":"200000000ugnot","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":""}} -{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"200000000ugnot","pkg_path":"gno.land/r/demo/users","func":"Register","args":["","manfred","https://github.com/moul"]}],"fee":{"gas_wanted":"2000000","gas_fee":"200000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"9CWeNbKx+hEL+RdHplAVAFntcrAVx5mK9tMqoywuHVoreH844n3yOxddQrGfBk6T2tMBmNWakERRqWZfS+bYAQ=="}],"memo":""}} +{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1manfred47kzduec920z88wfr64ylksmdcedlf5","send":"200000000ugnot","pkg_path":"gno.land/r/demo/users","func":"Register","args":["g1manfred47kzduec920z88wfr64ylksmdcedlf5","moul","https://github.com/moul"]}],"fee":{"gas_wanted":"2000000","gas_fee":"200000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"9CWeNbKx+hEL+RdHplAVAFntcrAVx5mK9tMqoywuHVoreH844n3yOxddQrGfBk6T2tMBmNWakERRqWZfS+bYAQ=="}],"memo":""}} {"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9","send":"200000000ugnot","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":""}} -{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5","send":"","pkg_path":"gno.land/r/demo/users","func":"Register","args":["g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","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":""}} +{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5","send":"","pkg_path":"gno.land/r/demo/users","func":"Register","args":["g1manfred47kzduec920z88wfr64ylksmdcedlf5","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":""}} {"tx": {"msg":[{"@type":"/vm.m_call","caller":"g15gdm49ktawvkrl88jadqpucng37yxutucuwaef","send":"200000000ugnot","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":""}} {"tx": {"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":""}} {"tx": {"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.GetBoardIDFromName(\\\"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:testboard/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:testboard\"\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"V43B1waFxhzheW9TfmCpjLdrC4dC1yjUGES5y3J6QsNar6hRpNz4G1thzWmWK7xXhg8u1PCIpxLxGczKQYhuPw=="}],"memo":""}} {"tx": {"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":""}} {"tx": {"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/demo/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/demo/banktest:](/r/demo/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/demo/banktest](/r/demo/banktest) and the [quickstart guide](/r/demo/boards:testboard/4).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"iZX/llZlNTdZMLv1goCTgK2bWqzT8enlTq56wMTCpVxJGA0BTvuEM5Nnt9vrnlG6Taqj2GuTrmEnJBkDFTmt9g=="}],"memo":""}} {"tx": {"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":""}} -{"tx": {"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\u0026func=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.GetBoardIDFromName(\\\"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\u0026func=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\u0026func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards:BOARDNAME/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:gnolang\"\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":""}} -{"tx": {"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":""}} -{"tx": {"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":""}} +{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1manfred47kzduec920z88wfr64ylksmdcedlf5","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\u0026func=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.GetBoardIDFromName(\\\"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\u0026func=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\u0026func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards:BOARDNAME/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:gnolang\"\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":""}} +{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1manfred47kzduec920z88wfr64ylksmdcedlf5","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":""}} +{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1manfred47kzduec920z88wfr64ylksmdcedlf5","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 diff --git a/gno.land/pkg/gnoweb/gnoweb_test.go b/gno.land/pkg/gnoweb/gnoweb_test.go index 8c8bcca48f5..99eb86ea07e 100644 --- a/gno.land/pkg/gnoweb/gnoweb_test.go +++ b/gno.land/pkg/gnoweb/gnoweb_test.go @@ -34,7 +34,7 @@ func TestRoutes(t *testing.T) { {"/r/gnoland/blog$help&func=Render&path=foo/bar", ok, `input type="text" value="foo/bar"`}, {"/r/gnoland/blog$help&func=NonExisting", ok, "NonExisting not found"}, {"/r/demo/users:administrator", ok, "address"}, - {"/r/demo/users", ok, "manfred"}, + {"/r/demo/users", ok, "moul"}, {"/r/demo/users/users.gno", ok, "// State"}, {"/r/demo/deep/very/deep", ok, "it works!"}, {"/r/demo/deep/very/deep?arg1=val1&arg2=val2", ok, "hi ?arg1=val1&arg2=val2"}, diff --git a/gno.land/pkg/integration/testdata/adduserfrom.txtar b/gno.land/pkg/integration/testdata/adduserfrom.txtar index a23849aa604..47ec70b00e6 100644 --- a/gno.land/pkg/integration/testdata/adduserfrom.txtar +++ b/gno.land/pkg/integration/testdata/adduserfrom.txtar @@ -27,8 +27,8 @@ stdout ' "BaseAccount": {' stdout ' "address": "g1mtmrdmqfu0aryqfl4aw65n35haw2wdjkh5p4cp",' stdout ' "coins": "10000000ugnot",' stdout ' "public_key": null,' -stdout ' "account_number": "58",' +stdout ' "account_number": "59",' stdout ' "sequence": "0"' stdout ' }' stdout '}' -! stderr '.+' # empty \ No newline at end of file +! stderr '.+' # empty From 30aac2a81882452146807c559ff37aa6b9e2ca5a Mon Sep 17 00:00:00 2001 From: hthieu1110 Date: Mon, 25 Nov 2024 01:45:13 -0800 Subject: [PATCH 3/4] feat(gnovm): returns error like in Golang when assignment with a function which does not return any value (#3049) This PR aims at resolving this issue: https://github.com/gnolang/gno/issues/1082 This depends on https://github.com/gnolang/gno/pull/3017 because it refactored the code to sync the logic/code between AssignStmt vs ValueDecl. Related https://github.com/gnolang/gno/pull/2695
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--------- Co-authored-by: hieu.ha Co-authored-by: Mikael VALLENET --- gnovm/pkg/gnolang/preprocess.go | 20 +++++++------------- gnovm/pkg/gnolang/type_check.go | 8 ++++++++ gnovm/tests/files/assign37.gno | 10 ++++++++++ gnovm/tests/files/assign37b.gno | 12 ++++++++++++ gnovm/tests/files/var34.gno | 10 ++++++++++ gnovm/tests/files/var34b.gno | 11 +++++++++++ gnovm/tests/files/var34c.gno | 10 ++++++++++ 7 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 gnovm/tests/files/assign37.gno create mode 100644 gnovm/tests/files/assign37b.gno create mode 100644 gnovm/tests/files/var34.gno create mode 100644 gnovm/tests/files/var34b.gno create mode 100644 gnovm/tests/files/var34c.gno diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 85a846535ce..b9eb756512e 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2373,7 +2373,7 @@ func defineOrDecl( sts := make([]Type, numNames) // static types tvs := make([]TypedValue, numNames) - if numNames > 1 && len(valueExprs) == 1 { + if numVals == 1 && numNames > 1 { parseMultipleAssignFromOneExpr(sts, tvs, store, bn, nameExprs, typeExpr, valueExprs[0]) } else { parseAssignFromExprList(sts, tvs, store, bn, isConst, nameExprs, typeExpr, valueExprs) @@ -2410,7 +2410,7 @@ func parseAssignFromExprList( for _, v := range valueExprs { if cx, ok := v.(*CallExpr); ok { tt, ok := evalStaticTypeOfRaw(store, bn, cx).(*tupleType) - if ok && len(tt.Elts) != 1 { + if ok && len(tt.Elts) > 1 { panic(fmt.Sprintf("multiple-value %s (value of type %s) in single-value context", cx.Func.String(), tt.Elts)) } } @@ -3132,18 +3132,12 @@ func gnoTypeOf(store Store, t Type) Type { // but rather computes the type OF x. func evalStaticTypeOf(store Store, last BlockNode, x Expr) Type { t := evalStaticTypeOfRaw(store, last, x) - if tt, ok := t.(*tupleType); ok { - if len(tt.Elts) != 1 { - panic(fmt.Sprintf( - "evalStaticTypeOf() only supports *CallExpr with 1 result, got %s", - tt.String(), - )) - } else { - return tt.Elts[0] - } - } else { - return t + + if tt, ok := t.(*tupleType); ok && len(tt.Elts) == 1 { + return tt.Elts[0] } + + return t } // like evalStaticTypeOf() but returns the raw *tupleType for *CallExpr. diff --git a/gnovm/pkg/gnolang/type_check.go b/gnovm/pkg/gnolang/type_check.go index c62d67375ee..e786bed683f 100644 --- a/gnovm/pkg/gnolang/type_check.go +++ b/gnovm/pkg/gnolang/type_check.go @@ -1029,6 +1029,14 @@ func assertValidAssignRhs(store Store, last BlockNode, n Node) { tt = evalStaticType(store, last, exp) panic(fmt.Sprintf("%s (type) is not an expression", tt.String())) } + + // Ensures that function used in ValueDecl or AssignStmt must return at least 1 value. + if cx, ok := exp.(*CallExpr); ok { + tType, ok := tt.(*tupleType) + if ok && len(tType.Elts) == 0 { + panic(fmt.Sprintf("%s (no value) used as value", cx.Func.String())) + } + } } } diff --git a/gnovm/tests/files/assign37.gno b/gnovm/tests/files/assign37.gno new file mode 100644 index 00000000000..d96aab42070 --- /dev/null +++ b/gnovm/tests/files/assign37.gno @@ -0,0 +1,10 @@ +package main + +func f() { } + +func main() { + a := f() +} + +// Error: +// main/files/assign37.gno:6:2: f (no value) used as value diff --git a/gnovm/tests/files/assign37b.gno b/gnovm/tests/files/assign37b.gno new file mode 100644 index 00000000000..42e3dbe6e1d --- /dev/null +++ b/gnovm/tests/files/assign37b.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func f() { } + +func main() { + a, b := f(), f() +} + +// Error: +// main/files/assign37b.gno:8:2: f (no value) used as value diff --git a/gnovm/tests/files/var34.gno b/gnovm/tests/files/var34.gno new file mode 100644 index 00000000000..4f1dff6183f --- /dev/null +++ b/gnovm/tests/files/var34.gno @@ -0,0 +1,10 @@ +package main + +func f() {} + +func main() { + var t = f() +} + +// Error: +// main/files/var34.gno:6:6: f (no value) used as value diff --git a/gnovm/tests/files/var34b.gno b/gnovm/tests/files/var34b.gno new file mode 100644 index 00000000000..21e8a89bb14 --- /dev/null +++ b/gnovm/tests/files/var34b.gno @@ -0,0 +1,11 @@ +package main + +func f() {} + +func main() { + var a int + a = f() +} + +// Error: +// main/files/var34b.gno:7:2: f (no value) used as value diff --git a/gnovm/tests/files/var34c.gno b/gnovm/tests/files/var34c.gno new file mode 100644 index 00000000000..18ab996eefd --- /dev/null +++ b/gnovm/tests/files/var34c.gno @@ -0,0 +1,10 @@ +package main + +func f() {} + +func main() { + var a, b int = f(), 1 +} + +// Error: +// main/files/var34c.gno:6:6: f (no value) used as value From f27b182702d278d79d8b1f95d06913a20f4f5f62 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Mon, 25 Nov 2024 11:25:50 +0100 Subject: [PATCH 4/4] fix: bit shifting const expr overflow (#3192) This provides validation for cases where bit shifting const expressions overflow. Closes #3128 --------- Co-authored-by: ltzmaxwell --- gnovm/pkg/gnolang/machine.go | 44 ++--- gnovm/pkg/gnolang/op_assign.go | 4 +- gnovm/pkg/gnolang/op_binary.go | 177 ++++++++++++++++++- gnovm/pkg/gnolang/preprocess.go | 3 + gnovm/pkg/gnolang/values_conversions_test.go | 132 ++++++++++++++ 5 files changed, 332 insertions(+), 28 deletions(-) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index aac8b4f5802..e341ef8e9f1 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -67,13 +67,13 @@ type Machine struct { Debugger Debugger // Configuration - CheckTypes bool // not yet used - ReadOnly bool - MaxCycles int64 - Output io.Writer - Store Store - Context interface{} - GasMeter store.GasMeter + PreprocessorMode bool // this is used as a flag when const values are evaluated during preprocessing + ReadOnly bool + MaxCycles int64 + Output io.Writer + Store Store + Context interface{} + GasMeter store.GasMeter // PanicScope is incremented each time a panic occurs and is reset to // zero when it is recovered. PanicScope uint @@ -103,18 +103,18 @@ func NewMachine(pkgPath string, store Store) *Machine { // MachineOptions is used to pass options to [NewMachineWithOptions]. type MachineOptions struct { // Active package of the given machine; must be set before execution. - PkgPath string - CheckTypes bool // not yet used - ReadOnly bool - Debug bool - Input io.Reader // used for default debugger input only - Output io.Writer // default os.Stdout - Store Store // default NewStore(Alloc, nil, nil) - Context interface{} - Alloc *Allocator // or see MaxAllocBytes. - MaxAllocBytes int64 // or 0 for no limit. - MaxCycles int64 // or 0 for no limit. - GasMeter store.GasMeter + PkgPath string + PreprocessorMode bool + ReadOnly bool + Debug bool + Input io.Reader // used for default debugger input only + Output io.Writer // default os.Stdout + Store Store // default NewStore(Alloc, nil, nil) + Context interface{} + Alloc *Allocator // or see MaxAllocBytes. + MaxAllocBytes int64 // or 0 for no limit. + MaxCycles int64 // or 0 for no limit. + GasMeter store.GasMeter } // the machine constructor gets spammed @@ -136,7 +136,7 @@ var machinePool = sync.Pool{ // Machines initialized through this constructor must be finalized with // [Machine.Release]. func NewMachineWithOptions(opts MachineOptions) *Machine { - checkTypes := opts.CheckTypes + preprocessorMode := opts.PreprocessorMode readOnly := opts.ReadOnly maxCycles := opts.MaxCycles vmGasMeter := opts.GasMeter @@ -169,7 +169,7 @@ func NewMachineWithOptions(opts MachineOptions) *Machine { mm := machinePool.Get().(*Machine) mm.Package = pv mm.Alloc = alloc - mm.CheckTypes = checkTypes + mm.PreprocessorMode = preprocessorMode mm.ReadOnly = readOnly mm.MaxCycles = maxCycles mm.Output = output @@ -2249,7 +2249,7 @@ func (m *Machine) String() string { var builder strings.Builder builder.Grow(totalLength) - builder.WriteString(fmt.Sprintf("Machine:\n CheckTypes: %v\n Op: %v\n Values: (len: %d)\n", m.CheckTypes, m.Ops[:m.NumOps], m.NumValues)) + builder.WriteString(fmt.Sprintf("Machine:\n PreprocessorMode: %v\n Op: %v\n Values: (len: %d)\n", m.PreprocessorMode, m.Ops[:m.NumOps], m.NumValues)) for i := m.NumValues - 1; i >= 0; i-- { builder.WriteString(fmt.Sprintf(" #%d %v\n", i, m.Values[i])) diff --git a/gnovm/pkg/gnolang/op_assign.go b/gnovm/pkg/gnolang/op_assign.go index 114c8c589c4..5e841fb18fd 100644 --- a/gnovm/pkg/gnolang/op_assign.go +++ b/gnovm/pkg/gnolang/op_assign.go @@ -274,7 +274,7 @@ func (m *Machine) doOpShlAssign() { } } // lv <<= rv - shlAssign(lv.TV, rv) + shlAssign(m, lv.TV, rv) if lv.Base != nil { m.Realm.DidUpdate(lv.Base.(Object), nil, nil) } @@ -294,7 +294,7 @@ func (m *Machine) doOpShrAssign() { } } // lv >>= rv - shrAssign(lv.TV, rv) + shrAssign(m, lv.TV, rv) if lv.Base != nil { m.Realm.DidUpdate(lv.Base.(Object), nil, nil) } diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index a541a7da8b5..6d26fa7ce54 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -2,6 +2,7 @@ package gnolang import ( "fmt" + "math" "math/big" "github.com/cockroachdb/apd/v3" @@ -288,7 +289,7 @@ func (m *Machine) doOpShl() { } // lv << rv - shlAssign(lv, rv) + shlAssign(m, lv, rv) } func (m *Machine) doOpShr() { @@ -304,7 +305,7 @@ func (m *Machine) doOpShr() { } // lv >> rv - shrAssign(lv, rv) + shrAssign(m, lv, rv) } func (m *Machine) doOpBand() { @@ -1196,32 +1197,116 @@ func xorAssign(lv, rv *TypedValue) { } // for doOpShl and doOpShlAssign. -func shlAssign(lv, rv *TypedValue) { +func shlAssign(m *Machine, lv, rv *TypedValue) { rv.AssertNonNegative("runtime error: negative shift amount") + + checkOverflow := func(v func() bool) { + if m.PreprocessorMode && !v() { + panic(`constant overflows`) + } + } + // set the result in lv. // NOTE: baseOf(rv.T) is always UintType. switch baseOf(lv.T) { case IntType: + checkOverflow(func() bool { + l := big.NewInt(int64(lv.GetInt())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt)) != 1 + }) + lv.SetInt(lv.GetInt() << rv.GetUint()) case Int8Type: + checkOverflow(func() bool { + l := big.NewInt(int64(lv.GetInt8())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt8)) != 1 + }) + lv.SetInt8(lv.GetInt8() << rv.GetUint()) case Int16Type: + checkOverflow(func() bool { + l := big.NewInt(int64(lv.GetInt16())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt16)) != 1 + }) + lv.SetInt16(lv.GetInt16() << rv.GetUint()) case Int32Type, UntypedRuneType: + checkOverflow(func() bool { + l := big.NewInt(int64(lv.GetInt32())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt32)) != 1 + }) + lv.SetInt32(lv.GetInt32() << rv.GetUint()) case Int64Type: + checkOverflow(func() bool { + l := big.NewInt(lv.GetInt64()) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt64)) != 1 + }) + lv.SetInt64(lv.GetInt64() << rv.GetUint()) case UintType: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetUint())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(0).SetUint64(math.MaxUint)) != 1 + }) + lv.SetUint(lv.GetUint() << rv.GetUint()) case Uint8Type: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetUint8())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxUint8)) != 1 + }) + lv.SetUint8(lv.GetUint8() << rv.GetUint()) case DataByteType: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetDataByte())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxUint8)) != 1 + }) + lv.SetDataByte(lv.GetDataByte() << rv.GetUint()) case Uint16Type: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetUint16())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxUint16)) != 1 + }) + lv.SetUint16(lv.GetUint16() << rv.GetUint()) case Uint32Type: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetUint32())) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxUint32)) != 1 + }) + lv.SetUint32(lv.GetUint32() << rv.GetUint()) case Uint64Type: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(lv.GetUint64()) + r := big.NewInt(0).Lsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(0).SetUint64(math.MaxUint64)) != 1 + }) + lv.SetUint64(lv.GetUint64() << rv.GetUint()) case BigintType, UntypedBigintType: lb := lv.GetBigInt() @@ -1236,32 +1321,116 @@ func shlAssign(lv, rv *TypedValue) { } // for doOpShr and doOpShrAssign. -func shrAssign(lv, rv *TypedValue) { +func shrAssign(m *Machine, lv, rv *TypedValue) { rv.AssertNonNegative("runtime error: negative shift amount") + + checkOverflow := func(v func() bool) { + if m.PreprocessorMode && !v() { + panic(`constant overflows`) + } + } + // set the result in lv. // NOTE: baseOf(rv.T) is always UintType. switch baseOf(lv.T) { case IntType: + checkOverflow(func() bool { + l := big.NewInt(int64(lv.GetInt())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt)) != 1 + }) + lv.SetInt(lv.GetInt() >> rv.GetUint()) case Int8Type: + checkOverflow(func() bool { + l := big.NewInt(int64(lv.GetInt8())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt8)) != 1 + }) + lv.SetInt8(lv.GetInt8() >> rv.GetUint()) case Int16Type: + checkOverflow(func() bool { + l := big.NewInt(int64(lv.GetInt16())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt16)) != 1 + }) + lv.SetInt16(lv.GetInt16() >> rv.GetUint()) case Int32Type, UntypedRuneType: + checkOverflow(func() bool { + l := big.NewInt(int64(lv.GetInt32())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt32)) != 1 + }) + lv.SetInt32(lv.GetInt32() >> rv.GetUint()) case Int64Type: + checkOverflow(func() bool { + l := big.NewInt(lv.GetInt64()) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxInt64)) != 1 + }) + lv.SetInt64(lv.GetInt64() >> rv.GetUint()) case UintType: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetUint())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(0).SetUint64(math.MaxUint)) != 1 + }) + lv.SetUint(lv.GetUint() >> rv.GetUint()) case Uint8Type: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetUint8())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxUint8)) != 1 + }) + lv.SetUint8(lv.GetUint8() >> rv.GetUint()) case DataByteType: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetDataByte())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxUint8)) != 1 + }) + lv.SetDataByte(lv.GetDataByte() >> rv.GetUint()) case Uint16Type: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetUint16())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxUint16)) != 1 + }) + lv.SetUint16(lv.GetUint16() >> rv.GetUint()) case Uint32Type: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(uint64(lv.GetUint32())) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(math.MaxUint32)) != 1 + }) + lv.SetUint32(lv.GetUint32() >> rv.GetUint()) case Uint64Type: + checkOverflow(func() bool { + l := big.NewInt(0).SetUint64(lv.GetUint64()) + r := big.NewInt(0).Rsh(l, rv.GetUint()) + + return r.Cmp(big.NewInt(0).SetUint64(math.MaxUint64)) != 1 + }) + lv.SetUint64(lv.GetUint64() >> rv.GetUint()) case BigintType, UntypedBigintType: lb := lv.GetBigInt() diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index b9eb756512e..7198d4f6a98 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -3258,7 +3258,10 @@ func evalConst(store Store, last BlockNode, x Expr) *ConstExpr { // TODO: some check or verification for ensuring x // is constant? From the machine? m := NewMachine(".dontcare", store) + m.PreprocessorMode = true + cv := m.EvalStatic(last, x) + m.PreprocessorMode = false m.Release() cx := &ConstExpr{ Source: x, diff --git a/gnovm/pkg/gnolang/values_conversions_test.go b/gnovm/pkg/gnolang/values_conversions_test.go index 5436347733f..7ffa3e98c71 100644 --- a/gnovm/pkg/gnolang/values_conversions_test.go +++ b/gnovm/pkg/gnolang/values_conversions_test.go @@ -2,6 +2,7 @@ package gnolang import ( "math" + "strings" "testing" "github.com/cockroachdb/apd/v3" @@ -25,3 +26,134 @@ func TestConvertUntypedBigdecToFloat(t *testing.T) { require.Equal(t, float64(0), dst.GetFloat64()) } + +func TestBitShiftingOverflow(t *testing.T) { + t.Parallel() + + testFunc := func(source, msg string) { + defer func() { + if len(msg) == 0 { + return + } + + r := recover() + + if r == nil { + t.Fail() + } + + err := r.(*PreprocessError) + c := strings.Contains(err.Error(), msg) + if !c { + t.Fatalf(`expected "%s", got "%s"`, msg, r) + } + }() + + m := NewMachine("test", nil) + + n := MustParseFile("main.go", source) + m.RunFiles(n) + m.RunMain() + } + + type cases struct { + source string + msg string + } + + tests := []cases{ + { + `package test + +func main() { + const a = int32(1) << 33 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + +func main() { + const a1 = int8(1) << 8 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + +func main() { + const a2 = int16(1) << 16 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + +func main() { + const a3 = int32(1) << 33 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + +func main() { + const a4 = int64(1) << 65 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + +func main() { + const b1 = uint8(1) << 8 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + +func main() { + const b2 = uint16(1) << 16 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + +func main() { + const b3 = uint32(1) << 33 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + +func main() { + const b4 = uint64(1) << 65 +}`, + `test/main.go:3:1: constant overflows`, + }, + { + `package test + + func main() { + const c1 = 1 << 128 + }`, + ``, + }, + { + `package test + + func main() { + const c1 = 1 << 128 + println(c1) + }`, + `test/main.go:5:4: bigint overflows target kind`, + }, + } + + for _, tc := range tests { + testFunc(tc.source, tc.msg) + } +}