From 59f85434cf551ecbca4d0c17a6141a7a2a16187f Mon Sep 17 00:00:00 2001 From: irreverentsimplicity Date: Thu, 19 Sep 2024 00:47:47 -0400 Subject: [PATCH] minimal teams package --- .gitattributes | 4 +- .github/goreleaser.yaml | 189 +- .github/workflows/lint_template.yml | 15 +- .github/workflows/nightlies.yml | 9 +- .github/workflows/portal-loop.yml | 60 +- .github/workflows/releaser-master.yml | 9 +- .github/workflows/releaser.yml | 6 +- Dockerfile | 58 - Dockerfile.release | 7 - contribs/gnodev/Makefile | 8 +- contribs/gnodev/README.md | 73 +- .../cmd/gnobro/assets/banner_land_1.txt | 19 - .../gnodev/cmd/gnobro/assets/gn_hc1.utf8ans | 25 - .../gnodev/cmd/gnobro/assets/gn_hc2.utf8ans | 25 - .../gnodev/cmd/gnobro/assets/gn_hc3.utf8ans | 25 - .../gnodev/cmd/gnobro/assets/gn_hc4.utf8ans | 25 - contribs/gnodev/cmd/gnobro/banner.go | 37 - contribs/gnodev/cmd/gnobro/main.go | 462 -- contribs/gnodev/cmd/gnodev/accounts.go | 3 +- contribs/gnodev/go.mod | 86 +- contribs/gnodev/go.sum | 184 +- contribs/gnodev/pkg/browser/client_dev.go | 113 - contribs/gnodev/pkg/browser/client_node.go | 124 - contribs/gnodev/pkg/browser/list_model.go | 154 - contribs/gnodev/pkg/browser/model.go | 580 --- contribs/gnodev/pkg/browser/model_banner.go | 99 - contribs/gnodev/pkg/browser/model_nav.go | 73 - contribs/gnodev/pkg/browser/model_style.go | 239 - contribs/gnodev/pkg/browser/model_tasks.go | 85 - contribs/gnodev/pkg/browser/model_view.go | 174 - contribs/gnodev/pkg/browser/utils.go | 33 - contribs/gnodev/pkg/dev/node.go | 11 +- contribs/gnodev/pkg/dev/node_state_test.go | 18 +- contribs/gnodev/pkg/dev/node_test.go | 28 +- contribs/gnodev/pkg/dev/packages_test.go | 74 +- contribs/gnodev/pkg/emitter/server.go | 4 +- contribs/gnodev/pkg/emitter/server_test.go | 2 +- contribs/gnofaucet/go.mod | 47 +- contribs/gnofaucet/go.sum | 94 +- contribs/gnokeykc/go.mod | 36 +- contribs/gnokeykc/go.sum | 87 +- docs/concepts/portal-loop.md | 17 - .../local-setup/creating-a-keypair.md | 77 - .../local-setup/installation.md | 6 +- .../local-setup/interacting-with-gnoland.md | 26 +- .../local-setup}/working-with-key-pairs.md | 59 +- .../validators/setting-up-a-new-chain.md | 2 +- docs/gno-tooling/cli/faucet/faucet.md | 2 +- docs/gno-tooling/cli/gnodev.md | 2 +- docs/gno-tooling/cli/gnokey.md | 323 ++ .../cli/gnokey/full-security-tx.md | 134 - docs/gno-tooling/cli/gnokey/gnokey.md | 16 - .../cli/gnokey/querying-a-network.md | 233 - .../cli/gnokey/state-changing-calls.md | 466 -- docs/how-to-guides/connecting-from-go.md | 22 +- docs/how-to-guides/deploy.md | 2 +- docs/reference/gnoclient/gnoclient.md | 4 +- docs/reference/network-config.md | 2 +- docs/reference/stdlibs/std/chain.md | 2 +- .../gno.land/p/demo/avlhelpers/avlhelpers.gno | 41 - examples/gno.land/p/demo/avlhelpers/gno.mod | 3 - .../p/demo/avlhelpers/z_0_filetest.gno | 91 - examples/gno.land/p/demo/entropy/entropy.gno | 89 - .../gno.land/p/demo/entropy/entropy_test.gno | 46 - examples/gno.land/p/demo/entropy/gno.mod | 1 - .../gno.land/p/demo/entropy/z_filetest.gno | 56 - .../demo/flippandoserver/flippandoserver.gno | 161 + .../flippandoserver/flippandoserver_test.gno | 122 + .../p/demo/flippandoserver/fliprand.gno | 590 +++ .../gno.land/p/demo/flippandoserver/gno.mod | 1 + .../gno.land/p/demo/flippandoserver/rng.gno | 250 + examples/gno.land/p/demo/fqname/fqname.gno | 72 - .../gno.land/p/demo/fqname/fqname_test.gno | 74 - examples/gno.land/p/demo/fqname/gno.mod | 3 - examples/gno.land/p/demo/grc/grc20/token.gno | 45 +- .../gno.land/p/demo/grc/grc721/errors.gno | 1 + .../gno.land/p/demo/int256/arithmetic.gno | 68 +- .../p/demo/int256/arithmetic_test.gno | 78 +- .../gno.land/p/demo/int256/conversion.gno | 1 - .../p/demo/int256/conversion_test.gno | 63 - examples/gno.land/p/demo/merkle/merkle.gno | 11 - examples/gno.land/p/demo/ownable/errors.gno | 4 +- .../exts/authorizable/authorizable.gno | 90 - .../exts/authorizable/authorizable_test.gno | 116 - .../demo/ownable/exts/authorizable/errors.gno | 9 - .../p/demo/ownable/exts/authorizable/gno.mod | 9 - examples/gno.land/p/demo/ownable/ownable.gno | 12 +- .../gno.land/p/demo/ownable/ownable_test.gno | 56 +- examples/gno.land/p/demo/subscription/doc.gno | 66 - examples/gno.land/p/demo/subscription/gno.mod | 1 - .../p/demo/subscription/lifetime/errors.gno | 10 - .../p/demo/subscription/lifetime/gno.mod | 8 - .../p/demo/subscription/lifetime/lifetime.gno | 81 - .../subscription/lifetime/lifetime_test.gno | 105 - .../p/demo/subscription/recurring/errors.gno | 11 - .../p/demo/subscription/recurring/gno.mod | 8 - .../demo/subscription/recurring/recurring.gno | 104 - .../subscription/recurring/recurring_test.gno | 134 - .../p/demo/subscription/subscription.gno | 12 - examples/gno.land/p/demo/teams/errors.gno | 10 + examples/gno.land/p/demo/teams/gno.mod | 1 + examples/gno.land/p/demo/teams/teams.gno | 167 + examples/gno.land/p/demo/teams/types.gno | 14 + examples/gno.land/p/demo/uassert/uassert.gno | 97 +- .../gno.land/p/demo/uassert/uassert_test.gno | 2 - examples/gno.land/r/demo/art/gnoface/gno.mod | 1 - .../gno.land/r/demo/art/gnoface/gnoface.gno | 4 +- .../r/demo/art/millipede/millipede.gno | 2 +- .../r/demo/art/millipede/millipede_test.gno | 4 +- .../gno.land/r/demo/disperse/disperse.gno | 99 - examples/gno.land/r/demo/disperse/doc.gno | 19 - examples/gno.land/r/demo/disperse/errors.gno | 12 - examples/gno.land/r/demo/disperse/gno.mod | 3 - examples/gno.land/r/demo/disperse/util.gno | 67 - .../gno.land/r/demo/disperse/z_0_filetest.gno | 32 - .../gno.land/r/demo/disperse/z_1_filetest.gno | 32 - .../gno.land/r/demo/disperse/z_2_filetest.gno | 25 - .../gno.land/r/demo/disperse/z_3_filetest.gno | 45 - .../gno.land/r/demo/disperse/z_4_filetest.gno | 48 - .../gno.land/r/demo/flippando/airdrop.gno | 183 + .../gno.land/r/demo/flippando/basicNFT.gno | 374 ++ .../r/demo/flippando/compositeNFT.gno | 263 ++ examples/gno.land/r/demo/flippando/errors.gno | 14 + .../demo/flippando/flip_marketplace_test.gno | 142 + .../gno.land/r/demo/flippando/flippando.gno | 212 + .../r/demo/flippando/flippando_test.gno | 66 + .../r/demo/flippando/flippandosvg.gno | 327 ++ .../r/demo/flippando/flippandosvg_test.gno | 77 + examples/gno.land/r/demo/flippando/gno.mod | 5 + .../gno.land/r/demo/flippando/marketplace.gno | 384 ++ .../gno.land/r/demo/flippando/marshals.gno | 438 ++ examples/gno.land/r/demo/flippando/token.gno | 282 ++ examples/gno.land/r/demo/flippando/utils.gno | 69 + .../gno.land/r/demo/games/shifumi/gno.mod | 7 - .../gno.land/r/demo/games/shifumi/shifumi.gno | 120 - examples/gno.land/r/demo/profile/profile.gno | 67 +- .../gno.land/r/demo/profile/profile_test.gno | 94 +- examples/gno.land/r/demo/users/gno.mod | 1 - examples/gno.land/r/demo/users/users.gno | 7 - .../gno.land/r/demo/users/z_12_filetest.gno | 49 - .../r/gnoland/events/administration.gno | 26 - examples/gno.land/r/gnoland/events/errors.gno | 18 - examples/gno.land/r/gnoland/events/events.gno | 353 +- .../r/gnoland/events/events_filetest.gno | 226 + .../gno.land/r/gnoland/events/events_test.gno | 200 - examples/gno.land/r/gnoland/events/gno.mod | 8 +- .../gno.land/r/gnoland/events/rendering.gno | 145 - examples/gno.land/r/gnoland/home/gno.mod | 1 - examples/gno.land/r/gnoland/home/home.gno | 15 +- .../gno.land/r/gnoland/home/home_filetest.gno | 8 +- .../r/gnoland/home/overide_filetest.gno | 2 +- .../r/gnoland/pages/page_contribute.gno | 106 - .../r/gnoland/pages/page_ecosystem.gno | 18 +- .../gno.land/r/gnoland/pages/page_gor.gno | 221 + .../gno.land/r/gnoland/pages/pages_test.gno | 2 +- examples/gno.land/r/leon/config/config.gno | 65 - examples/gno.land/r/leon/config/gno.mod | 1 - examples/gno.land/r/leon/home/gno.mod | 8 - examples/gno.land/r/leon/home/home.gno | 121 - .../gno.land/r/morgan/guestbook/admin.gno | 25 - examples/gno.land/r/morgan/guestbook/gno.mod | 7 - .../gno.land/r/morgan/guestbook/guestbook.gno | 126 - .../r/morgan/guestbook/guestbook_test.gno | 131 - examples/gno.land/r/morgan/home/gno.mod | 1 - examples/gno.land/r/morgan/home/home.gno | 10 - gno.land/cmd/gnoland/config_get.go | 13 - gno.land/cmd/gnoland/config_help.go | 127 - gno.land/cmd/gnoland/config_set.go | 12 - gno.land/cmd/gnoland/genesis_balances_add.go | 13 +- .../cmd/gnoland/genesis_balances_add_test.go | 39 +- .../gnoland/genesis_balances_export_test.go | 3 +- .../gnoland/genesis_balances_remove_test.go | 3 +- .../cmd/gnoland/genesis_txs_add_packages.go | 3 +- .../cmd/gnoland/genesis_txs_add_sheet_test.go | 5 +- gno.land/cmd/gnoland/secrets_get.go | 12 - gno.land/cmd/gnoland/testdata/addpkg.txtar | 20 +- .../cmd/gnoland/testdata/alloc_array.txtar | 16 - .../gnoland/testdata/alloc_byte_slice.txtar | 16 - .../cmd/gnoland/testdata/alloc_slice.txtar | 16 - .../testdata/issue_2283_cacheTypes.txtar | 1 + gno.land/cmd/gnoland/testdata/panic.txtar | 27 - .../testdata/restart_missing_type.txtar | 202 - .../cmd/gnoland/testdata/restart_nonval.txtar | 5 - gno.land/pkg/gnoclient/client_test.go | 480 +- gno.land/pkg/gnoclient/client_txs.go | 226 +- gno.land/pkg/gnoclient/integration_test.go | 214 +- gno.land/pkg/gnoclient/signer.go | 3 +- gno.land/pkg/gnoclient/util.go | 41 + gno.land/pkg/gnoland/app.go | 268 +- gno.land/pkg/gnoland/app_test.go | 204 +- gno.land/pkg/gnoland/balance_test.go | 25 +- gno.land/pkg/gnoland/mock_test.go | 44 +- gno.land/pkg/gnoland/node_inmemory.go | 46 +- gno.land/pkg/gnoland/ugnot/denom.go | 11 - gno.land/pkg/gnoweb/alias.go | 27 - gno.land/pkg/gnoweb/gnoweb.go | 40 +- gno.land/pkg/gnoweb/gnoweb_test.go | 5 +- gno.land/pkg/gnoweb/static/js/renderer.js | 57 +- gno.land/pkg/gnoweb/views/funcs.html | 20 +- gno.land/pkg/gnoweb/views/package_file.html | 10 +- gno.land/pkg/gnoweb/views/realm_render.html | 3 - gno.land/pkg/integration/doc.go | 5 +- .../pkg/integration/testdata/gnoland.txtar | 2 +- .../pkg/integration/testdata/restart.txtar | 24 - .../pkg/integration/testing_integration.go | 55 +- gno.land/pkg/integration/testing_node.go | 36 +- gno.land/pkg/keyscli/root.go | 2 +- gno.land/pkg/sdk/vm/common_test.go | 14 +- gno.land/pkg/sdk/vm/errors.go | 6 - gno.land/pkg/sdk/vm/gas_test.go | 13 +- gno.land/pkg/sdk/vm/keeper.go | 245 +- gno.land/pkg/sdk/vm/keeper_test.go | 138 +- gno.land/pkg/sdk/vm/package.go | 1 - .../pkg/sdk/vm/testdata/emptystdlib/README | 1 - gno.land/pkg/sdk/vm/vm.proto | 3 - gnovm/cmd/gno/run.go | 10 +- gnovm/pkg/gnolang/alloc.go | 11 +- gnovm/pkg/gnolang/debugger_test.go | 22 +- gnovm/pkg/gnolang/eval_test.go | 109 +- gnovm/pkg/gnolang/frame.go | 123 - gnovm/pkg/gnolang/gno_test.go | 5 +- gnovm/pkg/gnolang/internal/txlog/txlog.go | 141 - .../pkg/gnolang/internal/txlog/txlog_test.go | 553 --- gnovm/pkg/gnolang/machine.go | 118 +- gnovm/pkg/gnolang/misc.go | 4 - gnovm/pkg/gnolang/nodes.go | 3 +- gnovm/pkg/gnolang/nodes_test.go | 44 - gnovm/pkg/gnolang/op_binary.go | 4 +- gnovm/pkg/gnolang/op_call.go | 4 +- gnovm/pkg/gnolang/op_expressions.go | 7 +- gnovm/pkg/gnolang/preprocess.go | 230 +- gnovm/pkg/gnolang/store.go | 244 +- gnovm/pkg/gnolang/store_test.go | 99 - gnovm/pkg/gnolang/uverse.go | 128 +- gnovm/pkg/gnolang/uverse_test.go | 4 +- gnovm/pkg/gnolang/values.go | 61 +- gnovm/pkg/gnolang/values_string.go | 3 - gnovm/pkg/gnolang/values_test.go | 70 - gnovm/stdlibs/math/all_test.gno | 4027 ----------------- gnovm/tests/file.go | 59 +- gnovm/tests/files/a31.gno | 4 +- .../unnamedtype5_filetest.gno | 4 +- .../unnamedtype5a_filetest.gno | 3 +- gnovm/tests/files/cap1.gno | 10 - gnovm/tests/files/cap10.gno | 8 - gnovm/tests/files/cap2.gno | 9 - gnovm/tests/files/cap3.gno | 9 - gnovm/tests/files/cap4.gno | 9 - gnovm/tests/files/cap5.gno | 12 - gnovm/tests/files/cap6.gno | 31 - gnovm/tests/files/cap7.gno | 9 - gnovm/tests/files/cap8.gno | 9 - gnovm/tests/files/cap9.gno | 9 - gnovm/tests/files/circular_constant.gno | 10 - gnovm/tests/files/convert4.gno | 3 +- gnovm/tests/files/convert5.gno | 3 +- gnovm/tests/files/defer6.gno | 16 +- gnovm/tests/files/len1.gno | 10 - gnovm/tests/files/len2.gno | 9 - gnovm/tests/files/len3.gno | 10 - gnovm/tests/files/len4.gno | 12 - gnovm/tests/files/len5.gno | 9 - gnovm/tests/files/len6.gno | 14 - gnovm/tests/files/len7.gno | 8 - gnovm/tests/files/len8.gno | 10 - gnovm/tests/files/map15.gno | 4 +- gnovm/tests/files/method27.gno | 4 +- gnovm/tests/files/panic0.gno | 5 - gnovm/tests/files/panic0a.gno | 45 - gnovm/tests/files/panic0b.gno | 13 - gnovm/tests/files/panic0c.gno | 87 - gnovm/tests/files/panic1.gno | 5 - gnovm/tests/files/panic2a.gno | 275 -- gnovm/tests/files/panic2b.gno | 44 - gnovm/tests/files/recover10.gno | 5 - gnovm/tests/files/recover1b.gno | 5 - gnovm/tests/files/recover8.gno | 7 - gnovm/tests/files/recursive1.gno | 13 - gnovm/tests/files/recursive1a.gno | 15 - gnovm/tests/files/recursive1b.gno | 16 - gnovm/tests/files/recursive1c.gno | 17 - gnovm/tests/files/recursive1d.gno | 17 - gnovm/tests/files/recursive1e.gno | 13 - gnovm/tests/files/recursive1f.gno | 13 - gnovm/tests/files/recursive2.gno | 21 - gnovm/tests/files/recursive2a.gno | 21 - gnovm/tests/files/recursive2b.gno | 21 - gnovm/tests/files/recursive2c.gno | 21 - gnovm/tests/files/recursive2d.gno | 21 - gnovm/tests/files/recursive3.gno | 13 - gnovm/tests/files/recursive4.gno | 15 - gnovm/tests/files/recursive4a.gno | 9 - gnovm/tests/files/recursive5.gno | 13 - gnovm/tests/files/recursive6.gno | 23 - gnovm/tests/files/recursive6a.gno | 12 - gnovm/tests/files/recursive7.gno | 10 - gnovm/tests/files/recursive7a.gno | 8 - gnovm/tests/files/recursive8.gno | 8 - gnovm/tests/files/recursive9.gno | 8 - gnovm/tests/files/recursive9a.gno | 8 - gnovm/tests/files/recursive9b.gno | 8 - gnovm/tests/files/recursive9c.gno | 8 - gnovm/tests/files/recursive9d.gno | 10 - gnovm/tests/files/std5_stdlibs.gno | 9 - gnovm/tests/files/std8_stdlibs.gno | 13 - gnovm/tests/files/time17_native.gno | 20 - gnovm/tests/files/typeassert1.gno | 5 - gnovm/tests/files/typeassert2a.gno | 5 - gnovm/tests/files/typeassert9.gno | 5 - gnovm/tests/files/types/cmp_databyte.gno | 12 - .../tests/files/types/cmp_iface_0_stdlibs.gno | 27 - gnovm/tests/files/types/cmp_iface_1.gno | 29 - gnovm/tests/files/types/cmp_iface_2.gno | 32 - .../tests/files/types/cmp_iface_3_stdlibs.gno | 27 - gnovm/tests/files/types/cmp_iface_4.gno | 24 - .../tests/files/types/cmp_iface_5_stdlibs.gno | 27 - gnovm/tests/files/types/cmp_iface_6.gno | 31 - gnovm/tests/files/types/cmp_iface_7.gno | 24 - gnovm/tests/files/types/cmp_primitive_0.gno | 24 - gnovm/tests/files/types/cmp_primitive_1.gno | 22 - gnovm/tests/files/types/cmp_primitive_2.gno | 15 - gnovm/tests/files/types/cmp_primitive_3.gno | 23 - gnovm/tests/files/types/cmp_slice_0.gno | 20 - gnovm/tests/files/types/cmp_slice_1.gno | 10 - gnovm/tests/files/types/cmp_slice_2.gno | 14 - gnovm/tests/files/types/cmp_slice_3.gno | 16 - gnovm/tests/files/types/cmp_slice_4.gno | 10 - gnovm/tests/files/types/cmp_typeswitch.gno | 18 - gnovm/tests/files/types/cmp_typeswitch_a.gno | 18 - gnovm/tests/files/types/eql_0f2d.gno | 2 +- gnovm/tests/files/types/eql_0f2e.gno | 2 +- gnovm/tests/files/types/eql_0f49.gno | 21 - gnovm/tests/files/types/iface_eql.gno | 9 - gnovm/tests/files/types/runtime_a2.gno | 2 +- gnovm/tests/files/types/shift_a12.gno | 2 +- gnovm/tests/files/types/shift_a13.gno | 2 +- gnovm/tests/files/var19.gno | 1 - gnovm/tests/files/var20.gno | 2 +- gnovm/tests/files/var29.gno | 14 - gnovm/tests/files/var30.gno | 17 - gnovm/tests/files/vardecl.gno | 23 - gnovm/tests/files/zrealm_panic.gno | 20 - go.mod | 46 +- go.sum | 99 +- .../staging.gno.land/docker-compose.yml | 228 +- .../staging.gno.land/gnoland.entrypoint.sh | 23 - misc/docker-integration/integration_test.go | 6 +- tm2/pkg/bft/fail/fail.go | 24 +- tm2/pkg/crypto/bech32_test.go | 2 - tm2/pkg/crypto/crypto.go | 15 - tm2/pkg/sdk/abci.go | 9 - tm2/pkg/sdk/baseapp.go | 12 - tm2/pkg/sdk/baseapp_test.go | 50 +- tm2/pkg/sdk/context.go | 22 +- tm2/pkg/sdk/options.go | 14 - 355 files changed, 7134 insertions(+), 17210 deletions(-) delete mode 100644 Dockerfile delete mode 100644 contribs/gnodev/cmd/gnobro/assets/banner_land_1.txt delete mode 100644 contribs/gnodev/cmd/gnobro/assets/gn_hc1.utf8ans delete mode 100644 contribs/gnodev/cmd/gnobro/assets/gn_hc2.utf8ans delete mode 100644 contribs/gnodev/cmd/gnobro/assets/gn_hc3.utf8ans delete mode 100644 contribs/gnodev/cmd/gnobro/assets/gn_hc4.utf8ans delete mode 100644 contribs/gnodev/cmd/gnobro/banner.go delete mode 100644 contribs/gnodev/cmd/gnobro/main.go delete mode 100644 contribs/gnodev/pkg/browser/client_dev.go delete mode 100644 contribs/gnodev/pkg/browser/client_node.go delete mode 100644 contribs/gnodev/pkg/browser/list_model.go delete mode 100644 contribs/gnodev/pkg/browser/model.go delete mode 100644 contribs/gnodev/pkg/browser/model_banner.go delete mode 100644 contribs/gnodev/pkg/browser/model_nav.go delete mode 100644 contribs/gnodev/pkg/browser/model_style.go delete mode 100644 contribs/gnodev/pkg/browser/model_tasks.go delete mode 100644 contribs/gnodev/pkg/browser/model_view.go delete mode 100644 contribs/gnodev/pkg/browser/utils.go delete mode 100644 docs/getting-started/local-setup/creating-a-keypair.md rename docs/{gno-tooling/cli/gnokey => getting-started/local-setup}/working-with-key-pairs.md (75%) create mode 100644 docs/gno-tooling/cli/gnokey.md delete mode 100644 docs/gno-tooling/cli/gnokey/full-security-tx.md delete mode 100644 docs/gno-tooling/cli/gnokey/gnokey.md delete mode 100644 docs/gno-tooling/cli/gnokey/querying-a-network.md delete mode 100644 docs/gno-tooling/cli/gnokey/state-changing-calls.md delete mode 100644 examples/gno.land/p/demo/avlhelpers/avlhelpers.gno delete mode 100644 examples/gno.land/p/demo/avlhelpers/gno.mod delete mode 100644 examples/gno.land/p/demo/avlhelpers/z_0_filetest.gno delete mode 100644 examples/gno.land/p/demo/entropy/entropy.gno delete mode 100644 examples/gno.land/p/demo/entropy/entropy_test.gno delete mode 100644 examples/gno.land/p/demo/entropy/gno.mod delete mode 100644 examples/gno.land/p/demo/entropy/z_filetest.gno create mode 100644 examples/gno.land/p/demo/flippandoserver/flippandoserver.gno create mode 100644 examples/gno.land/p/demo/flippandoserver/flippandoserver_test.gno create mode 100644 examples/gno.land/p/demo/flippandoserver/fliprand.gno create mode 100644 examples/gno.land/p/demo/flippandoserver/gno.mod create mode 100644 examples/gno.land/p/demo/flippandoserver/rng.gno delete mode 100644 examples/gno.land/p/demo/fqname/fqname.gno delete mode 100644 examples/gno.land/p/demo/fqname/fqname_test.gno delete mode 100644 examples/gno.land/p/demo/fqname/gno.mod delete mode 100644 examples/gno.land/p/demo/ownable/exts/authorizable/authorizable.gno delete mode 100644 examples/gno.land/p/demo/ownable/exts/authorizable/authorizable_test.gno delete mode 100644 examples/gno.land/p/demo/ownable/exts/authorizable/errors.gno delete mode 100644 examples/gno.land/p/demo/ownable/exts/authorizable/gno.mod delete mode 100644 examples/gno.land/p/demo/subscription/doc.gno delete mode 100644 examples/gno.land/p/demo/subscription/gno.mod delete mode 100644 examples/gno.land/p/demo/subscription/lifetime/errors.gno delete mode 100644 examples/gno.land/p/demo/subscription/lifetime/gno.mod delete mode 100644 examples/gno.land/p/demo/subscription/lifetime/lifetime.gno delete mode 100644 examples/gno.land/p/demo/subscription/lifetime/lifetime_test.gno delete mode 100644 examples/gno.land/p/demo/subscription/recurring/errors.gno delete mode 100644 examples/gno.land/p/demo/subscription/recurring/gno.mod delete mode 100644 examples/gno.land/p/demo/subscription/recurring/recurring.gno delete mode 100644 examples/gno.land/p/demo/subscription/recurring/recurring_test.gno delete mode 100644 examples/gno.land/p/demo/subscription/subscription.gno create mode 100644 examples/gno.land/p/demo/teams/errors.gno create mode 100644 examples/gno.land/p/demo/teams/gno.mod create mode 100644 examples/gno.land/p/demo/teams/teams.gno create mode 100644 examples/gno.land/p/demo/teams/types.gno delete mode 100644 examples/gno.land/r/demo/disperse/disperse.gno delete mode 100644 examples/gno.land/r/demo/disperse/doc.gno delete mode 100644 examples/gno.land/r/demo/disperse/errors.gno delete mode 100644 examples/gno.land/r/demo/disperse/gno.mod delete mode 100644 examples/gno.land/r/demo/disperse/util.gno delete mode 100644 examples/gno.land/r/demo/disperse/z_0_filetest.gno delete mode 100644 examples/gno.land/r/demo/disperse/z_1_filetest.gno delete mode 100644 examples/gno.land/r/demo/disperse/z_2_filetest.gno delete mode 100644 examples/gno.land/r/demo/disperse/z_3_filetest.gno delete mode 100644 examples/gno.land/r/demo/disperse/z_4_filetest.gno create mode 100644 examples/gno.land/r/demo/flippando/airdrop.gno create mode 100644 examples/gno.land/r/demo/flippando/basicNFT.gno create mode 100644 examples/gno.land/r/demo/flippando/compositeNFT.gno create mode 100644 examples/gno.land/r/demo/flippando/errors.gno create mode 100644 examples/gno.land/r/demo/flippando/flip_marketplace_test.gno create mode 100644 examples/gno.land/r/demo/flippando/flippando.gno create mode 100644 examples/gno.land/r/demo/flippando/flippando_test.gno create mode 100644 examples/gno.land/r/demo/flippando/flippandosvg.gno create mode 100644 examples/gno.land/r/demo/flippando/flippandosvg_test.gno create mode 100644 examples/gno.land/r/demo/flippando/gno.mod create mode 100644 examples/gno.land/r/demo/flippando/marketplace.gno create mode 100644 examples/gno.land/r/demo/flippando/marshals.gno create mode 100644 examples/gno.land/r/demo/flippando/token.gno create mode 100644 examples/gno.land/r/demo/flippando/utils.gno delete mode 100644 examples/gno.land/r/demo/games/shifumi/gno.mod delete mode 100644 examples/gno.land/r/demo/games/shifumi/shifumi.gno delete mode 100644 examples/gno.land/r/demo/users/z_12_filetest.gno delete mode 100644 examples/gno.land/r/gnoland/events/administration.gno delete mode 100644 examples/gno.land/r/gnoland/events/errors.gno create mode 100644 examples/gno.land/r/gnoland/events/events_filetest.gno delete mode 100644 examples/gno.land/r/gnoland/events/events_test.gno delete mode 100644 examples/gno.land/r/gnoland/events/rendering.gno delete mode 100644 examples/gno.land/r/gnoland/pages/page_contribute.gno create mode 100644 examples/gno.land/r/gnoland/pages/page_gor.gno delete mode 100644 examples/gno.land/r/leon/config/config.gno delete mode 100644 examples/gno.land/r/leon/config/gno.mod delete mode 100644 examples/gno.land/r/leon/home/gno.mod delete mode 100644 examples/gno.land/r/leon/home/home.gno delete mode 100644 examples/gno.land/r/morgan/guestbook/admin.gno delete mode 100644 examples/gno.land/r/morgan/guestbook/gno.mod delete mode 100644 examples/gno.land/r/morgan/guestbook/guestbook.gno delete mode 100644 examples/gno.land/r/morgan/guestbook/guestbook_test.gno delete mode 100644 examples/gno.land/r/morgan/home/gno.mod delete mode 100644 examples/gno.land/r/morgan/home/home.gno delete mode 100644 gno.land/cmd/gnoland/config_help.go delete mode 100644 gno.land/cmd/gnoland/testdata/alloc_array.txtar delete mode 100644 gno.land/cmd/gnoland/testdata/alloc_byte_slice.txtar delete mode 100644 gno.land/cmd/gnoland/testdata/alloc_slice.txtar delete mode 100644 gno.land/cmd/gnoland/testdata/panic.txtar delete mode 100644 gno.land/cmd/gnoland/testdata/restart_missing_type.txtar delete mode 100644 gno.land/cmd/gnoland/testdata/restart_nonval.txtar delete mode 100644 gno.land/pkg/gnoland/ugnot/denom.go delete mode 100644 gno.land/pkg/gnoweb/alias.go delete mode 100644 gno.land/pkg/integration/testdata/restart.txtar delete mode 100644 gno.land/pkg/sdk/vm/testdata/emptystdlib/README delete mode 100644 gnovm/pkg/gnolang/internal/txlog/txlog.go delete mode 100644 gnovm/pkg/gnolang/internal/txlog/txlog_test.go delete mode 100644 gnovm/pkg/gnolang/nodes_test.go delete mode 100644 gnovm/pkg/gnolang/store_test.go delete mode 100644 gnovm/pkg/gnolang/values_test.go delete mode 100644 gnovm/stdlibs/math/all_test.gno delete mode 100644 gnovm/tests/files/cap1.gno delete mode 100644 gnovm/tests/files/cap10.gno delete mode 100644 gnovm/tests/files/cap2.gno delete mode 100644 gnovm/tests/files/cap3.gno delete mode 100644 gnovm/tests/files/cap4.gno delete mode 100644 gnovm/tests/files/cap5.gno delete mode 100644 gnovm/tests/files/cap6.gno delete mode 100644 gnovm/tests/files/cap7.gno delete mode 100644 gnovm/tests/files/cap8.gno delete mode 100644 gnovm/tests/files/cap9.gno delete mode 100644 gnovm/tests/files/circular_constant.gno delete mode 100644 gnovm/tests/files/len1.gno delete mode 100644 gnovm/tests/files/len2.gno delete mode 100644 gnovm/tests/files/len3.gno delete mode 100644 gnovm/tests/files/len4.gno delete mode 100644 gnovm/tests/files/len5.gno delete mode 100644 gnovm/tests/files/len6.gno delete mode 100644 gnovm/tests/files/len7.gno delete mode 100644 gnovm/tests/files/len8.gno delete mode 100644 gnovm/tests/files/panic0a.gno delete mode 100644 gnovm/tests/files/panic0c.gno delete mode 100644 gnovm/tests/files/panic2a.gno delete mode 100644 gnovm/tests/files/panic2b.gno delete mode 100644 gnovm/tests/files/recursive1.gno delete mode 100644 gnovm/tests/files/recursive1a.gno delete mode 100644 gnovm/tests/files/recursive1b.gno delete mode 100644 gnovm/tests/files/recursive1c.gno delete mode 100644 gnovm/tests/files/recursive1d.gno delete mode 100644 gnovm/tests/files/recursive1e.gno delete mode 100644 gnovm/tests/files/recursive1f.gno delete mode 100644 gnovm/tests/files/recursive2.gno delete mode 100644 gnovm/tests/files/recursive2a.gno delete mode 100644 gnovm/tests/files/recursive2b.gno delete mode 100644 gnovm/tests/files/recursive2c.gno delete mode 100644 gnovm/tests/files/recursive2d.gno delete mode 100644 gnovm/tests/files/recursive3.gno delete mode 100644 gnovm/tests/files/recursive4.gno delete mode 100644 gnovm/tests/files/recursive4a.gno delete mode 100644 gnovm/tests/files/recursive5.gno delete mode 100644 gnovm/tests/files/recursive6.gno delete mode 100644 gnovm/tests/files/recursive6a.gno delete mode 100644 gnovm/tests/files/recursive7.gno delete mode 100644 gnovm/tests/files/recursive7a.gno delete mode 100644 gnovm/tests/files/recursive8.gno delete mode 100644 gnovm/tests/files/recursive9.gno delete mode 100644 gnovm/tests/files/recursive9a.gno delete mode 100644 gnovm/tests/files/recursive9b.gno delete mode 100644 gnovm/tests/files/recursive9c.gno delete mode 100644 gnovm/tests/files/recursive9d.gno delete mode 100644 gnovm/tests/files/time17_native.gno delete mode 100644 gnovm/tests/files/types/cmp_databyte.gno delete mode 100644 gnovm/tests/files/types/cmp_iface_0_stdlibs.gno delete mode 100644 gnovm/tests/files/types/cmp_iface_1.gno delete mode 100644 gnovm/tests/files/types/cmp_iface_2.gno delete mode 100644 gnovm/tests/files/types/cmp_iface_3_stdlibs.gno delete mode 100644 gnovm/tests/files/types/cmp_iface_4.gno delete mode 100644 gnovm/tests/files/types/cmp_iface_5_stdlibs.gno delete mode 100644 gnovm/tests/files/types/cmp_iface_6.gno delete mode 100644 gnovm/tests/files/types/cmp_iface_7.gno delete mode 100644 gnovm/tests/files/types/cmp_primitive_0.gno delete mode 100644 gnovm/tests/files/types/cmp_primitive_1.gno delete mode 100644 gnovm/tests/files/types/cmp_primitive_2.gno delete mode 100644 gnovm/tests/files/types/cmp_primitive_3.gno delete mode 100644 gnovm/tests/files/types/cmp_slice_0.gno delete mode 100644 gnovm/tests/files/types/cmp_slice_1.gno delete mode 100644 gnovm/tests/files/types/cmp_slice_2.gno delete mode 100644 gnovm/tests/files/types/cmp_slice_3.gno delete mode 100644 gnovm/tests/files/types/cmp_slice_4.gno delete mode 100644 gnovm/tests/files/types/cmp_typeswitch.gno delete mode 100644 gnovm/tests/files/types/cmp_typeswitch_a.gno delete mode 100644 gnovm/tests/files/types/eql_0f49.gno delete mode 100644 gnovm/tests/files/types/iface_eql.gno delete mode 100644 gnovm/tests/files/var29.gno delete mode 100644 gnovm/tests/files/var30.gno delete mode 100644 gnovm/tests/files/vardecl.gno delete mode 100644 gnovm/tests/files/zrealm_panic.gno delete mode 100755 misc/deployments/staging.gno.land/gnoland.entrypoint.sh diff --git a/.gitattributes b/.gitattributes index adc4144ffa3..c22d136ec50 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ *.gno linguist-language=Go *.pb.go linguist-generated merge=ours -diff go.sum linguist-generated text -gnovm/stdlibs/generated.go linguist-generated -gnovm/tests/stdlibs/generated.go linguist-generated +gnovm/stdlibs/native.go linguist-generated +gnovm/tests/stdlibs/native.go linguist-generated diff --git a/.github/goreleaser.yaml b/.github/goreleaser.yaml index 1984493d36f..ab98aa92555 100644 --- a/.github/goreleaser.yaml +++ b/.github/goreleaser.yaml @@ -1,10 +1,4 @@ project_name: gno -version: 2 - -env: - - TAG_VERSION={{ if index .Env "TAG_VERSION" }}{{ .Env.TAG_VERSION }}{{ else }}latest{{ end }} - # supported in next versions -> https://github.com/goreleaser/goreleaser/issues/5059 - # - TAG_VERSION="{{ envOrDefault "TAG_VERSION" "latest" }}" before: hooks: @@ -71,22 +65,6 @@ builds: goarm: - 6 - 7 - - id: gnofaucet - dir: ./contribs/gnofaucet - binary: gnofaucet - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 - gomod: proxy: true @@ -121,7 +99,7 @@ dockers: goarch: amd64 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }}-amd64" + - "ghcr.io/gnolang/{{ .ProjectName }}:latest-amd64" build_flag_templates: - "--target=gno" - "--platform=linux/amd64" @@ -141,7 +119,7 @@ dockers: goarch: arm64 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }}-arm64v8" + - "ghcr.io/gnolang/{{ .ProjectName }}:latest-arm64v8" build_flag_templates: - "--target=gno" - "--platform=linux/arm64/v8" @@ -162,7 +140,7 @@ dockers: goarm: 6 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }}-armv6" + - "ghcr.io/gnolang/{{ .ProjectName }}:latest-armv6" build_flag_templates: - "--target=gno" - "--platform=linux/arm/v6" @@ -183,7 +161,7 @@ dockers: goarm: 7 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }}-armv7" + - "ghcr.io/gnolang/{{ .ProjectName }}:latest-armv7" build_flag_templates: - "--target=gno" - "--platform=linux/arm/v7" @@ -205,7 +183,7 @@ dockers: goarch: amd64 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }}-amd64" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest-amd64" build_flag_templates: - "--target=gnoland" - "--platform=linux/amd64" @@ -226,7 +204,7 @@ dockers: goarch: arm64 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }}-arm64v8" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest-arm64v8" build_flag_templates: - "--target=gnoland" - "--platform=linux/arm64/v8" @@ -248,7 +226,7 @@ dockers: goarm: 6 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }}-armv6" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest-armv6" build_flag_templates: - "--target=gnoland" - "--platform=linux/arm/v6" @@ -270,7 +248,7 @@ dockers: goarm: 7 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }}-armv7" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest-armv7" build_flag_templates: - "--target=gnoland" - "--platform=linux/arm/v7" @@ -292,7 +270,7 @@ dockers: goarch: amd64 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }}-amd64" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest-amd64" build_flag_templates: - "--target=gnokey" - "--platform=linux/amd64" @@ -308,7 +286,7 @@ dockers: goarch: arm64 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }}-arm64v8" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest-arm64v8" build_flag_templates: - "--target=gnokey" - "--platform=linux/arm64/v8" @@ -325,7 +303,7 @@ dockers: goarm: 6 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }}-armv6" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest-armv6" build_flag_templates: - "--target=gnokey" - "--platform=linux/arm/v6" @@ -342,7 +320,7 @@ dockers: goarm: 7 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }}-armv7" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest-armv7" build_flag_templates: - "--target=gnokey" - "--platform=linux/arm/v7" @@ -360,7 +338,7 @@ dockers: goarch: amd64 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }}-amd64" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest-amd64" build_flag_templates: - "--target=gnoweb" - "--platform=linux/amd64" @@ -376,7 +354,7 @@ dockers: goarch: arm64 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }}-arm64v8" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest-arm64v8" build_flag_templates: - "--target=gnoweb" - "--platform=linux/arm64/v8" @@ -393,7 +371,7 @@ dockers: goarm: 6 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }}-armv6" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest-armv6" build_flag_templates: - "--target=gnoweb" - "--platform=linux/arm/v6" @@ -410,7 +388,7 @@ dockers: goarm: 7 image_templates: - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }}-armv7" + - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest-armv7" build_flag_templates: - "--target=gnoweb" - "--platform=linux/arm/v7" @@ -421,74 +399,6 @@ dockers: ids: - gnoweb - # gnofaucet - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }}-amd64" - build_flag_templates: - - "--target=gnofaucet" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnofaucet" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnofaucet - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }}-arm64v8" - build_flag_templates: - - "--target=gnofaucet" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnofaucet" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnofaucet - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }}-armv6" - build_flag_templates: - - "--target=gnofaucet" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnofaucet" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnofaucet - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }}-armv7" - build_flag_templates: - - "--target=gnofaucet" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnofaucet" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnofaucet - docker_manifests: # https://goreleaser.com/customization/docker_manifest/ @@ -499,12 +409,12 @@ docker_manifests: - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-arm64v8 - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv6 - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv7 - - name_template: ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }} + - name_template: ghcr.io/gnolang/{{ .ProjectName }}:latest image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }}-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }}-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }}-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Env.TAG_VERSION }}-armv7 + - ghcr.io/gnolang/{{ .ProjectName }}:latest-amd64 + - ghcr.io/gnolang/{{ .ProjectName }}:latest-arm64v8 + - ghcr.io/gnolang/{{ .ProjectName }}:latest-armv6 + - ghcr.io/gnolang/{{ .ProjectName }}:latest-armv7 # gnoland - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }} @@ -513,12 +423,12 @@ docker_manifests: - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-arm64v8 - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-armv6 - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-armv7 - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }} + - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }}-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }}-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }}-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Env.TAG_VERSION }}-armv7 + - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest-amd64 + - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest-arm64v8 + - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest-armv6 + - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:latest-armv7 # gnokey - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }} @@ -527,13 +437,13 @@ docker_manifests: - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-arm64v8 - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-armv6 - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-armv7 - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }} + - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }}-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }}-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }}-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Env.TAG_VERSION }}-armv7 - + - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest-amd64 + - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest-arm64v8 + - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest-armv6 + - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:latest-armv7 + # gnoweb - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }} image_templates: @@ -541,26 +451,12 @@ docker_manifests: - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-arm64v8 - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-armv6 - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-armv7 - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }} + - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }}-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }}-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }}-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Env.TAG_VERSION }}-armv7 - - # gnofaucet - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }}-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }}-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }}-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Version }}-armv7 - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }}-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }}-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }}-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnofaucet:{{ .Env.TAG_VERSION }}-armv7 + - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest-amd64 + - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest-arm64v8 + - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest-armv6 + - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:latest-armv7 docker_signs: - cmd: cosign @@ -588,8 +484,6 @@ sboms: artifacts: source release: - disable: '{{ if eq .Env.TAG_VERSION "master" }}true{{ else }}false{{ end }}' - skip_upload: '{{ if eq .Env.TAG_VERSION "master" }}true{{ else }}false{{ end }}' draft: true replace_existing_draft: true prerelease: auto @@ -599,11 +493,4 @@ release: You can find all docker images at: - https://github.com/orgs/gnolang/packages?repo_name={{ .ProjectName }} - -# Only valid for nightly build -nightly: - tag_name: nightly - publish_release: true - keep_single_release: true - name_template: "{{ incpatch .Version }}-{{ .ShortCommit }}-{{ .Env.TAG_VERSION }}" + https://github.com/orgs/gnolang/packages?repo_name={{ .ProjectName }} \ No newline at end of file diff --git a/.github/workflows/lint_template.yml b/.github/workflows/lint_template.yml index 65679633240..098650c1df2 100644 --- a/.github/workflows/lint_template.yml +++ b/.github/workflows/lint_template.yml @@ -1,12 +1,12 @@ on: workflow_call: - inputs: - modulepath: - required: true - type: string - go-version: - required: true - type: string + inputs: + modulepath: + required: true + type: string + go-version: + required: true + type: string jobs: @@ -25,4 +25,3 @@ jobs: working-directory: ${{ inputs.modulepath }} args: --config=${{ github.workspace }}/.github/golangci.yml - version: v1.59 # sync with misc/devdeps \ No newline at end of file diff --git a/.github/workflows/nightlies.yml b/.github/workflows/nightlies.yml index e8f3fe4ca5c..6e3e3e58935 100644 --- a/.github/workflows/nightlies.yml +++ b/.github/workflows/nightlies.yml @@ -23,8 +23,8 @@ jobs: go-version: "1.22.x" cache: true - - uses: sigstore/cosign-installer@v3.6.0 - - uses: anchore/sbom-action/download-syft@v0.17.2 + - uses: sigstore/cosign-installer@v3.5.0 + - uses: anchore/sbom-action/download-syft@v0.17.0 - uses: docker/login-action@v3 with: @@ -38,9 +38,8 @@ jobs: - uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser-pro - version: ~> v2 - args: release --clean --nightly --config ./.github/goreleaser.yaml + version: v1.26.2-pro + args: release --clean --nightly --config ./.github/goreleaser-nightly.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} - TAG_VERSION: nightly diff --git a/.github/workflows/portal-loop.yml b/.github/workflows/portal-loop.yml index b81957b22db..1c83a2854c2 100644 --- a/.github/workflows/portal-loop.yml +++ b/.github/workflows/portal-loop.yml @@ -1,17 +1,13 @@ name: portal-loop on: - pull_request: - branches: - - master push: paths: - "misc/loop/**" - ".github/workflows/portal-loop.yml" branches: - "master" - # NOTE(albttx): branch name to simplify tests for this workflow - - "ci/portal-loop" + - "ops/portal-loop" tags: - "v*" @@ -50,57 +46,3 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - - test-portal-loop-docker-compose: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: "Checkout" - uses: actions/checkout@v4 - - - name: "Setup the images" - run: | - cd misc/loop - - docker compose build - docker compose pull - docker compose up -d - - - name: "Test1 - Portal loop start gnoland" - run: | - while - block_height=$(curl -s localhost:26657/status | jq -r '.result.sync_info.latest_block_height') - echo "Current block height: $block_height" - [[ "$block_height" -lt 10 ]] - do - sleep 1 - done - - curl -s localhost:26657/status | jq - - - name: "Buid new gnolang/gno image" - run: | - docker build -t ghcr.io/gnolang/gno/gnoland:master -f Dockerfile --target gnoland . - - - name: "Wait for new docker image" - run: | - ip_addr=$(cat misc/loop/traefik/gno.yml | grep -o "http://.*:26657") - while - new_ip_addr=$(cat misc/loop/traefik/gno.yml | grep -o "http://.*:26657") - echo "${ip_addr} -> ${new_ip_addr}" - [[ "${ip_addr}" == ${new_ip_addr} ]] - do - sleep 5 - done - - - name: "Test2 - Wait portal-loop start new image" - run: | - while - block_height=$(curl -s localhost:26657/status | jq -r '.result.sync_info.latest_block_height') - echo "Current block height: $block_height" - [[ "$block_height" -lt 10 ]] - do - sleep 5 - done - docker ps -a - curl -s localhost:26657/status | jq diff --git a/.github/workflows/releaser-master.yml b/.github/workflows/releaser-master.yml index 7eda0536532..3ed5353ec89 100644 --- a/.github/workflows/releaser-master.yml +++ b/.github/workflows/releaser-master.yml @@ -24,8 +24,8 @@ jobs: go-version: "1.22.x" cache: true - - uses: sigstore/cosign-installer@v3.6.0 - - uses: anchore/sbom-action/download-syft@v0.17.2 + - uses: sigstore/cosign-installer@v3.5.0 + - uses: anchore/sbom-action/download-syft@v0.17.0 - uses: docker/login-action@v3 with: @@ -39,9 +39,8 @@ jobs: - uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser-pro - version: ~> v2 - args: release --clean --nightly --config ./.github/goreleaser.yaml + version: v1.26.2-pro + args: release --clean --nightly --config ./.github/goreleaser-master.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} - TAG_VERSION: master diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml index 5433582cace..9148d9ac15c 100644 --- a/.github/workflows/releaser.yml +++ b/.github/workflows/releaser.yml @@ -23,8 +23,8 @@ jobs: go-version: "1.22.x" cache: true - - uses: sigstore/cosign-installer@v3.6.0 - - uses: anchore/sbom-action/download-syft@v0.17.2 + - uses: sigstore/cosign-installer@v3.5.0 + - uses: anchore/sbom-action/download-syft@v0.17.0 - uses: docker/login-action@v3 with: @@ -38,7 +38,7 @@ jobs: - uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser-pro - version: ~> v2 + version: v1.26.2-pro args: release --clean --config ./.github/goreleaser.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index fa5a9e47270..00000000000 --- a/Dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -# build gno -FROM golang:1.22-alpine AS build-gno -RUN go env -w GOMODCACHE=/root/.cache/go-build -WORKDIR /gnoroot -ENV GNOROOT="/gnoroot" -COPY . ./ -RUN --mount=type=cache,target=/root/.cache/go-build go mod download -RUN --mount=type=cache,target=/root/.cache/go-build go build -o ./build/gnoland ./gno.land/cmd/gnoland -RUN --mount=type=cache,target=/root/.cache/go-build go build -o ./build/gnokey ./gno.land/cmd/gnokey -RUN --mount=type=cache,target=/root/.cache/go-build go build -o ./build/gnoweb ./gno.land/cmd/gnoweb -RUN --mount=type=cache,target=/root/.cache/go-build go build -o ./build/gno ./gnovm/cmd/gno - -# Base image -FROM alpine:3.17 AS base -WORKDIR /gnoroot -ENV GNOROOT="/gnoroot" -RUN apk add ca-certificates -CMD [ "" ] - -# alpine images -# gnoland -FROM base AS gnoland -COPY --from=build-gno /gnoroot/build/gnoland /usr/bin/gnoland -COPY --from=build-gno /gnoroot/examples /gnoroot/examples -COPY --from=build-gno /gnoroot/gnovm/stdlibs /gnoroot/gnovm/stdlibs -COPY --from=build-gno /gnoroot/gno.land/genesis/genesis_txs.jsonl /gnoroot/gno.land/genesis/genesis_txs.jsonl -COPY --from=build-gno /gnoroot/gno.land/genesis/genesis_balances.txt /gnoroot/gno.land/genesis/genesis_balances.txt -EXPOSE 26656 26657 -ENTRYPOINT ["/usr/bin/gnoland"] - -# gnokey -FROM base AS gnokey -COPY --from=build-gno /gnoroot/build/gnokey /usr/bin/gnokey -# gofmt is required by `gnokey maketx addpkg` -COPY --from=build-gno /usr/local/go/bin/gofmt /usr/bin/gofmt -ENTRYPOINT ["/usr/bin/gnokey"] - -# gno -FROM base AS gno -COPY --from=build-gno /gnoroot/build/gno /usr/bin/gno -ENTRYPOINT ["/usr/bin/gno"] - -# gnoweb -FROM base AS gnoweb -COPY --from=build-gno /gnoroot/build/gnoweb /usr/bin/gnoweb -COPY --from=build-gno /opt/gno/src/gno.land/cmd/gnoweb /opt/gno/src/gnoweb -EXPOSE 8888 -ENTRYPOINT ["/usr/bin/gnoweb"] - -# all, contains everything. -FROM base AS all -COPY --from=build-gno /gnoroot/build/* /usr/bin/ -COPY --from=build-gno /gnoroot/examples /gnoroot/examples -COPY --from=build-gno /gnoroot/gnovm/stdlibs /gnoroot/gnovm/stdlibs -COPY --from=build-gno /gnoroot/gno.land/genesis/genesis_txs.jsonl /gnoroot/gno.land/genesis/genesis_txs.jsonl -COPY --from=build-gno /gnoroot/gno.land/genesis/genesis_balances.txt /gnoroot/gno.land/genesis/genesis_balances.txt -# gofmt is required by `gnokey maketx addpkg` -COPY --from=build-gno /usr/local/go/bin/gofmt /usr/bin diff --git a/Dockerfile.release b/Dockerfile.release index 644f8cb5de9..2e36453382e 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -35,13 +35,6 @@ COPY ./gnoweb /usr/bin/gnoweb EXPOSE 8888 ENTRYPOINT [ "/usr/bin/gnoweb" ] -# -## ghcr.io/gnolang/gno/gnofaucet -FROM base as gnofaucet - -COPY ./gnofaucet /usr/bin/gnofaucet -EXPOSE 5050 -ENTRYPOINT [ "/usr/bin/gnofaucet" ] # ## ghcr.io/gnolang/gno diff --git a/contribs/gnodev/Makefile b/contribs/gnodev/Makefile index df57040d92d..01801064d1f 100644 --- a/contribs/gnodev/Makefile +++ b/contribs/gnodev/Makefile @@ -5,13 +5,11 @@ GOTEST_FLAGS ?= $(GOBUILD_FLAGS) -v -p 1 -timeout=5m rundep := go run -modfile ../../misc/devdeps/go.mod golangci_lint := $(rundep) github.com/golangci/golangci-lint/cmd/golangci-lint -install: install.gnodev -install.gnodev: +install: go install $(GOBUILD_FLAGS) ./cmd/gnodev -# keep gnobro out the default install for now -install.gnobro: - go install $(GOBUILD_FLAGS) ./cmd/gnobro +build: + go build $(GOBUILD_FLAGS) -o build/gnodev ./cmd/gnodev lint: $(golangci_lint) --config ../../.github/golangci.yml run ./... diff --git a/contribs/gnodev/README.md b/contribs/gnodev/README.md index 3b26903c7eb..6da9e7b1ebc 100644 --- a/contribs/gnodev/README.md +++ b/contribs/gnodev/README.md @@ -1,67 +1,30 @@ -## `gnodev`: Your Gno Development Companion +## `gnodev`: Your Gno Companion Tool -`gnodev` is a robust tool designed to streamline your Gno package development process, enhancing productivity -by providing immediate feedback on code changes. +`gnodev` is designed to be a robust and user-friendly tool in your realm package development journey, streamlining your workflow and enhancing productivity. -Please note that this is a quick overview. For a more detailed guide, refer to the official documentation at -[docs/gno-tooling/gnodev.md](../../docs/gno-tooling/cli/gnodev.md). +We will only give a quick overview below. You may find the official documentation at [docs/gno-tooling/gnodev.md](../../docs/gno-tooling/cli/gnodev.md). ### Synopsis -**gnodev** [**options**] [**PKG_PATH ...**] +**gnodev** [**-minimal**] [**-no-watch**] [**PKG_PATH ...**] ### Features -- **In-Memory Node**: Gnodev starts an in-memory node, automatically loading the **examples** folder and any - user-specified paths. -- **Web Interface Server**: Gnodev starts a `gnoweb` server on [`localhost:8888`](https://localhost:8888). -- **Balances and Keybase Customization**: Set account balances, load them from a file, or add new accounts via a flag. -- **Hot Reload**: Monitors the **examples** folder and specified directories for file changes, reloading the - package and automatically restarting the node as needed. -- **State Maintenance**: Ensures the previous node state is preserved by replaying all transactions. -- **Transaction Manipulation**: Allows for interactive cancellation and redoing of transactions. -- **State Export**: Export the current state at any time in a genesis doc format. +- **In-Memory Node**: Gnodev starts an in-memory node, and automatically loads + the **examples** folder and any user-specified paths. +- **Web Interface Server**: Starts a `gnoweb` server on `localhost:8888`. +- **Hot Reload**: Monitors the example packages folder and specified directories for file changes, + reloading the package and automatically restarting the node as needed. +- **State Maintenance**: Ensures the current state is preserved by replaying all transactions. ### Commands -While `gnodev` is running, trigger specific actions by pressing the following combinations: -- **H**: Display help information. -- **A**: Display account balances. -- **R**: Reload the node manually. -- **P**: Cancel the last action. -- **N**: Redo the last cancelled action. -- **Ctrl+S**: Save the current state. -- **Ctrl+R**: Restore the saved state. -- **E**: Export the current state to a genesis file. -- **Cmd+R**: Reset the current node state. -- **Cmd+C**: Exit `gnodev`. - -### Usage -Run `gnodev` followed by any specific options and/or package paths. The **examples** directory is loaded -automatically. Use `--minimal` to prevent this. - -Example: -``` -gnodev --add-account [:] ./myrealm -``` - -### `gnobro`: realm interface -`gnobro` is a terminal user interface (TUI) that allows you to browse realms within your terminal. It -automatically connects to `gnodev` for real-time development. In addition to hot reload, it also has the -ability to execute commands and interact with your realm. - - -#### Usage -**gnobro** [**options**] [**PKG_PATH **] - -Run gnobro followed by any specific options and/or a target pacakge path. - -Use `gnobro -h` for a detailed list of options. - -Example: -``` -gnobro gno.land/r/demo/home -``` +While `gnodev` is running, the user can trigger specific actions by pressing +the following combinations: +- **H**: Display help information. +- **R**: Reload the node, without resetting the state. +- **Ctrl+R**: Reset the current node state. +- **Ctrl+C**: Exit `gnodev`. +### Loading 'examples' +The **examples** directory is loaded automatically. If working within this folder, you don't have to specify any additional paths to `gnodev`. Use `--minimal` to prevent this. ### Installation Run `make install` to install `gnodev`. - -Run `make install.gnobro` to install `gnobro`. diff --git a/contribs/gnodev/cmd/gnobro/assets/banner_land_1.txt b/contribs/gnodev/cmd/gnobro/assets/banner_land_1.txt deleted file mode 100644 index 9a5931625ca..00000000000 --- a/contribs/gnodev/cmd/gnobro/assets/banner_land_1.txt +++ /dev/null @@ -1,19 +0,0 @@ - . + - + . Hello %s, Welcome to - . -+ .,-:::::/ :::. :::. ... . - . ,;;-'````' `;;;;, `;;; .;;;;;;;. - [[[ [[[[[[/ [[[[[. '[[ ,[[ \[[, - "$$c. "$$ + $$$ "Y$c$$ $$$, $$$ - `Y8bo,,,o88o 888 Y88 "888,_ _,88P - . `'YMUP"YMM MMM . YM "YMMMMMP" + - . . - ::: + :::. :::. :::. :::::::-. - ;;; ;;`;; `;;;;, `;;; ;;, `';, - + [[[ ,[[ '[[, + [[[[[. '[[ `[[ [[ - $$' c$$$cc$$$c $$$ "Y$c$$ $$, $$ - o88oo,.__ 888 888, 888 Y88 888_,o8P' - """"YUMMM YMM ""` MMM + YM MMMMP"` + - . - + - press to continue diff --git a/contribs/gnodev/cmd/gnobro/assets/gn_hc1.utf8ans b/contribs/gnodev/cmd/gnobro/assets/gn_hc1.utf8ans deleted file mode 100644 index b50762d0abb..00000000000 --- a/contribs/gnodev/cmd/gnobro/assets/gn_hc1.utf8ans +++ /dev/null @@ -1,25 +0,0 @@ - · . · · - . * . . * . · - · · · · . . . - · . . . . · * - . · . . · - ░░ ░░ ░ ░░ ░ ░░ ░ ░░ ░░░ ░░░░░░ ░░░ ░░░░ ░ ░░ -░░▒▒░░░▒▒░░░░░▒░░░░░░▒▒░░▒░░▒▒░▒░░░░░░░ ░░░░░░▒▒░▒▒▒░▒▒▒▒▒▒░░▒▒▒░░░▒▒▒▒░▒░░▒▒░░ -▒▒▓▓▒▒▒▓▓▒▒▒▒▒▓▒▒▒▒▒▒▓▓▒▒▓▒▒▓▓▒▓▒▒▒▒▒▒▒░▒▒▒▒▒▒▓▓▒▓▓▓▒▓▓▓▓▓▓▒▒▓▓▓▒▒▒▓▓▓▓▒▓▒▒▓▓▒▒ -▓▓██▓▓▓██▓▓▓▓▓█▓▓▓▓▓▓██▓▓█▓▓██▓█▓▓▓▓▓▓▓▒▓▓▓▓▓▓██▓███▓██████▓▓███▓▓▓████▓█▓▓██▓▓ -▀██▒███ █████ ██████▌▐██▒██▌██▒███████▓███▓██▌▐██▒██▌██▒█████▒████ ███▒███ ██ - ▐▒▒▒█ █▒█▌ ▐▒███▌ ▐▒▒▒▌ ▐▒▒███▌█▒███▌███▌ ▐▒▒▒▌ ▐▒▒███▌█▒███ █▒▒▒█▌ ▐▒ - ▒▒▒▒▄ ▄▒█ ▒█▒█▄ ▒▒▒░ ▀▒▒█▌ ▐▒██▐ █▒█▄ ▒▒▒░ ▀▒▒█▌ ▐▒ █▄ ▄▒▒ ▒ ▒ - ░ ░ ▄ ▄▄▒▌ ▒█▒▀ ▀▒▒ ▒▒▒▀▄ ▄▒▄▀▀▄▐▒▀ ▀▒▒ ▒▒▒▀▄ ▄▒ █ ▄ ▄▄▄▀▀▄ ▒ - ▀░ ▒░▒▄░ ▀▄▒▀▒▒ ▀█▒▄▄ ▄■▄▒▒▀ ▒▌░░▐░▀ ▒ ▀ ▄ ■▒░▀ ▒ ▀░ ▒░▌░░▐░ ▀▄ - ▌░░▐ ▌░░▐ - ▄▄▀▀▀▀▀▀▀▄▄▀▀▄▀▀▀▀▀▄ ▄▀▀▀▀▀▄ ▌▒▒▐ ▄▄▀▀▀▀▀▄ ▄▀▄▄▀▀▀▀▀▄ ▄▄▄▄▄▌▒▒▐ - ▌▄▓▓▓▓▓▓▓▄ ▓▓▄▓▓▓▓▓▄▀▀▄▓▓▓▓▓▄▀▄ ▌▓▓▐ ▌▄▓▓▓▓▓▄▀▌▓▌▄▓▓▓▓▓▄▀▀▄▄▄▄▄▄▓▓▐ - ▌█▌ ██ ███▀▄▄▀██ ▐██▀▀▀██▌▐ ▌██▐ ▐▐██▀▀▀██▌ ███▀▄▄▀██ ▐██▀▀▀███▐ - ▌▀░░░░░░░░ ░░▌▌ ▌░░ ░░ ░░▐ ▌░░▐ ▌░░ ░░ ░░▌█ ▌░░ ░░▌ ▐░░▐ - ▐ ▒▒ ▒▒▌▌ ▌▒▒ ▒▒▌ ▐▒▒▐▄▀▄▌▒▒▐ ▌▒▒▌ ▐▒▒ ▒▒▌▌ ▌▒▒ ▒▒▌ ▐▒▒▐ - ▌▄▄ ▓▓ ▓▓▌▌ ▌▓▓ ▓▓▓ ▓▓▓ ▄▓▄ ▓▓ ▀▀ ▓▓▓ ▐▓▓ ▓▓▌▌ ▌▓▓ ▓▓▓ ▐▓▓▐ -░ ▌▀███████▀ ███▐ ▐▐██ ▄▀█████▀▄▄▀█▀▄▀████ ▄▀████▀██ ███▐ ▐▐██ ▄▀████▀██▐ ░ -▒ ▓▓▄▄▄▄▄▄▄▄▀▄▄▄▀ ▀▄▄▀ ▀▄▄▄▄▄▀ ▀▄▀ ▀▄▄▄▄▀ ▀▄▄▄▄▀▄▄▀▄▄▄▀ ▀▄▄▀ ▀▄▄▄▄▀▄▄▓ ▒ -▓ ▓ -█▓▒░ ░▒▓█ \ No newline at end of file diff --git a/contribs/gnodev/cmd/gnobro/assets/gn_hc2.utf8ans b/contribs/gnodev/cmd/gnobro/assets/gn_hc2.utf8ans deleted file mode 100644 index 12a3a9a236f..00000000000 --- a/contribs/gnodev/cmd/gnobro/assets/gn_hc2.utf8ans +++ /dev/null @@ -1,25 +0,0 @@ - · . · · - . + . . + . · - · · · · . . . - · . . . . · + - . · . . · - ░░ ░░ ░ ░░ ░ ░░ ░ ░░ ░░░ ░░░░░░ ░░░ ░░░░ ░ ░░ -░░▒▒░░░▒▒░░░░░▒░░░░░░▒▒░░▒░░▒▒░▒░░░░░░░ ░░░░░░▒▒░▒▒▒░▒▒▒▒▒▒░░▒▒▒░░░▒▒▒▒░▒░░▒▒░░ -▒▒▓▓▒▒▒▓▓▒▒▒▒▒▓▒▒▒▒▒▒▓▓▒▒▓▒▒▓▓▒▓▒▒▒▒▒▒▒░▒▒▒▒▒▒▓▓▒▓▓▓▒▓▓▓▓▓▓▒▒▓▓▓▒▒▒▓▓▓▓▒▓▒▒▓▓▒▒ -▓▓██▓▓▓██▓▓▓▓▓█▓▓▓▓▓▓██▓▓█▓▓██▓█▓▓▓▓▓▓▓▒▓▓▓▓▓▓██▓███▓██████▓▓███▓▓▓████▓█▓▓██▓▓ -▀██▒███ █████ ██████▌▐██▒██▌██▒███████▓███▓██▌▐██▒██▌██▒█████▒████ ███▒███ ██ - ▐▒▒▒█ █▒█▌ ▐▒███▌ ▐▒▒▒▌ ▐▒▒███▌█▒███▌███▌ ▐▒▒▒▌ ▐▒▒███▌█▒███ █▒▒▒█▌ ▐▒ - ▒▒▒▒▄ ▄▒█ ▒█▒█▄ ▒▒▒░ ▀▒▒█▌ ▐▒██▐ █▒█▄ ▒▒▒░ ▀▒▒█▌ ▐▒ █▄ ▄▒▒ ▒ ▒ - ░ ░ ▄ ▄▄▒▌ ▒█▒▀ ▀▒▒ ▒▒▒▀▄ ▄▒▄▀▀▄▐▒▀ ▀▒▒ ▒▒▒▀▄ ▄▒ █ ▄ ▄▄▄▀▀▄ ▒ - ▀░ ▒░▒▄░ ▀▄▒▀▒▒ ▀█▒▄▄ ▄■▄▒▒▀ ▒▌░░▐░▀ ▒ ▀ ▄ ■▒░▀ ▒ ▀░ ▒░▌░░▐░ ▀▄ - ▌░░▐ ▌░░▐ - ▄▄▀▀▀▀▀▀▀▄▄▀▀▄▀▀▀▀▀▄ ▄▀▀▀▀▀▄ ▌▒▒▐ ▄▄▀▀▀▀▀▄ ▄▀▄▄▀▀▀▀▀▄ ▄▄▄▄▄▌▒▒▐ - ▌▄▓▓▓▓▓▓▓▄ ▓▓▄▓▓▓▓▓▄▀▀▄▓▓▓▓▓▄▀▄ ▌▓▓▐ ▌▄▓▓▓▓▓▄▀▌▓▌▄▓▓▓▓▓▄▀▀▄▄▄▄▄▄▓▓▐ - ▌█▌ ██ ███▀▄▄▀██ ▐██▀▀▀██▌▐ ▌██▐ ▐▐██▀▀▀██▌ ███▀▄▄▀██ ▐██▀▀▀███▐ - ▌▀░░░░░░░░ ░░▌▌ ▌░░ ░░ ░░▐ ▌░░▐ ▌░░ ░░ ░░▌█ ▌░░ ░░▌ ▐░░▐ - ▐ ▒▒ ▒▒▌▌ ▌▒▒ ▒▒▌ ▐▒▒▐▄▀▄▌▒▒▐ ▌▒▒▌ ▐▒▒ ▒▒▌▌ ▌▒▒ ▒▒▌ ▐▒▒▐ - ▌▄▄ ▓▓ ▓▓▌▌ ▌▓▓ ▓▓▓ ▓▓▓ ▄▓▄ ▓▓ ▀▀ ▓▓▓ ▐▓▓ ▓▓▌▌ ▌▓▓ ▓▓▓ ▐▓▓▐ -░ ▌▀███████▀ ███▐ ▐▐██ ▄▀█████▀▄▄▀█▀▄▀████ ▄▀████▀██ ███▐ ▐▐██ ▄▀████▀██▐ ░ -▒ ▓▓▄▄▄▄▄▄▄▄▀▄▄▄▀ ▀▄▄▀ ▀▄▄▄▄▄▀ ▀▄▀ ▀▄▄▄▄▀ ▀▄▄▄▄▀▄▄▀▄▄▄▀ ▀▄▄▀ ▀▄▄▄▄▀▄▄▓ ▒ -▓ ▓ -█▓▒░ ░▒▓█ \ No newline at end of file diff --git a/contribs/gnodev/cmd/gnobro/assets/gn_hc3.utf8ans b/contribs/gnodev/cmd/gnobro/assets/gn_hc3.utf8ans deleted file mode 100644 index ff26c68f964..00000000000 --- a/contribs/gnodev/cmd/gnobro/assets/gn_hc3.utf8ans +++ /dev/null @@ -1,25 +0,0 @@ - · . · · - . · . . · . · - · · · · . . . - · . . . . · · - . · . . · - ░░ ░░ ░ ░░ ░ ░░ ░ ░░ ░░░ ░░░░░░ ░░░ ░░░░ ░ ░░ -░░▒▒░░░▒▒░░░░░▒░░░░░░▒▒░░▒░░▒▒░▒░░░░░░░ ░░░░░░▒▒░▒▒▒░▒▒▒▒▒▒░░▒▒▒░░░▒▒▒▒░▒░░▒▒░░ -▒▒▓▓▒▒▒▓▓▒▒▒▒▒▓▒▒▒▒▒▒▓▓▒▒▓▒▒▓▓▒▓▒▒▒▒▒▒▒░▒▒▒▒▒▒▓▓▒▓▓▓▒▓▓▓▓▓▓▒▒▓▓▓▒▒▒▓▓▓▓▒▓▒▒▓▓▒▒ -▓▓██▓▓▓██▓▓▓▓▓█▓▓▓▓▓▓██▓▓█▓▓██▓█▓▓▓▓▓▓▓▒▓▓▓▓▓▓██▓███▓██████▓▓███▓▓▓████▓█▓▓██▓▓ -▀██▒███ █████ ██████▌▐██▒██▌██▒███████▓███▓██▌▐██▒██▌██▒█████▒████ ███▒███ ██ - ▐▒▒▒█ █▒█▌ ▐▒███▌ ▐▒▒▒▌ ▐▒▒███▌█▒███▌███▌ ▐▒▒▒▌ ▐▒▒███▌█▒███ █▒▒▒█▌ ▐▒ - ▒▒▒▒▄ ▄▒█ ▒█▒█▄ ▒▒▒░ ▀▒▒█▌ ▐▒██▐ █▒█▄ ▒▒▒░ ▀▒▒█▌ ▐▒ █▄ ▄▒▒ ▒ ▒ - ░ ░ ▄ ▄▄▒▌ ▒█▒▀ ▀▒▒ ▒▒▒▀▄ ▄▒▄▀▀▄▐▒▀ ▀▒▒ ▒▒▒▀▄ ▄▒ █ ▄ ▄▄▄▀▀▄ ▒ - ▀░ ▒░▒▄░ ▀▄▒▀▒▒ ▀█▒▄▄ ▄■▄▒▒▀ ▒▌░░▐░▀ ▒ ▀ ▄ ■▒░▀ ▒ ▀░ ▒░▌░░▐░ ▀▄ - ▌░░▐ ▌░░▐ - ▄▄▀▀▀▀▀▀▀▄▄▀▀▄▀▀▀▀▀▄ ▄▀▀▀▀▀▄ ▌▒▒▐ ▄▄▀▀▀▀▀▄ ▄▀▄▄▀▀▀▀▀▄ ▄▄▄▄▄▌▒▒▐ - ▌▄▓▓▓▓▓▓▓▄ ▓▓▄▓▓▓▓▓▄▀▀▄▓▓▓▓▓▄▀▄ ▌▓▓▐ ▌▄▓▓▓▓▓▄▀▌▓▌▄▓▓▓▓▓▄▀▀▄▄▄▄▄▄▓▓▐ - ▌█▌ ██ ███▀▄▄▀██ ▐██▀▀▀██▌▐ ▌██▐ ▐▐██▀▀▀██▌ ███▀▄▄▀██ ▐██▀▀▀███▐ - ▌▀░░░░░░░░ ░░▌▌ ▌░░ ░░ ░░▐ ▌░░▐ ▌░░ ░░ ░░▌█ ▌░░ ░░▌ ▐░░▐ - ▐ ▒▒ ▒▒▌▌ ▌▒▒ ▒▒▌ ▐▒▒▐▄▀▄▌▒▒▐ ▌▒▒▌ ▐▒▒ ▒▒▌▌ ▌▒▒ ▒▒▌ ▐▒▒▐ - ▌▄▄ ▓▓ ▓▓▌▌ ▌▓▓ ▓▓▓ ▓▓▓ ▄▓▄ ▓▓ ▀▀ ▓▓▓ ▐▓▓ ▓▓▌▌ ▌▓▓ ▓▓▓ ▐▓▓▐ -░ ▌▀███████▀ ███▐ ▐▐██ ▄▀█████▀▄▄▀█▀▄▀████ ▄▀████▀██ ███▐ ▐▐██ ▄▀████▀██▐ ░ -▒ ▓▓▄▄▄▄▄▄▄▄▀▄▄▄▀ ▀▄▄▀ ▀▄▄▄▄▄▀ ▀▄▀ ▀▄▄▄▄▀ ▀▄▄▄▄▀▄▄▀▄▄▄▀ ▀▄▄▀ ▀▄▄▄▄▀▄▄▓ ▒ -▓ ▓ -█▓▒░ ░▒▓█ \ No newline at end of file diff --git a/contribs/gnodev/cmd/gnobro/assets/gn_hc4.utf8ans b/contribs/gnodev/cmd/gnobro/assets/gn_hc4.utf8ans deleted file mode 100644 index b92dee86843..00000000000 --- a/contribs/gnodev/cmd/gnobro/assets/gn_hc4.utf8ans +++ /dev/null @@ -1,25 +0,0 @@ - · . · · - . · . . · . · - · · · · . . . - · . . . . · · - . · . . · - ░░ ░░ ░ ░░ ░ ░░ ░ ░░ ░░░ ░░░░░░ ░░░ ░░░░ ░ ░░ -░░▒▒░░░▒▒░░░░░▒░░░░░░▒▒░░▒░░▒▒░▒░░░░░░░ ░░░░░░▒▒░▒▒▒░▒▒▒▒▒▒░░▒▒▒░░░▒▒▒▒░▒░░▒▒░░ -▒▒▓▓▒▒▒▓▓▒▒▒▒▒▓▒▒▒▒▒▒▓▓▒▒▓▒▒▓▓▒▓▒▒▒▒▒▒▒░▒▒▒▒▒▒▓▓▒▓▓▓▒▓▓▓▓▓▓▒▒▓▓▓▒▒▒▓▓▓▓▒▓▒▒▓▓▒▒ -▓▓██▓▓▓██▓▓▓▓▓█▓▓▓▓▓▓██▓▓█▓▓██▓█▓▓▓▓▓▓▓▒▓▓▓▓▓▓██▓███▓██████▓▓███▓▓▓████▓█▓▓██▓▓ -▀██▒███ █████ ██████▌▐██▒██▌██▒███████▓███▓██▌▐██▒██▌██▒█████▒████ ███▒███ ██ - ▐▒▒▒█ █▒█▌ ▐▒███▌ ▐▒▒▒▌ ▐▒▒███▌█▒███▌███▌ ▐▒▒▒▌ ▐▒▒███▌█▒███ █▒▒▒█▌ ▐▒ - ▒▒▒▒▄ ▄▒█ ▒█▒█▄ ▒▒▒░ ▀▒▒█▌ ▐▒██▐ █▒█▄ ▒▒▒░ ▀▒▒█▌ ▐▒ █▄ ▄▒▒ ▒ ▒ - ░ ░ ▄ ▄▄▒▌ ▒█▒▀ ▀▒▒ ▒▒▒▀▄ ▄▒▄▀▀▄▐▒▀ ▀▒▒ ▒▒▒▀▄ ▄▒ █ ▄ ▄▄▄▀▀▄ ▒ - ▀░ ▒░▒▄░ ▀▄▒▀▒▒ ▀█▒▄▄ ▄■▄▒▒▀ ▒▌░░▐░▀ ▒ ▀ ▄ ■▒░▀ ▒ ▀░ ▒░▌░░▐░ ▀▄ - ▌░░▐ ▌░░▐ - ▄▄▀▀▀▀▀▀▀▄▄▀▀▄▀▀▀▀▀▄ ▄▀▀▀▀▀▄ ▌▒▒▐ ▄▄▀▀▀▀▀▄ ▄▀▄▄▀▀▀▀▀▄ ▄▄▄▄▄▌▒▒▐ - ▌▄▓▓▓▓▓▓▓▄ ▓▓▄▓▓▓▓▓▄▀▀▄▓▓▓▓▓▄▀▄ ▌▓▓▐ ▌▄▓▓▓▓▓▄▀▌▓▌▄▓▓▓▓▓▄▀▀▄▄▄▄▄▄▓▓▐ - ▌█▌ ██ ███▀▄▄▀██ ▐██▀▀▀██▌▐ ▌██▐ ▐▐██▀▀▀██▌ ███▀▄▄▀██ ▐██▀▀▀███▐ - ▌▀░░░░░░░░ ░░▌▌ ▌░░ ░░ ░░▐ ▌░░▐ ▌░░ ░░ ░░▌█ ▌░░ ░░▌ ▐░░▐ - ▐ ▒▒ ▒▒▌▌ ▌▒▒ ▒▒▌ ▐▒▒▐▄▀▄▌▒▒▐ ▌▒▒▌ ▐▒▒ ▒▒▌▌ ▌▒▒ ▒▒▌ ▐▒▒▐ - ▌▄▄ ▓▓ ▓▓▌▌ ▌▓▓ ▓▓▓ ▓▓▓ ▄▓▄ ▓▓ ▀▀ ▓▓▓ ▐▓▓ ▓▓▌▌ ▌▓▓ ▓▓▓ ▐▓▓▐ -░ ▌▀███████▀ ███▐ ▐▐██ ▄▀█████▀▄▄▀█▀▄▀████ ▄▀████▀██ ███▐ ▐▐██ ▄▀████▀██▐ ░ -▒ ▓▓▄▄▄▄▄▄▄▄▀▄▄▄▀ ▀▄▄▀ ▀▄▄▄▄▄▀ ▀▄▀ ▀▄▄▄▄▀ ▀▄▄▄▄▀▄▄▀▄▄▄▀ ▀▄▄▀ ▀▄▄▄▄▀▄▄▓ ▒ -▓ ▓ -█▓▒░ ░▒▓█ \ No newline at end of file diff --git a/contribs/gnodev/cmd/gnobro/banner.go b/contribs/gnodev/cmd/gnobro/banner.go deleted file mode 100644 index 311ee9bdb2a..00000000000 --- a/contribs/gnodev/cmd/gnobro/banner.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "embed" - "path/filepath" - "time" - - "github.com/gnolang/gno/contribs/gnodev/pkg/browser" -) - -//go:embed assets/*.utf8ans -var gnoland_banner embed.FS - -func NewGnoLandBanner() browser.ModelBanner { - const assets = "assets" - - entries, err := gnoland_banner.ReadDir(assets) - if err != nil { - panic("unable to banner dir: " + err.Error()) - } - - frames := make([]string, len(entries)) - for i, entry := range entries { - if entry.IsDir() { - continue - } - - frame, err := gnoland_banner.ReadFile(filepath.Join(assets, entry.Name())) - if err != nil { - panic("unable to read banner frame: " + err.Error()) - } - - frames[i] = string(frame) - } - - return browser.NewModelBanner(time.Second/3, frames) -} diff --git a/contribs/gnodev/cmd/gnobro/main.go b/contribs/gnodev/cmd/gnobro/main.go deleted file mode 100644 index 6bb6bfc2396..00000000000 --- a/contribs/gnodev/cmd/gnobro/main.go +++ /dev/null @@ -1,462 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "log/slog" - "net" - "net/url" - "os" - "os/signal" - "path/filepath" - "strings" - "time" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - charmlog "github.com/charmbracelet/log" - "github.com/charmbracelet/ssh" - "github.com/charmbracelet/wish" - "github.com/charmbracelet/wish/activeterm" - "github.com/charmbracelet/wish/bubbletea" - "github.com/charmbracelet/wish/logging" - "golang.org/x/sync/errgroup" - - "github.com/gnolang/gno/contribs/gnodev/pkg/browser" - "github.com/gnolang/gno/contribs/gnodev/pkg/events" - "github.com/gnolang/gno/gno.land/pkg/gnoclient" - "github.com/gnolang/gno/gno.land/pkg/integration" - "github.com/gnolang/gno/gnovm/pkg/gnoenv" - "github.com/gnolang/gno/tm2/pkg/bft/rpc/client" - "github.com/gnolang/gno/tm2/pkg/commands" - "github.com/gnolang/gno/tm2/pkg/crypto/keys" -) - -const gnoPrefix = "gno.land" - -type broCfg struct { - readonly bool - remote string - dev bool - devRemote string - chainID string - defaultAccount string - defaultRealm string - sshListener string - sshHostKeyPath string - banner bool -} - -var defaultBroOptions = broCfg{ - remote: "127.0.0.1:26657", - dev: true, - devRemote: "", - sshListener: "", - defaultRealm: "gno.land/r/gnoland/home", - chainID: "dev", - sshHostKeyPath: ".ssh/id_ed25519", -} - -func main() { - cfg := &broCfg{} - - stdio := commands.NewDefaultIO() - cmd := commands.NewCommand( - commands.Metadata{ - Name: "gnobro", - ShortUsage: "gnobro [flags] [pkg_path]", - ShortHelp: "Gno Browser, a realm explorer", - LongHelp: `Gnobro is a terminal user interface (TUI) that allows you to browse realms within your -terminal. It automatically connects to Gnodev for real-time development. In -addition to hot reload, it also has the ability to execute commands and interact -with your realm. -`, - }, - cfg, - func(_ context.Context, args []string) error { - return execBrowser(cfg, args, stdio) - }) - - cmd.Execute(context.Background(), os.Args[1:]) -} - -func (c *broCfg) RegisterFlags(fs *flag.FlagSet) { - fs.StringVar( - &c.remote, - "remote", - defaultBroOptions.remote, - "remote gno.land URL", - ) - - fs.StringVar( - &c.chainID, - "chainid", - defaultBroOptions.chainID, - "chainid", - ) - - fs.StringVar( - &c.defaultAccount, - "account", - defaultBroOptions.defaultAccount, - "default local account to use", - ) - - fs.StringVar( - &c.defaultRealm, - "default-realm", - defaultBroOptions.defaultRealm, - "default realm to display when gnobro starts and no argument is provided", - ) - - fs.StringVar( - &c.sshListener, - "ssh", - defaultBroOptions.sshListener, - "ssh server listener address", - ) - - fs.StringVar( - &c.sshHostKeyPath, - "ssh-key", - defaultBroOptions.sshHostKeyPath, - "ssh host key path", - ) - - fs.BoolVar( - &c.dev, - "dev", - defaultBroOptions.dev, - "enable dev mode and connect to gnodev for realtime update", - ) - - fs.StringVar( - &c.devRemote, - "dev-remote", - defaultBroOptions.devRemote, - "dev endpoint, if empty will default to `ws://:8888`", - ) - - fs.BoolVar( - &c.banner, - "banner", - defaultBroOptions.banner, - "if enabled, display a banner", - ) - - fs.BoolVar( - &c.readonly, - "readonly", - defaultBroOptions.readonly, - "readonly mode, no commands allowed", - ) -} - -func execBrowser(cfg *broCfg, args []string, cio commands.IO) error { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - home := gnoenv.HomeDir() - - var address string - var kb keys.Keybase - if cfg.defaultAccount != "" { - address = cfg.defaultAccount - - var err error - kb, err = keys.NewKeyBaseFromDir(home) - if err != nil { - return fmt.Errorf("unable to load keybase: %w", err) - } - } else { - // create a inmemory keybase - kb = keys.NewInMemory() - kb.CreateAccount(integration.DefaultAccount_Name, integration.DefaultAccount_Seed, "", "", 0, 0) - address = integration.DefaultAccount_Name - } - - signer, err := getSignerForAccount(cio, address, kb, cfg) - if err != nil { - return fmt.Errorf("unable to get signer for account %q: %w", address, err) - } - - cl, err := client.NewHTTPClient(cfg.remote) - if err != nil { - return fmt.Errorf("unable to create http client for %q: %w", cfg.remote, err) - } - - gnocl := &gnoclient.Client{ - RPCClient: cl, - Signer: signer, - } - - var path string - switch { - case len(args) > 0: - path = strings.TrimSpace(args[0]) - path = strings.TrimPrefix(path, gnoPrefix) - case cfg.defaultRealm != "": - path = strings.TrimLeft(cfg.defaultRealm, gnoPrefix) - } - - bcfg := browser.DefaultConfig() - bcfg.Readonly = cfg.readonly - bcfg.Renderer = lipgloss.DefaultRenderer() - bcfg.URLDefaultValue = path - bcfg.URLPrefix = gnoPrefix - bcfg.URLPrefix = gnoPrefix - - if cfg.sshListener == "" { - if cfg.banner { - bcfg.Banner = NewGnoLandBanner() - } - - return runLocal(ctx, gnocl, cfg, bcfg, cio) - } - - return runServer(ctx, gnocl, cfg, bcfg, cio) -} - -func runLocal(ctx context.Context, gnocl *gnoclient.Client, cfg *broCfg, bcfg browser.Config, io commands.IO) error { - ctx, cancel := signal.NotifyContext(ctx, os.Interrupt) - defer cancel() - - model := browser.New(bcfg, gnocl) - p := tea.NewProgram(model, - tea.WithContext(ctx), - tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer" - tea.WithMouseCellMotion(), // turn on mouse support so we can track the mouse wheel - ) - - var errgs errgroup.Group - - if cfg.dev { - devpoint, err := getDevEndpoint(cfg) - if err != nil { - return fmt.Errorf("unable to parse dev endpoint: %w", err) - } - - var devcl browser.DevClient - devcl.Handler = func(typ events.Type, data any) error { - switch typ { - case events.EvtReload, events.EvtReset, events.EvtTxResult: - p.Send(browser.RefreshRealm()) - default: - } - - return nil - } - - errgs.Go(func() error { - defer cancel() - - if err := devcl.Run(ctx, devpoint, nil); err != nil { - return fmt.Errorf("dev connection failed: %w", err) - } - - return nil - }) - } - - errgs.Go(func() error { - defer cancel() - - _, err := p.Run() - return err - }) - - if err := errgs.Wait(); err != nil && !errors.Is(err, context.Canceled) { - return err - } - - io.Println("Bye!") - return nil -} - -func runServer(ctx context.Context, gnocl *gnoclient.Client, cfg *broCfg, bcfg browser.Config, io commands.IO) error { - // setup logger - charmlogger := charmlog.New(io.Out()) - charmlogger.SetLevel(charmlog.DebugLevel) - logger := slog.New(charmlogger) - - teaHandler := func(s ssh.Session) (tea.Model, []tea.ProgramOption) { - shortid := fmt.Sprintf("%.10s", s.Context().SessionID()) - - bcfgCopy := bcfg // copy config - - bcfgCopy.Logger = logger.WithGroup(shortid) - bcfgCopy.Renderer = bubbletea.MakeRenderer(s) - - if cfg.banner { - bcfgCopy.Banner = NewGnoLandBanner() - } - - pval := s.Context().Value("path") - if path, ok := pval.(string); ok && len(path) > 0 { - // Erase banner on specifc command - bcfgCopy.Banner = browser.ModelBanner{} - // Set up url - bcfgCopy.URLDefaultValue = path - } - - bcfgCopy.Logger.Info("session started", - "time", time.Now(), - "path", bcfgCopy.URLDefaultValue, - "sid", s.Context().SessionID(), - "user", s.User()) - model := browser.New(bcfgCopy, gnocl) - - return model, []tea.ProgramOption{ - tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer" - tea.WithMouseCellMotion(), // turn on mouse support so we can track the mouse wheel - } - } - - sshaddr, err := net.ResolveTCPAddr("", cfg.sshListener) - if err != nil { - return fmt.Errorf("unable to resolve address: %w", err) - } - - s, err := wish.NewServer( - wish.WithAddress(sshaddr.String()), - wish.WithHostKeyPath(cfg.sshHostKeyPath), - wish.WithMiddleware( - bubbletea.Middleware(teaHandler), - activeterm.Middleware(), // ensure PTY - ValidatePathCommandMiddleware(bcfg.URLPrefix), - logging.StructuredMiddlewareWithLogger( - charmlogger, charmlog.DebugLevel, - ), - // XXX: add ip throttler - ), - ) - - var errgs errgroup.Group - - errgs.Go(func() error { - logger.Info("starting SSH server", "addr", sshaddr.String()) - return s.ListenAndServe() - }) - - ctx, cancel := signal.NotifyContext(ctx, os.Interrupt) - defer cancel() - - errgs.Go(func() error { - <-ctx.Done() - - logger.Info("stopping SSH server... (5s timeout)") - - sctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - return s.Shutdown(sctx) - }) - - if err := errgs.Wait(); err != nil && !errors.Is(err, ssh.ErrServerClosed) { - return err - } - - io.Println("Bye!") - return nil -} - -func getDevEndpoint(cfg *broCfg) (string, error) { - var err error - - // use remote address as default - host, port := cfg.remote, "8888" - if cfg.devRemote != "" { - // if any dev endpoint as been set, fallback on this - host, port, err = net.SplitHostPort(cfg.devRemote) - if err != nil { - return "", fmt.Errorf("unable to parse dev endpoint: %w", err) - } - } - - // ensure having a (any) protocol scheme - if !strings.Contains(host, "://") { - host = "http://" + host - } - - // parse full host including port - devpoint, err := url.Parse(host) - if err != nil { - return "", fmt.Errorf("unable to construct devaddr: %w", err) - } - - host, _, _ = net.SplitHostPort(devpoint.Host) - if port != "" { - devpoint.Host = host + ":" + port - } else { - devpoint.Host = host - } - - switch devpoint.Scheme { - case "ws", "wss": // already good - case "https": - devpoint.Scheme = "wss" - default: - devpoint.Scheme = "ws" - } - devpoint.Path = "_events" - - return devpoint.String(), nil -} - -func getSignerForAccount(io commands.IO, address string, kb keys.Keybase, cfg *broCfg) (gnoclient.Signer, error) { - var signer gnoclient.SignerFromKeybase - - signer.Keybase = kb - signer.Account = address - signer.ChainID = cfg.chainID - - if ok, err := kb.HasByNameOrAddress(address); !ok || err != nil { - if err != nil { - return nil, fmt.Errorf("invalid name: %w", err) - } - - return nil, fmt.Errorf("unknown name/address: %q", address) - } - - // try empty password first - if _, err := kb.ExportPrivKeyUnsafe(address, ""); err != nil { - prompt := fmt.Sprintf("[%.10s] Enter password:", address) - signer.Password, err = io.GetPassword(prompt, true) - if err != nil { - return nil, fmt.Errorf("error while reading password: %w", err) - } - - if _, err := kb.ExportPrivKeyUnsafe(address, signer.Password); err != nil { - return nil, fmt.Errorf("invalid password: %w", err) - } - } - - return signer, nil -} - -func ValidatePathCommandMiddleware(pathPrefix string) wish.Middleware { - return func(next ssh.Handler) ssh.Handler { - return func(s ssh.Session) { - switch cmd := s.Command(); len(cmd) { - case 0: // ok - next(s) - return - case 1: // check for valid path - path := cmd[0] - if strings.HasPrefix(path, pathPrefix) && filepath.Clean(path) == path { - s.Context().SetValue("path", path) - next(s) - return - } - - fmt.Fprintln(s.Stderr(), "provided path is invalid") - default: - fmt.Fprintln(s.Stderr(), "too many arguments") - } - - s.Exit(1) - } - } -} diff --git a/contribs/gnodev/cmd/gnodev/accounts.go b/contribs/gnodev/cmd/gnodev/accounts.go index 95c2c3efffc..b263cc44f70 100644 --- a/contribs/gnodev/cmd/gnodev/accounts.go +++ b/contribs/gnodev/cmd/gnodev/accounts.go @@ -10,7 +10,6 @@ import ( "github.com/gnolang/gno/contribs/gnodev/pkg/address" "github.com/gnolang/gno/contribs/gnodev/pkg/dev" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/rpc/client" "github.com/gnolang/gno/tm2/pkg/std" @@ -51,7 +50,7 @@ func (va varPremineAccounts) String() string { func generateBalances(bk *address.Book, cfg *devCfg) (gnoland.Balances, error) { bls := gnoland.NewBalances() - premineBalance := std.Coins{std.NewCoin(ugnot.Denom, 10e12)} + premineBalance := std.Coins{std.NewCoin("ugnot", 10e12)} entries := bk.List() diff --git a/contribs/gnodev/go.mod b/contribs/gnodev/go.mod index f4859889a16..53973b15fbf 100644 --- a/contribs/gnodev/go.mod +++ b/contribs/gnodev/go.mod @@ -2,54 +2,32 @@ module github.com/gnolang/gno/contribs/gnodev go 1.22 +toolchain go1.22.4 + replace github.com/gnolang/gno => ../.. require ( - github.com/charmbracelet/bubbles v0.18.0 - github.com/charmbracelet/bubbletea v0.26.6 - github.com/charmbracelet/glamour v0.7.0 - github.com/charmbracelet/lipgloss v0.11.0 - github.com/charmbracelet/log v0.4.0 - github.com/charmbracelet/ssh v0.0.0-20240604154955-a40c6a0d028f - github.com/charmbracelet/wish v1.4.0 + github.com/charmbracelet/lipgloss v0.9.1 + github.com/charmbracelet/log v0.3.1 github.com/fsnotify/fsnotify v1.7.0 github.com/gnolang/gno v0.0.0-00010101000000-000000000000 github.com/gorilla/websocket v1.5.3 - github.com/lrstanley/bubblezone v0.0.0-20240624011428-67235275f80c - github.com/muesli/reflow v0.3.0 github.com/muesli/termenv v0.15.2 - github.com/sahilm/fuzzy v0.1.1 github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 - golang.org/x/sync v0.8.0 - golang.org/x/term v0.23.0 + golang.org/x/term v0.22.0 ) require ( - dario.cat/mergo v1.0.1 // indirect - github.com/alecthomas/chroma/v2 v2.8.0 // indirect - github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect - github.com/atotto/clipboard v0.1.4 // indirect + dario.cat/mergo v1.0.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/aymerick/douceur v0.2.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect - github.com/btcsuite/btcd/btcutil v1.1.6 // indirect + github.com/btcsuite/btcd/btcutil v1.1.5 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/charmbracelet/keygen v0.5.0 // indirect - github.com/charmbracelet/x/ansi v0.1.2 // indirect - github.com/charmbracelet/x/conpty v0.1.0 // indirect - github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 // indirect - github.com/charmbracelet/x/input v0.1.2 // indirect - github.com/charmbracelet/x/term v0.1.1 // indirect - github.com/charmbracelet/x/termios v0.1.0 // indirect - github.com/charmbracelet/x/windows v0.1.2 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect - github.com/creack/pty v1.1.21 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect - github.com/dlclark/regexp2 v1.4.0 // indirect - github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -57,55 +35,47 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect github.com/gotuna/gotuna v0.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/microcosm-cc/bluemonday v1.0.25 // indirect - github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect - github.com/muesli/cancelreader v0.2.2 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/muesli/reflow v0.3.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/peterbourgon/ff/v3 v3.4.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/rs/cors v1.11.1 // indirect - github.com/rs/xid v1.6.0 // indirect + github.com/rs/cors v1.11.0 // indirect + github.com/rs/xid v1.5.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - github.com/yuin/goldmark v1.5.4 // indirect - github.com/yuin/goldmark-emoji v1.0.2 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect - go.etcd.io/bbolt v1.3.11 // indirect - go.opentelemetry.io/otel v1.29.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/sdk v1.29.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect + go.etcd.io/bbolt v1.3.10 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap/exp v0.2.0 // indirect - golang.org/x/crypto v0.26.0 // indirect + golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect - golang.org/x/mod v0.20.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - golang.org/x/tools v0.24.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.23.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/contribs/gnodev/go.sum b/contribs/gnodev/go.sum index af57f320257..2b5c964a014 100644 --- a/contribs/gnodev/go.sum +++ b/contribs/gnodev/go.sum @@ -1,34 +1,20 @@ -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink= -github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= -github.com/alecthomas/chroma/v2 v2.8.0 h1:w9WJUjFFmHHB2e8mRpL9jjy3alYDlU0QLDezj1xE264= -github.com/alecthomas/chroma/v2 v2.8.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw= -github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= -github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= -github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= -github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7Nzl7WHaOTlTr5hIrR4n1NM4v9n4Kw= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= -github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= -github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= -github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= -github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= @@ -44,42 +30,14 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= -github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= -github.com/charmbracelet/bubbletea v0.26.6 h1:zTCWSuST+3yZYZnVSvbXwKOPRSNZceVeqpzOLN2zq1s= -github.com/charmbracelet/bubbletea v0.26.6/go.mod h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk= -github.com/charmbracelet/glamour v0.7.0 h1:2BtKGZ4iVJCDfMF229EzbeR1QRKLWztO9dMtjmqZSng= -github.com/charmbracelet/glamour v0.7.0/go.mod h1:jUMh5MeihljJPQbJ/wf4ldw2+yBP59+ctV36jASy7ps= -github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc= -github.com/charmbracelet/keygen v0.5.0/go.mod h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8= -github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g= -github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8= -github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM= -github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM= -github.com/charmbracelet/ssh v0.0.0-20240604154955-a40c6a0d028f h1:DnNHMcvpjh51pFVuYCxf+pVNdfZ3w51gGAtDiuVmFEk= -github.com/charmbracelet/ssh v0.0.0-20240604154955-a40c6a0d028f/go.mod h1:LmMZag2g7ILMmWtDmU7dIlctUopwmb73KpPzj0ip1uk= -github.com/charmbracelet/wish v1.4.0 h1:pL1uVP/YuYgJheHEj98teZ/n6pMYnmlZq/fcHvomrfc= -github.com/charmbracelet/wish v1.4.0/go.mod h1:ew4/MjJVfW/akEO9KmrQHQv1F7bQRGscRMrA+KtovTk= -github.com/charmbracelet/x/ansi v0.1.2 h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY= -github.com/charmbracelet/x/ansi v0.1.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= -github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= -github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA= -github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= -github.com/charmbracelet/x/input v0.1.2 h1:QJAZr33eOhDowkkEQ24rsJy4Llxlm+fRDf/cQrmqJa0= -github.com/charmbracelet/x/input v0.1.2/go.mod h1:LGBim0maUY4Pitjn/4fHnuXb4KirU3DODsyuHuXdOyA= -github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= -github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= -github.com/charmbracelet/x/termios v0.1.0 h1:y4rjAHeFksBAfGbkRDmVinMg7x7DELIGAFbdNvxg97k= -github.com/charmbracelet/x/termios v0.1.0/go.mod h1:H/EVv/KRnrYjz+fCYa9bsKdqF3S8ouDK0AZEbG7r+/U= -github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg= -github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= +github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= +github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw= +github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= -github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= -github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -91,10 +49,6 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeC github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= -github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -131,8 +85,6 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= -github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= @@ -145,10 +97,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotuna/gotuna v0.6.0 h1:N1lQKXEi/lwRp8u3sccTYLhzOffA4QasExz/1M5Riws= github.com/gotuna/gotuna v0.6.0/go.mod h1:F/ecRt29ChB6Ycy1AFIBpBiMNK0j7Heq+gFbLWquhjc= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= -github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -158,30 +108,17 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/lrstanley/bubblezone v0.0.0-20240624011428-67235275f80c h1:hu82xYs8yOIM1TSq+L5VIZeRsHVROpe3gL0qscUlXJA= -github.com/lrstanley/bubblezone v0.0.0-20240624011428-67235275f80c/go.mod h1:fMHACHXouhQO+NLAFvHEeKdVSzG7L/O1khqsvswCTmk= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= -github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= @@ -189,8 +126,6 @@ github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1n github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -215,50 +150,36 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= -github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= -github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= -github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU= -github.com/yuin/goldmark v1.5.4/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s= -github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= -go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= -go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 h1:k6fQVDQexDE+3jG2SfCQjnHS7OamcP73YMoxEVq5B6k= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0/go.mod h1:t4BrYLHU450Zo9fnydWlIuswB1bm7rM8havDpWOJeDo= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 h1:xvhQxJ/C9+RTnAj5DpTg7LSM1vbbMTiXt7e9hsfqHNw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0/go.mod h1:Fcvs2Bz1jkDM+Wf5/ozBGmi3tQ/c9zPKLnsipnfhGAo= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/sdk/metric v1.29.0 h1:K2CfmJohnRgvZ9UAj2/FhIf/okdWcNdBwe1m8xFXiSY= -go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLmmtjRke7LPDQ3lvpFz+kNEH43faFhzW7v8BFIEydg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0/go.mod h1:TC1pyCt6G9Sjb4bQpShH+P5R53pO6ZuGnHuuln9xMeE= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08= +go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -272,22 +193,22 @@ go.uber.org/zap/exp v0.2.0/go.mod h1:t0gqAIdh1MfKv9EwN/dLwfZnJxe9ITAZN78HEWPFWDQ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -297,27 +218,26 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/contribs/gnodev/pkg/browser/client_dev.go b/contribs/gnodev/pkg/browser/client_dev.go deleted file mode 100644 index 3d63b3abba7..00000000000 --- a/contribs/gnodev/pkg/browser/client_dev.go +++ /dev/null @@ -1,113 +0,0 @@ -package browser - -import ( - "context" - "errors" - "fmt" - "log/slog" - "net/http" - "time" - - "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" - "github.com/gnolang/gno/contribs/gnodev/pkg/events" - "github.com/gnolang/gno/tm2/pkg/log" - "github.com/gorilla/websocket" -) - -const MaxBackoff = time.Second * 20 - -var ErrHandlerNotSet = errors.New("handler not set") - -type DevClient struct { - Logger *slog.Logger - Handler func(typ events.Type, data any) error - - conn *websocket.Conn -} - -func (c *DevClient) Run(ctx context.Context, addr string, header http.Header) error { - if c.Handler == nil { - return ErrHandlerNotSet - } - - if c.Logger == nil { - c.Logger = log.NewNoopLogger() - } - - for ctx.Err() == nil { - if err := c.dialBackoff(ctx, addr, nil); err != nil { - return err - } - - c.Logger.Info("connected to server", "addr", addr) - - err := c.handleEvents(ctx) - if err == nil { - return nil - } - - var closeError *websocket.CloseError - if errors.As(err, &closeError) { - c.Logger.Error("connection has been closed, reconnecting...", "err", closeError) - continue - } - - return fmt.Errorf("unexpected error: %w", err) - } - - return context.Cause(ctx) -} - -func (c *DevClient) dialBackoff(ctx context.Context, addr string, header http.Header) error { - dialer := websocket.DefaultDialer - backoff := time.Second - for { - var err error - - c.Logger.Debug("connecting to dev events endpoint", addr, "addr") - c.conn, _, err = dialer.DialContext(ctx, addr, header) - - if ctx.Err() != nil { - return context.Cause(ctx) - } - - if err == nil { - return nil - } - - switch { - case backoff > MaxBackoff: - backoff = MaxBackoff - case backoff < MaxBackoff: - backoff *= 2 - default: - } - - c.Logger.Info("could not connect to server", "err", err, "next_attempt", backoff) - select { - case <-ctx.Done(): - return context.Cause(ctx) - case <-time.After(backoff): - } - } -} - -func (c *DevClient) handleEvents(ctx context.Context) error { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - go func() { - <-ctx.Done() - c.conn.Close() - }() - - for { - var evt emitter.EventJSON - if err := c.conn.ReadJSON(&evt); err != nil { - return fmt.Errorf("unable to read json event: %w", err) - } - - if err := c.Handler(evt.Type, evt.Data); err != nil { - return fmt.Errorf("unable to handle event: %w", err) - } - } -} diff --git a/contribs/gnodev/pkg/browser/client_node.go b/contribs/gnodev/pkg/browser/client_node.go deleted file mode 100644 index 2ffa26aa08f..00000000000 --- a/contribs/gnodev/pkg/browser/client_node.go +++ /dev/null @@ -1,124 +0,0 @@ -package browser - -import ( - "errors" - "fmt" - "log/slog" - "regexp" - "strings" - - "github.com/gnolang/gno/gno.land/pkg/gnoclient" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" - "github.com/gnolang/gno/tm2/pkg/amino" -) - -var ( - ErrInternalError = errors.New("internal error") - ErrRenderNotFound = errors.New("render not found") -) - -type NodeClient struct { - base gnoclient.BaseTxCfg - client *gnoclient.Client - logger *slog.Logger -} - -func NewNodeClient(logger *slog.Logger, base gnoclient.BaseTxCfg, client *gnoclient.Client) *NodeClient { - return &NodeClient{ - base: base, - client: client, - logger: logger, - } -} - -func (ncl *NodeClient) Call(path, call string) ([]byte, error) { - method, args, err := parseMethodToArgs(call) - if err != nil { - return nil, fmt.Errorf("unable to parse method/args: %w", err) - } - - if len(args) == 0 { - args = nil - } - - infos, err := ncl.client.Signer.Info() - if err != nil { - return nil, fmt.Errorf("unable to get signer infos: %w", err) - } - - cm, err := ncl.client.Call(ncl.base, vm.MsgCall{ - Caller: infos.GetAddress(), - PkgPath: path, - Func: method, - Args: args, - }) - if err != nil { - return nil, err - } - - if cm.CheckTx.Error != nil { - return nil, fmt.Errorf("check error: %w", err) - } - - if cm.DeliverTx.Error != nil { - return nil, fmt.Errorf("delivry error: %w", err) - } - - return cm.DeliverTx.Data, nil -} - -func (ncl *NodeClient) Funcs(path string) (vm.FunctionSignatures, error) { - res, err := ncl.client.Query(gnoclient.QueryCfg{ - Path: "vm/qfuncs", - Data: []byte(path), - }) - if err != nil { - return nil, err - } - - if err := res.Response.Error; err != nil { - return nil, err - } - - var fsigs vm.FunctionSignatures - if err := amino.UnmarshalJSON(res.Response.Data, &fsigs); err != nil { - return nil, fmt.Errorf("unable to unmarshal response: %w", err) - } - - return fsigs, nil -} - -func (ncl *NodeClient) Render(path, args string) ([]byte, error) { - data, res, err := ncl.client.Render(path, args) - if err != nil { - return nil, err - } - if err := res.Response.Error; err != nil { - return nil, err - } - - return []byte(data), nil -} - -var reMethod = regexp.MustCompile(`([^(]+)\(([^)]*)\)`) - -func parseMethodToArgs(call string) (method string, args []string, err error) { - matches := reMethod.FindStringSubmatch(call) - if len(matches) == 0 { - return "", nil, fmt.Errorf("invalid call: %w", err) - } - - method = matches[1] - sargs := matches[2] - if sargs == "" { - return method, args, err - } - - // Splitting arguments by comma - args = strings.Split(sargs, ",") - for i, arg := range args { - args[i] = strings.Trim(strings.TrimSpace(arg), "\"") - } - - return method, args, err -} diff --git a/contribs/gnodev/pkg/browser/list_model.go b/contribs/gnodev/pkg/browser/list_model.go deleted file mode 100644 index db4656fbf24..00000000000 --- a/contribs/gnodev/pkg/browser/list_model.go +++ /dev/null @@ -1,154 +0,0 @@ -package browser - -import ( - "fmt" - "io" - "sort" - "strings" - - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" - "github.com/sahilm/fuzzy" -) - -var ( - listItemStyle = lipgloss.NewStyle().PaddingLeft(4) - listSelectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) - listPaginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) -) - -type FuncListModel struct { - list.Model - items []list.Item -} - -func (m *FuncListModel) SetItems(items []list.Item) { - m.Model.SetItems(items) - m.items = items -} - -func (m FuncListModel) Update(msg tea.Msg) (FuncListModel, tea.Cmd) { - var cmd tea.Cmd - m.Model, cmd = m.Model.Update(msg) - return m, cmd -} - -func (m *FuncListModel) OriginItems() []list.Item { - return m.items -} - -func (m *FuncListModel) Erase() { - m.Model.SetItems([]list.Item{}) -} - -func (m *FuncListModel) Reset() { - m.Model.SetItems(m.items) -} - -func (m *FuncListModel) FilterItems(pattern string) { - if pattern == "" { - m.Reset() - return - } - - i := strings.IndexRune(pattern, '(') - if i > 0 { - pattern = pattern[:i] - } - - data := make([]string, len(m.items)) - for i, item := range m.items { - data[i] = item.FilterValue() - } - - ranks := fuzzy.Find(pattern, data) - sort.Stable(ranks) - if len(ranks) > 0 && i > 0 { - m.Model.SetItems([]list.Item{m.items[ranks[0].Index]}) - return - } - - items := make([]list.Item, len(ranks)) - for i, r := range ranks { - items[i] = m.items[r.Index] - } - - m.Model.SetItems(items) -} - -type itemFunc vm.FunctionSignature - -func (i itemFunc) Name() string { return i.FuncName } -func (i itemFunc) Title() string { return i.Name() } -func (i itemFunc) Description() string { return i.FuncName } -func (i itemFunc) FilterValue() string { return i.FuncName } - -type itemFuncsDelegate struct{} - -func (d itemFuncsDelegate) Height() int { return 1 } -func (d itemFuncsDelegate) Spacing() int { return 0 } -func (d itemFuncsDelegate) Update(_ tea.Msg, _ *list.Model) tea.Cmd { return nil } -func (d itemFuncsDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { - fun, ok := listItem.(itemFunc) - if !ok { - return - } - - maxw := m.Width() - 10 - - var proto strings.Builder - fmt.Fprintf(&proto, "%s(", fun.FuncName) - for j, param := range fun.Params { - if j != 0 { - fmt.Fprint(&proto, ", ") - } - - fmt.Fprintf(&proto, "%s %s", param.Name, param.Type) - } - fmt.Fprint(&proto, ")") - - switch len(fun.Results) { - case 0: // none - case 1: - fmt.Fprintf(&proto, " %s", fun.Results[0].Type) - default: - fmt.Fprint(&proto, " (") - for j, res := range fun.Results { - if j != 0 { - fmt.Fprint(&proto, ", ") - } - - fmt.Fprint(&proto, res.Type) - } - fmt.Fprint(&proto, ")") - } - - fn := listItemStyle.Render - if index == m.Index() { - fn = func(s ...string) string { - return listSelectedItemStyle.Render("> " + strings.Join(s, " ")) - } - } - - str := proto.String() - if len(str) > maxw { - str = str[:maxw-3] + "..." - } - - fmt.Fprint(w, fn(str)) -} - -func newFuncList() FuncListModel { - l := list.New([]list.Item{}, &itemFuncsDelegate{}, 0, 0) - l.SetShowStatusBar(false) - l.SetFilteringEnabled(true) - l.SetShowHelp(false) - l.SetShowPagination(false) - l.Styles.PaginationStyle = listPaginationStyle - return FuncListModel{ - Model: l, - items: l.Items(), - } -} diff --git a/contribs/gnodev/pkg/browser/model.go b/contribs/gnodev/pkg/browser/model.go deleted file mode 100644 index bdd7eac9c82..00000000000 --- a/contribs/gnodev/pkg/browser/model.go +++ /dev/null @@ -1,580 +0,0 @@ -package browser - -import ( - "bytes" - clist "container/list" - "errors" - "fmt" - "log/slog" - "path/filepath" - "regexp" - "strings" - - "github.com/charmbracelet/bubbles/list" - "github.com/charmbracelet/bubbles/textinput" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - zone "github.com/lrstanley/bubblezone" - "github.com/muesli/reflow/wordwrap" - - "github.com/gnolang/gno/gno.land/pkg/gnoclient" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" - "github.com/gnolang/gno/tm2/pkg/log" -) - -var promptStyle = func(r *lipgloss.Renderer) lipgloss.Style { - return r.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#dd7878")) -} - -var ErrEmptyRenderer = errors.New("empty rendrer") - -type Config struct { - URLPrefix string - URLDefaultValue string - Logger *slog.Logger - Renderer *lipgloss.Renderer - Readonly bool - Banner ModelBanner -} - -const DefaultGnoLandPrefix = "gno.land/" - -func DefaultConfig() Config { - return Config{ - Logger: log.NewNoopLogger(), - URLPrefix: DefaultGnoLandPrefix, - Renderer: lipgloss.DefaultRenderer(), - URLDefaultValue: "gnoland/home", - } -} - -type model struct { - render *lipgloss.Renderer - client *NodeClient - logger *slog.Logger - - // misc - banner ModelBanner - bannerDiscarded bool - - // Viewport - zone *zone.Manager - ready bool - viewport viewport.Model - height, width int - readonly bool - messageDisplay bool - - // Nav - taskLoader LoaderModel - - pageurls map[string]string - history *clist.List - current *clist.Element - - // Url - urlInput textinput.Model - urlPrefix string - - // Commands - listFuncs FuncListModel - commandInput textinput.Model - commandFocus bool -} - -func initURLInput(prefix string, r *lipgloss.Renderer) textinput.Model { - ti := textinput.New() - ti.Placeholder = "r/gnoland/blog" // XXX: Use as example, customize this ? - ti.Focus() - ti.CharLimit = 156 - ti.PromptStyle = promptStyle(r) - ti.Prompt = prefix + "/" - - return ti -} - -func initCommandInput(r *lipgloss.Renderer) textinput.Model { - ti := textinput.New() - ti.Placeholder = "" - ti.CharLimit = 156 - ti.PromptStyle = promptStyle(r) - ti.Prompt = "> " - - return ti -} - -func New(cfg Config, client *gnoclient.Client) tea.Model { - renderer := lipgloss.DefaultRenderer() - if cfg.Renderer != nil { - renderer = cfg.Renderer - } - - // Setup url input - urlinput := initURLInput(cfg.URLPrefix, renderer) - - path := cleanupRealmPath(cfg.URLPrefix, cfg.URLDefaultValue) - urlinput.SetValue(path) - - // Setup cmd input - cmdinput := initCommandInput(renderer) - - // XXX: Customize this - base := gnoclient.BaseTxCfg{ - GasFee: "1000000ugnot", - GasWanted: 2000000, - } - - nodeclient := NewNodeClient(cfg.Logger, base, client) - return &model{ - logger: cfg.Logger, - render: cfg.Renderer, - readonly: cfg.Readonly, - client: nodeclient, - taskLoader: newLoaderModel(), - - banner: cfg.Banner, - bannerDiscarded: cfg.Banner.Empty(), - - urlInput: urlinput, - urlPrefix: cfg.URLPrefix, - - commandInput: cmdinput, - listFuncs: newFuncList(), - - zone: zone.New(), - pageurls: map[string]string{}, - history: clist.New(), - } -} - -func (m model) Init() tea.Cmd { - m.history.Init() - return m.banner.Init() -} - -type fetchRealmMsg struct { - realmPath string -} - -func FetchRealm(path string) tea.Cmd { - return func() tea.Msg { return fetchRealmMsg{path} } -} - -func RefreshRealm() tea.Cmd { - return func() tea.Msg { return fetchRealmMsg{""} } -} - -type renderUpdateMsg struct { - Render []byte - Funcs vm.FunctionSignatures - Error error -} - -func (m *model) RenderUpdate(path string) tea.Cmd { - return func() tea.Msg { - var msg renderUpdateMsg - var err error - msg.Render, err = m.fetchRenderView(path) - if err != nil { - msg.Error = fmt.Errorf("unable to fetch view: %w", err) - return msg - } - - msg.Funcs, err = m.fetchFuncsList(path) - if err != nil { - msg.Error = fmt.Errorf("unable to fetch function list: %w", err) - return msg - } - - return msg - } -} - -type execCommandRequestMsg struct { - Path string - Command string -} - -func (m *model) ExecCommandRequest(path, command string) tea.Cmd { - return func() tea.Msg { - return execCommandRequestMsg{path, command} - } -} - -type execCommandMsg struct { - Response []byte - Error error -} - -func (m *model) ExecCommand(path, command string) tea.Cmd { - return func() tea.Msg { - res, err := m.client.Call(path, command) - return execCommandMsg{res, err} - } -} - -func (m *model) ExtendCommandInput() bool { - if !m.commandInput.Focused() { - return false - } - - if item, ok := m.listFuncs.SelectedItem().(itemFunc); ok { - var value string - if len(item.Params) > 0 { - value = item.Title() + "(" - } else { - value = item.Title() + "()" - } - - currentValue := m.commandInput.Value() - if len(value) > len(currentValue) && strings.HasPrefix(value, currentValue) { - m.commandInput.SetValue(value) - return true - } - - // Put cursor at the end - m.commandInput.CursorEnd() - } - - return false -} - -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - var cmd tea.Cmd - - switch msg := msg.(type) { - case fetchRealmMsg: - if msg.realmPath != "" { - return m, tea.Sequence(m.taskLoader.Add(1), m.moveToRealm(msg.realmPath)) - } - - // If no realm path is given simply refresh the current realm - path := m.getCurrentPath() - m.logger.Info("rendering realm", "path", path) - - return m, tea.Sequence(m.taskLoader.Add(1), m.RenderUpdate(path)) - - case execCommandRequestMsg: - m.logger.Info("requesting command", "path", msg.Path, "cmd", msg.Command) - cmd = m.ExecCommand(msg.Path, msg.Command) - return m, tea.Sequence(m.taskLoader.Add(1), cmd) - - case execCommandMsg: - m.taskLoader.Done() - - // If any error, display it as message. - if msg.Error != nil { - m.logger.Warn("command exec", "error", msg.Error) - - content := wordwrap.NewWriter(m.viewport.Width) - fmt.Fprint(content, msg.Error.Error()) - fmt.Fprintf(content, "\n\npress [enter] to dismiss error\n") - m.viewport.SetContent(content.String()) - m.messageDisplay = true - return m, nil - } - - // If any response, display it as message. - if res := bytes.TrimSpace(msg.Response); len(res) > 0 { - m.logger.Info("command exec", "res", string(res)) - - content := wordwrap.NewWriter(m.viewport.Width) - content.Write(res) - fmt.Fprintf(content, "\n\npress [enter] to dismiss message\n") - m.viewport.SetContent(content.String()) - m.messageDisplay = true - return m, nil - } - - // If no error or empty response is returned, simply refresh the page. - m.messageDisplay = false - return m, RefreshRealm() - - case renderUpdateMsg: - m.taskLoader.Done() - - var content string - if err := msg.Error; err != nil { - m.logger.Warn("render", "error", msg.Error) - // Write error to the frame - content = fmt.Sprintf("ERROR: %s", err.Error()) - } else { - content = string(m.findAndMarkURLs(msg.Render)) - } - - if len(msg.Funcs) > 0 { - items := make([]list.Item, 0, len(msg.Funcs)) - for _, fun := range msg.Funcs { - if fun.FuncName != "Render" { - items = append(items, itemFunc(fun)) - } - } - m.listFuncs.SetItems(items) - m.listFuncs.FilterItems(m.commandInput.Value()) - - // Update funcs list - m.listFuncs.Title = m.urlInput.Value() - m.listFuncs.SetSize(m.viewport.Width, 7) - } - - m.viewport.SetContent(content) - return m, cmd - - case SpinnerTickMsg: - if m.taskLoader.Active() { - m.taskLoader, cmd = m.taskLoader.Update(msg) - } - - case tea.MouseMsg: - cmd = m.updateMouse(msg) - - // Fallback on viewport - if cmd == nil { - m.viewport, cmd = m.viewport.Update(msg) - } - - return m, cmd - - case tea.KeyMsg: - cmd = m.updateKey(msg) - m.listFuncs.FilterItems(m.commandInput.Value()) - if !m.readonly && cmd == nil { - m.listFuncs, cmd = m.listFuncs.Update(msg) - } - - // Fallback on list funcs update - if cmd == nil { - m.viewport, cmd = m.viewport.Update(msg) - } - - // Fallback on viewport update - return m, cmd - - case tea.WindowSizeMsg: - m.width = msg.Width - - headerHeight := lipgloss.Height(m.headerView()) - footerHeight := lipgloss.Height(m.footerView()) - verticalMarginHeight := headerHeight + footerHeight - - if !m.ready { - m.viewport = viewport.New(msg.Width, msg.Height-verticalMarginHeight) - m.viewport.YPosition = headerHeight - m.viewport.MouseWheelEnabled = true - m.viewport.MouseWheelDelta = 1 - m.ready = true - m.viewport.YPosition = headerHeight + 1 - - if value := m.urlInput.Value(); value != "" { - cmd = RefreshRealm() - m.updateHistory() - } - } else { - m.viewport.Width = msg.Width - m.viewport.Height = msg.Height - verticalMarginHeight - } - - m.height = m.viewport.Height - if !m.urlInput.Focused() && len(m.listFuncs.Items()) > 0 { - m.viewport.Height = m.height - lipgloss.Height(m.listFuncsView()) - } - - return m, cmd - } - - // Update other models - cmds := []tea.Cmd{cmd} - - if !m.bannerDiscarded { - var bannerCmd tea.Cmd - m.banner, bannerCmd = m.banner.Update(msg) - cmds = append(cmds, bannerCmd) - } - - var viewCmd tea.Cmd - m.viewport, viewCmd = m.viewport.Update(msg) - cmds = append(cmds, viewCmd) - - var funcCmd tea.Cmd - m.listFuncs, funcCmd = m.listFuncs.Update(msg) - cmds = append(cmds, funcCmd) - - return m, tea.Batch(cmds...) -} - -func (m *model) updateKey(msg tea.KeyMsg) tea.Cmd { - var cmd tea.Cmd - if !m.bannerDiscarded { - switch key := msg.String(); key { - case "ctrl+c": - return tea.Quit - case "enter": - m.bannerDiscarded = true - } - // Discard other input while banner is active - return nil - } - - switch msg.String() { - case "alt+down": - if m.urlInput.Focused() && !m.readonly { - m.urlInput.Blur() - cmd = m.commandInput.Focus() - m.commandFocus = true - } - case "alt+up": - if m.commandInput.Focused() { - m.commandInput.Blur() - cmd = m.urlInput.Focus() - m.commandFocus = false - } - case "tab": - if m.commandInput.Focused() { - m.ExtendCommandInput() - } - case "alt+r": - cmd = RefreshRealm() - case "enter": - // Update command on focus - if m.commandInput.Focused() && !m.messageDisplay { - if len(m.listFuncs.Items()) == 1 { - path := m.getCurrentPath() - cmd = m.ExecCommand(path, m.commandInput.Value()) - } else { - m.ExtendCommandInput() - } - - break - } - - // Update url on focus - if m.messageDisplay || m.urlInput.Focused() { - m.listFuncs.Erase() - - cmd = m.moveToRealm(m.urlInput.Value()) - if m.current.Value.(string) != m.urlInput.Value() { - m.updateHistory() - } - - // Discard message - m.messageDisplay = false - } - - case "ctrl+c", "esc": - return tea.Quit - default: - // handle url input - if m.urlInput.Focused() { - m.urlInput, cmd = m.urlInput.Update(msg) - } - - if m.commandInput.Focused() { - // handle command input - m.commandInput, cmd = m.commandInput.Update(msg) - } - } - - return cmd -} - -func (m *model) updateMouse(msg tea.MouseMsg) tea.Cmd { - if msg.Action != tea.MouseActionRelease { - return nil - } - - var cmd tea.Cmd - - switch { - case m.zone.Get("prev_button").InBounds(msg): - if path, ok := m.moveHistoryBackward(); ok { - cmd = m.moveToRealm(path) - } - case m.zone.Get("next_button").InBounds(msg): - if path, ok := m.moveHistoryForward(); ok { - cmd = m.moveToRealm(path) - } - case m.zone.Get("home_button").InBounds(msg): - if cmd = m.moveToRealm("gno.land/r/gnoland/home"); cmd != nil { - m.updateHistory() - } - - case m.zone.Get("url_input").InBounds(msg): - m.commandInput.Blur() - cmd = m.urlInput.Focus() - m.commandFocus = false - case !m.readonly && m.zone.Get("command_input").InBounds(msg): - m.urlInput.Blur() - cmd = m.commandInput.Focus() - m.commandFocus = true - default: - for mark := range m.pageurls { - if !m.zone.Get(mark).InBounds(msg) { - continue - } - - if uri := m.pageurls[mark]; uri != "" { - if cmd = m.moveToRealm(uri); cmd != nil { - m.updateHistory() - break - } - } - } - } - - return cmd -} - -// realm path surrounded by ansi escape sequences -var reUrlPattern = regexp.MustCompile(`(?mU)\x1b[^m]*m(?:(?:https?://)?gno.land)?(/[^\s]+)\x1b[^m]*m`) - -func (m model) findAndMarkURLs(body []byte) []byte { - var buf bytes.Buffer - lastIndex := 0 - - indexes := reUrlPattern.FindAllSubmatchIndex(body, -1) - for i, loc := range indexes { - match := string(body[loc[0]:loc[1]]) - uri := string(body[loc[2]:loc[3]]) - markid := fmt.Sprintf("url_%d", i) - - // Write bytes before match - buf.Write(body[lastIndex:loc[0]]) - - // Write quoted URL - buf.WriteString(m.zone.Mark(markid, match)) - m.pageurls[markid] = uri - lastIndex = loc[1] - } - // Write remaining bytes - buf.Write(body[lastIndex:]) - - // Cleanup previous urls - for i := len(indexes); i < len(m.pageurls); i++ { - markid := fmt.Sprintf("url_%d", i) - delete(m.pageurls, markid) - } - - return buf.Bytes() -} - -func (m model) fetchFuncsList(path string) (view vm.FunctionSignatures, err error) { - rlmpath, _, _ := strings.Cut(path, ":") - funcs, err := m.client.Funcs(rlmpath) - if err != nil { - return nil, fmt.Errorf("unable to fetch Render: %w", err) - } - - return funcs, nil -} - -func (m *model) getCurrentPath() string { - path := strings.Trim(m.urlInput.Value(), "/") - if len(path) == 0 { - return m.urlPrefix - } - - return filepath.Join(m.urlPrefix, path) -} diff --git a/contribs/gnodev/pkg/browser/model_banner.go b/contribs/gnodev/pkg/browser/model_banner.go deleted file mode 100644 index ac983951dab..00000000000 --- a/contribs/gnodev/pkg/browser/model_banner.go +++ /dev/null @@ -1,99 +0,0 @@ -package browser - -import ( - "strings" - "time" - - tea "github.com/charmbracelet/bubbletea" -) - -type ModelBanner struct { - Banner string - - offset int - frameIndex int - frames [][]string - - fps time.Duration -} - -func NewModelBanner(fps time.Duration, frames []string) ModelBanner { - splited := make([][]string, len(frames)) - for i, frame := range frames { - lines := strings.Split(frame, "\n") - for j, line := range lines { - lines[j] = line + "\033[0m" - } - splited[i] = lines - } - - return ModelBanner{ - frames: splited, - fps: fps, - } -} - -func (m ModelBanner) Empty() bool { - return m.frames == nil -} - -type ( - tickBannerMsg struct{} - tickBannerOffsetMsg struct{} -) - -func (m ModelBanner) tick() tea.Cmd { - return tea.Tick(m.fps, func(_ time.Time) tea.Msg { - return tickBannerMsg{} - }) -} - -func (m ModelBanner) tickOffset() tea.Cmd { - return tea.Tick(time.Second/10, func(_ time.Time) tea.Msg { - return tickBannerOffsetMsg{} - }) -} - -func (m ModelBanner) Init() tea.Cmd { - if m.Empty() { - return nil - } - - return tea.Batch(m.tickOffset(), m.tick()) -} - -func (m ModelBanner) Update(msg tea.Msg) (ModelBanner, tea.Cmd) { - var cmd tea.Cmd - switch msg.(type) { - case tickBannerOffsetMsg: - frame := m.frames[m.frameIndex] - m.Banner = getFrameLinesOffset(frame, m.offset) - if m.offset < (len(frame) / 2) { - m.offset++ - cmd = m.tickOffset() - } - - case tickBannerMsg: - frame := m.frames[m.frameIndex] - m.Banner = getFrameLinesOffset(frame, m.offset) - m.frameIndex = (m.frameIndex + 1) % len(m.frames) // move to next frame - cmd = m.tick() - // XXX: handle window size - } - return m, cmd -} - -func (m ModelBanner) View() string { - return m.Banner -} - -func getFrameLinesOffset(lines []string, offset int) string { - middle := len(lines) / 2 - if offset < middle { - start := middle - min(middle, offset) - end := middle + min(middle, offset) - lines = lines[start:end] - } - - return strings.Join(lines, "\n") -} diff --git a/contribs/gnodev/pkg/browser/model_nav.go b/contribs/gnodev/pkg/browser/model_nav.go deleted file mode 100644 index 6936f413d94..00000000000 --- a/contribs/gnodev/pkg/browser/model_nav.go +++ /dev/null @@ -1,73 +0,0 @@ -package browser - -import ( - "fmt" - "strings" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/glamour" -) - -func (m *model) moveToRealm(realm string) tea.Cmd { - path := cleanupRealmPath(m.urlPrefix, realm) - - // Set uri input - m.urlInput.SetValue(path) - m.urlInput.CursorEnd() - - // return command update - return tea.Sequence(RefreshRealm(), m.urlInput.Focus()) -} - -func (m *model) updateHistory() { - v := m.urlInput.Value() - if m.history.Len() == 0 { - m.current = m.history.PushBack(v) - return - } - - m.current = m.history.InsertAfter(v, m.current) - for next := m.current.Next(); next != nil; { - m.history.Remove(next) - next = m.current.Next() - } -} - -func (m *model) moveHistoryForward() (string, bool) { - if next := m.current.Next(); next != nil { - m.current = next - return m.current.Value.(string), true - } - return "", false -} - -func (m *model) moveHistoryBackward() (string, bool) { - if prev := m.current.Prev(); prev != nil { - m.current = prev - return m.current.Value.(string), true - } - return "", false -} - -func (m model) fetchRenderView(path string) (view []byte, err error) { - rlmpath, args, _ := strings.Cut(path, ":") - res, err := m.client.Render(rlmpath, args) - if err != nil { - return nil, fmt.Errorf("unable to fetch Render: %w", err) - } - - r, err := glamour.NewTermRenderer( - glamour.WithStyles(CatppuccinStyleConfig), // XXX: use gno custom theme - glamour.WithWordWrap(m.viewport.Width), - ) - if err != nil { - return nil, fmt.Errorf("unable to get render view: %w", err) - } - - view, err = r.RenderBytes(res) - if err != nil { - return nil, fmt.Errorf("uanble to render markdown view: %w", err) - } - - return view, nil -} diff --git a/contribs/gnodev/pkg/browser/model_style.go b/contribs/gnodev/pkg/browser/model_style.go deleted file mode 100644 index f3c3a18fd96..00000000000 --- a/contribs/gnodev/pkg/browser/model_style.go +++ /dev/null @@ -1,239 +0,0 @@ -package browser - -import "github.com/charmbracelet/glamour/ansi" - -const ( - defaultListIndent = 2 - defaultListLevelIndent = 4 - defaultMargin = 2 -) - -// Catpuccin style: https://github.com/catppuccin/catppuccin -// XXX: update this with `gno` colors scheme -var CatppuccinStyleConfig = ansi.StyleConfig{ - Document: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - BlockPrefix: "\n", - BlockSuffix: "\n", - Color: stringPtr("#cad3f5"), - }, - Margin: uintPtr(defaultMargin), - }, - BlockQuote: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Color: stringPtr("#cad3f5"), - Italic: boolPtr(true), - }, - Indent: uintPtr(1), - }, - List: ansi.StyleList{ - LevelIndent: defaultListIndent, - StyleBlock: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Color: stringPtr("#cad3f5"), - }, - }, - }, - Heading: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - BlockSuffix: "\n", - Color: stringPtr("#cad3f5"), - Bold: boolPtr(true), - }, - }, - H1: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Prefix: " ", - Suffix: " ", - BackgroundColor: stringPtr("#f0c6c6"), - Color: stringPtr("#181926"), - Bold: boolPtr(true), - }, - }, - H2: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Prefix: "● ", - Color: stringPtr("#f5a97f"), - }, - }, - H3: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Prefix: "◉ ", - Color: stringPtr("#eed49f"), - }, - }, - H4: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Prefix: "○ ", - Color: stringPtr("#a6da95"), - }, - }, - H5: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Prefix: "◌ ", - Color: stringPtr("#7dc4e4"), - }, - }, - H6: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Prefix: "‣ ", - Color: stringPtr("#b7bdf8"), - }, - }, - Strikethrough: ansi.StylePrimitive{ - CrossedOut: boolPtr(true), - }, - Emph: ansi.StylePrimitive{ - Color: stringPtr("#cad3f5"), - Italic: boolPtr(true), - }, - Strong: ansi.StylePrimitive{ - Bold: boolPtr(true), - Color: stringPtr("#cad3f5"), - }, - HorizontalRule: ansi.StylePrimitive{ - Color: stringPtr("#6e738d"), - Format: "\n--------\n", - }, - Item: ansi.StylePrimitive{ - BlockPrefix: "• ", - }, - Enumeration: ansi.StylePrimitive{ - BlockPrefix: ". ", - Color: stringPtr("#cad3f5"), - }, - Task: ansi.StyleTask{ - StylePrimitive: ansi.StylePrimitive{}, - Ticked: "[✓] ", - Unticked: "[ ] ", - }, - Link: ansi.StylePrimitive{ - Color: stringPtr("#8aadf4"), - Underline: boolPtr(true), - }, - LinkText: ansi.StylePrimitive{ - Color: stringPtr("#b7bdf8"), - }, - Image: ansi.StylePrimitive{ - Color: stringPtr("#8aadf4"), - Underline: boolPtr(true), - }, - ImageText: ansi.StylePrimitive{ - Color: stringPtr("#b7bdf8"), - Format: "Image: {{.text}} →", - }, - Code: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Color: stringPtr("#ee99a0"), - }, - }, - CodeBlock: ansi.StyleCodeBlock{ - StyleBlock: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{ - Color: stringPtr("#1e2030"), - }, - Margin: uintPtr(defaultMargin), - }, - Chroma: &ansi.Chroma{ - Text: ansi.StylePrimitive{ - Color: stringPtr("#cad3f5"), - }, - Error: ansi.StylePrimitive{ - Color: stringPtr("#cad3f5"), - BackgroundColor: stringPtr("#ed8796"), - }, - Comment: ansi.StylePrimitive{ - Color: stringPtr("#6e738d"), - }, - CommentPreproc: ansi.StylePrimitive{ - Color: stringPtr("#8aadf4"), - }, - Keyword: ansi.StylePrimitive{ - Color: stringPtr("#c6a0f6"), - }, - KeywordReserved: ansi.StylePrimitive{ - Color: stringPtr("#c6a0f6"), - }, - KeywordNamespace: ansi.StylePrimitive{ - Color: stringPtr("#eed49f"), - }, - KeywordType: ansi.StylePrimitive{ - Color: stringPtr("#eed49f"), - }, - Operator: ansi.StylePrimitive{ - Color: stringPtr("#91d7e3"), - }, - Punctuation: ansi.StylePrimitive{ - Color: stringPtr("#939ab7"), - }, - Name: ansi.StylePrimitive{ - Color: stringPtr("#b7bdf8"), - }, - NameBuiltin: ansi.StylePrimitive{ - Color: stringPtr("#f5a97f"), - }, - NameTag: ansi.StylePrimitive{ - Color: stringPtr("#c6a0f6"), - }, - NameAttribute: ansi.StylePrimitive{ - Color: stringPtr("#eed49f"), - }, - NameClass: ansi.StylePrimitive{ - Color: stringPtr("#eed49f"), - }, - NameConstant: ansi.StylePrimitive{ - Color: stringPtr("#eed49f"), - }, - NameDecorator: ansi.StylePrimitive{ - Color: stringPtr("#f5bde6"), - }, - NameFunction: ansi.StylePrimitive{ - Color: stringPtr("#8aadf4"), - }, - LiteralNumber: ansi.StylePrimitive{ - Color: stringPtr("#f5a97f"), - }, - LiteralString: ansi.StylePrimitive{ - Color: stringPtr("#a6da95"), - }, - LiteralStringEscape: ansi.StylePrimitive{ - Color: stringPtr("#f5bde6"), - }, - GenericDeleted: ansi.StylePrimitive{ - Color: stringPtr("#ed8796"), - }, - GenericEmph: ansi.StylePrimitive{ - Color: stringPtr("#cad3f5"), - Italic: boolPtr(true), - }, - GenericInserted: ansi.StylePrimitive{ - Color: stringPtr("#a6da95"), - }, - GenericStrong: ansi.StylePrimitive{ - Color: stringPtr("#cad3f5"), - Bold: boolPtr(true), - }, - GenericSubheading: ansi.StylePrimitive{ - Color: stringPtr("#91d7e3"), - }, - Background: ansi.StylePrimitive{ - BackgroundColor: stringPtr("#1e2030"), - }, - }, - }, - Table: ansi.StyleTable{ - StyleBlock: ansi.StyleBlock{ - StylePrimitive: ansi.StylePrimitive{}, - }, - CenterSeparator: stringPtr("┼"), - ColumnSeparator: stringPtr("│"), - RowSeparator: stringPtr("─"), - }, - DefinitionDescription: ansi.StylePrimitive{ - BlockPrefix: "\n🠶 ", - }, -} - -func boolPtr(b bool) *bool { return &b } -func stringPtr(s string) *string { return &s } -func uintPtr(u uint) *uint { return &u } diff --git a/contribs/gnodev/pkg/browser/model_tasks.go b/contribs/gnodev/pkg/browser/model_tasks.go deleted file mode 100644 index 553d0168b6d..00000000000 --- a/contribs/gnodev/pkg/browser/model_tasks.go +++ /dev/null @@ -1,85 +0,0 @@ -// modified version of ""github.com/charmbracelet/bubbles/spinner" - -package browser - -import ( - "time" - - tea "github.com/charmbracelet/bubbletea" -) - -type Spinner struct { - Frames []string - FPS time.Duration -} - -// TickMsg indicates that the timer has ticked and we should render a frame. -type SpinnerTickMsg time.Time - -var MeterLoader = Spinner{ - Frames: []string{ - "▱▱▱▱▱▱▱▱", "▰▱▱▱▱▱▱▱", "▰▰▱▱▱▱▱▱", "▰▰▰▱▱▱▱▱", - "▰▰▰▰▱▱▱▱", "▰▰▰▰▰▱▱▱", "▰▰▰▰▰▰▱▱", "▰▰▰▰▰▰▰▱", - "▰▰▰▰▰▰▰▰", "▱▰▰▰▰▰▰▰", "▱▱▰▰▰▰▰▰", "▱▱▱▰▰▰▰▰", - "▱▱▱▱▰▰▰▰", "▱▱▱▱▱▰▰▰", "▱▱▱▱▱▱▰▰", "▱▱▱▱▱▱▱▰", - }, - FPS: time.Second / 70, //nolint:gomnd -} - -type LoaderModel struct { - spinner Spinner - frame int - task int -} - -func newLoaderModel() LoaderModel { - return LoaderModel{ - spinner: MeterLoader, - } -} - -func (m LoaderModel) Update(msg tea.Msg) (LoaderModel, tea.Cmd) { - switch msg.(type) { - case SpinnerTickMsg: - m.frame = (m.frame + 1) % len(m.spinner.Frames) - return m, m.tick() - default: - return m, nil - } -} - -func (m LoaderModel) tick() tea.Cmd { - return tea.Tick(m.spinner.FPS, func(t time.Time) tea.Msg { - return SpinnerTickMsg(t) - }) -} - -func (m LoaderModel) Tick() tea.Msg { - return SpinnerTickMsg(time.Now()) -} - -func (m *LoaderModel) Active() bool { - return m.frame > 0 || m.task > 0 -} - -func (m *LoaderModel) Add(i int) tea.Cmd { - var cmd tea.Cmd - if i > 0 { - if m.task == 0 { - cmd = m.Tick - } - - m.task += i - } - return cmd -} - -func (m *LoaderModel) Done() { - if m.task > 0 { - m.task -= 1 - } -} - -func (m *LoaderModel) View() string { - return m.spinner.Frames[m.frame] -} diff --git a/contribs/gnodev/pkg/browser/model_view.go b/contribs/gnodev/pkg/browser/model_view.go deleted file mode 100644 index 40d78d18c6d..00000000000 --- a/contribs/gnodev/pkg/browser/model_view.go +++ /dev/null @@ -1,174 +0,0 @@ -package browser - -import ( - "fmt" - "strings" - - "github.com/charmbracelet/lipgloss" -) - -var ( - boxRoundedStyle = func(r *lipgloss.Renderer) lipgloss.Style { - b := lipgloss.RoundedBorder() - return r.NewStyle(). - BorderStyle(b). - Padding(0, 2) - } - - inputStyleLeft = func(r *lipgloss.Renderer) lipgloss.Style { - b := lipgloss.RoundedBorder() - b.Right = "├" - return r.NewStyle(). - BorderStyle(b). - Padding(0, 2) - } - - infoStyle = func(r *lipgloss.Renderer) lipgloss.Style { - b := lipgloss.RoundedBorder() - b.Left = "┤" - return boxRoundedStyle(r).Copy().BorderStyle(b) - } -) - -func (m model) View() string { - if !m.bannerDiscarded { - return m.bannerView() - } - - if !m.ready { - return "+" - } - - mainView := fmt.Sprintf("%s\n%s\n%s", m.headerView(), m.bodyView(), m.footerView()) - return m.zone.Scan(mainView) -} - -func (m model) bannerView() string { - banner := m.banner.View() - if banner == "" || m.width == 0 || m.height == 0 { - return "" - } - - // XXX: Encapsulate banner to avoid banner glitches - bannerView := m.render.NewStyle().Margin(1). - Render(banner) - widthView := m.width + 1 - - return lipgloss.Place(widthView, m.height, lipgloss.Center, lipgloss.Center, - lipgloss.JoinVertical(lipgloss.Center, - bannerView, - "press to continue", - ), - ) -} - -func (m model) listFuncsView() string { - return boxRoundedStyle(m.render). - Render(m.listFuncs.View()) -} - -func (m model) bodyView() string { - if m.commandInput.Focused() { - // handle command input - if v := m.commandInput.Value(); v != "" { - m.listFuncs.FilterItems(v) - } else { - m.listFuncs.Reset() - } - - if len(m.listFuncs.Items()) > 0 { - m.viewport.Height = m.height - lipgloss.Height(m.listFuncsView()) - } else { - m.viewport.Height = m.height - } - } - - return m.viewport.View() -} - -var ( - loadingStyle = func(r *lipgloss.Renderer) lipgloss.Style { - return r.NewStyle(). - Foreground(lipgloss.Color("#dd7878")). - Bold(true) - } - - navStyleEnable = func(r *lipgloss.Renderer) lipgloss.Style { - return r.NewStyle(). - Foreground(lipgloss.Color("#fab387")) - } - - navStyleDisable = func(r *lipgloss.Renderer) lipgloss.Style { - return r.NewStyle(). - Foreground(lipgloss.Color("240")) - } -) - -func (m model) navView() string { - home := navStyleEnable(m.render).Padding(0, 1).Render("[Home]") - - var style lipgloss.Style - if m.current != nil && m.current.Prev() != nil { - style = navStyleEnable(m.render) - } else { - style = navStyleDisable(m.render) - } - prev := style.Margin(0, 1).Render("") - - title := m.render.NewStyle().Bold(true).Render("Gno.Land") - if m.taskLoader.Active() { - title = loadingStyle(m.render).Render(m.taskLoader.View()) - } - - spaceWidth := m.width / 3 // left middle and right - return lipgloss.JoinHorizontal(lipgloss.Left, - m.render.NewStyle().Width(spaceWidth).Padding(0, 1). - Render(lipgloss.JoinHorizontal(lipgloss.Left, - m.zone.Mark("prev_button", prev), - m.zone.Mark("next_button", next), - )), - m.render.PlaceHorizontal(spaceWidth, lipgloss.Center, title), - m.render.PlaceHorizontal(spaceWidth, lipgloss.Right, - m.zone.Mark("home_button", home)), - ) -} - -func (m model) headerView() string { - return lipgloss.JoinVertical(lipgloss.Left, m.navView(), m.urlView()) -} - -func (m model) urlView() string { - return m.zone.Mark("url_input", boxRoundedStyle(m.render). - Width(m.viewport.Width-2). - Render(m.urlInput.View())) -} - -func (m model) footerView() string { - info := infoStyle(m.render).Render(fmt.Sprintf("%3.f%%", m.viewport.ScrollPercent()*100)) - - if m.readonly { - // On readonly, simply discard command input interface - line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(info))) - return lipgloss.JoinHorizontal(lipgloss.Center, line, info) - } - - command := m.zone.Mark("command_input", inputStyleLeft(m.render). - Width(m.viewport.Width-lipgloss.Width(info)-5). - Render(m.commandInput.View())) - line := strings.Repeat("─", 3) - - powerline := lipgloss.JoinHorizontal(lipgloss.Center, command, line, info) - if m.commandFocus && len(m.listFuncs.Items()) > 0 { - suggestions := m.listFuncsView() - return lipgloss.JoinVertical(lipgloss.Left, suggestions, powerline) - } - - return powerline -} diff --git a/contribs/gnodev/pkg/browser/utils.go b/contribs/gnodev/pkg/browser/utils.go deleted file mode 100644 index b322bea552a..00000000000 --- a/contribs/gnodev/pkg/browser/utils.go +++ /dev/null @@ -1,33 +0,0 @@ -package browser - -import ( - "path/filepath" - "strings" - - "github.com/gnolang/gno/gno.land/pkg/gnoweb" -) - -func redirectWebPath(path string) string { - if alias, ok := gnoweb.Aliases[path]; ok { - return alias - } - - if redirect, ok := gnoweb.Redirects[path]; ok { - return redirect - } - - return path -} - -func cleanupRealmPath(prefix, realm string) string { - // Trim prefix - path := strings.TrimPrefix(realm, prefix) - // redirect if any well known path - path = redirectWebPath(path) - // trim any slash - path = strings.TrimPrefix(path, "/") - // clean up path - path = filepath.Clean(path) - - return path -} diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index c3e70366fb2..7f0c266bf48 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -12,7 +12,6 @@ import ( "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/contribs/gnodev/pkg/events" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/gno.land/pkg/integration" "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/tm2/pkg/amino" @@ -53,7 +52,7 @@ func DefaultNodeConfig(rootdir string) *NodeConfig { balances := []gnoland.Balance{ { Address: defaultDeployer, - Amount: std.Coins{std.NewCoin(ugnot.Denom, 10e12)}, + Amount: std.Coins{std.NewCoin("ugnot", 10e12)}, }, } @@ -88,7 +87,7 @@ type Node struct { currentStateIndex int } -var DefaultFee = std.NewFee(50000, std.MustParseCoin(ugnot.ValueString(1000000))) +var DefaultFee = std.NewFee(50000, std.MustParseCoin("1000000ugnot")) func NewDevNode(ctx context.Context, cfg *NodeConfig) (*Node, error) { mpkgs, err := NewPackagesMap(cfg.PackagesPathList) @@ -469,9 +468,7 @@ func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) // Setup node config nodeConfig := newNodeConfig(n.config.TMConfig, n.config.ChainID, genesis) - nodeConfig.GenesisTxResultHandler = n.genesisTxResultHandler - // Speed up stdlib loading after first start (saves about 2-3 seconds on each reload). - nodeConfig.CacheStdlibLoad = true + nodeConfig.GenesisTxHandler = n.genesisTxHandler nodeConfig.Genesis.ConsensusParams.Block.MaxGas = n.config.MaxGasPerBlock // recoverFromError handles panics and converts them to errors. @@ -514,7 +511,7 @@ func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) return nil } -func (n *Node) genesisTxResultHandler(ctx sdk.Context, tx std.Tx, res sdk.Result) { +func (n *Node) genesisTxHandler(ctx sdk.Context, tx std.Tx, res sdk.Result) { if !res.IsErr() { return } diff --git a/contribs/gnodev/pkg/dev/node_state_test.go b/contribs/gnodev/pkg/dev/node_state_test.go index efaeb979693..17f96367512 100644 --- a/contribs/gnodev/pkg/dev/node_state_test.go +++ b/contribs/gnodev/pkg/dev/node_state_test.go @@ -8,8 +8,8 @@ import ( emitter "github.com/gnolang/gno/contribs/gnodev/internal/mock" "github.com/gnolang/gno/contribs/gnodev/pkg/events" + "github.com/gnolang/gno/gno.land/pkg/gnoclient" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -87,10 +87,10 @@ func TestSaveCurrentState(t *testing.T) { require.NoError(t, err) // Send a new tx - msg := vm.MsgCall{ - PkgPath: testCounterRealm, - Func: "Inc", - Args: []string{"10"}, + msg := gnoclient.MsgCall{ + PkgPath: testCounterRealm, + FuncName: "Inc", + Args: []string{"10"}, } res, err := testingCallRealm(t, node, msg) @@ -169,10 +169,10 @@ func Render(_ string) string { return strconv.Itoa(value) } for i := 0; i < inc; i++ { t.Logf("call %d", i) // Craft `Inc` msg - msg := vm.MsgCall{ - PkgPath: testCounterRealm, - Func: "Inc", - Args: []string{"1"}, + msg := gnoclient.MsgCall{ + PkgPath: testCounterRealm, + FuncName: "Inc", + Args: []string{"1"}, } res, err := testingCallRealm(t, node, msg) diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index 11b0a2090d7..48204b4ce8d 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -10,9 +10,7 @@ import ( "github.com/gnolang/gno/contribs/gnodev/pkg/events" "github.com/gnolang/gno/gno.land/pkg/gnoclient" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/gno.land/pkg/integration" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/gnolang/gno/gnovm/pkg/gnoenv" core_types "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" "github.com/gnolang/gno/tm2/pkg/crypto" @@ -191,11 +189,11 @@ func Render(_ string) string { return str } require.Equal(t, render, "foo") // Call `UpdateStr` to update `str` value with "bar" - msg := vm.MsgCall{ - PkgPath: "gno.land/r/dev/foo", - Func: "UpdateStr", - Args: []string{"bar"}, - Send: nil, + msg := gnoclient.MsgCall{ + PkgPath: "gno.land/r/dev/foo", + FuncName: "UpdateStr", + Args: []string{"bar"}, + Send: "", } res, err := testingCallRealm(t, node, msg) require.NoError(t, err) @@ -238,7 +236,7 @@ func testingRenderRealm(t *testing.T, node *Node, rlmpath string) (string, error return render, err } -func testingCallRealm(t *testing.T, node *Node, msgs ...vm.MsgCall) (*core_types.ResultBroadcastTxCommit, error) { +func testingCallRealm(t *testing.T, node *Node, msgs ...gnoclient.MsgCall) (*core_types.ResultBroadcastTxCommit, error) { t.Helper() signer := newInMemorySigner(t, node.Config().ChainID()) @@ -248,19 +246,11 @@ func testingCallRealm(t *testing.T, node *Node, msgs ...vm.MsgCall) (*core_types } txcfg := gnoclient.BaseTxCfg{ - GasFee: ugnot.ValueString(1000000), // Gas fee - GasWanted: 2_000_000, // Gas wanted + GasFee: "1000000ugnot", // Gas fee + GasWanted: 2_000_000, // Gas wanted } - // Set Caller in the msgs - caller, err := signer.Info() - require.NoError(t, err) - vmMsgs := make([]vm.MsgCall, 0, len(msgs)) - for _, msg := range msgs { - vmMsgs = append(vmMsgs, vm.NewMsgCall(caller.GetAddress(), msg.Send, msg.PkgPath, msg.Func, msg.Args)) - } - - return cli.Call(txcfg, vmMsgs...) + return cli.Call(txcfg, msgs...) } func generateTestingPackage(t *testing.T, nameFile ...string) PackagePath { diff --git a/contribs/gnodev/pkg/dev/packages_test.go b/contribs/gnodev/pkg/dev/packages_test.go index 151a89a7815..605db312429 100644 --- a/contribs/gnodev/pkg/dev/packages_test.go +++ b/contribs/gnodev/pkg/dev/packages_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/gnolang/gno/contribs/gnodev/pkg/address" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/std" "github.com/stretchr/testify/assert" @@ -27,60 +26,33 @@ func TestResolvePackagePathQuery(t *testing.T) { ExpectedPackagePath PackagePath ShouldFail bool }{ - { + {".", PackagePath{ Path: ".", - ExpectedPackagePath: PackagePath{ - Path: ".", - }, - }, - { + }, false}, + {"/simple/path", PackagePath{ Path: "/simple/path", - ExpectedPackagePath: PackagePath{ - Path: "/simple/path", - }, - }, - { - Path: "/ambiguo/u//s/path///", - ExpectedPackagePath: PackagePath{ - Path: "/ambiguo/u/s/path", - }, - }, - { - Path: "/path/with/creator?creator=testAccount", - ExpectedPackagePath: PackagePath{ - Path: "/path/with/creator", - Creator: testingAddress, - }, - }, - { - Path: "/path/with/deposit?deposit=" + ugnot.ValueString(100), - ExpectedPackagePath: PackagePath{ - Path: "/path/with/deposit", - Deposit: std.MustParseCoins(ugnot.ValueString(100)), - }, - }, - { - Path: ".?creator=g1hr3dl82qdy84a5h3dmckh0suc7zgwm5rnns6na&deposit=" + ugnot.ValueString(100), - ExpectedPackagePath: PackagePath{ - Path: ".", - Creator: testingAddress, - Deposit: std.MustParseCoins(ugnot.ValueString(100)), - }, - }, + }, false}, + {"/ambiguo/u//s/path///", PackagePath{ + Path: "/ambiguo/u/s/path", + }, false}, + {"/path/with/creator?creator=testAccount", PackagePath{ + Path: "/path/with/creator", + Creator: testingAddress, + }, false}, + {"/path/with/deposit?deposit=100ugnot", PackagePath{ + Path: "/path/with/deposit", + Deposit: std.MustParseCoins("100ugnot"), + }, false}, + {".?creator=g1hr3dl82qdy84a5h3dmckh0suc7zgwm5rnns6na&deposit=100ugnot", PackagePath{ + Path: ".", + Creator: testingAddress, + Deposit: std.MustParseCoins("100ugnot"), + }, false}, // errors cases - { - Path: "/invalid/account?creator=UnknownAccount", - ShouldFail: true, - }, - { - Path: "/invalid/address?creator=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", - ShouldFail: true, - }, - { - Path: "/invalid/deposit?deposit=abcd", - ShouldFail: true, - }, + {"/invalid/account?creator=UnknownAccount", PackagePath{}, true}, + {"/invalid/address?creator=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", PackagePath{}, true}, + {"/invalid/deposit?deposit=abcd", PackagePath{}, true}, } for _, tc := range cases { diff --git a/contribs/gnodev/pkg/emitter/server.go b/contribs/gnodev/pkg/emitter/server.go index 3e32984268d..e6052890095 100644 --- a/contribs/gnodev/pkg/emitter/server.go +++ b/contribs/gnodev/pkg/emitter/server.go @@ -60,7 +60,7 @@ func (s *Server) Emit(evt events.Event) { go s.emit(evt) } -type EventJSON struct { +type eventJSON struct { Type events.Type `json:"type"` Data any `json:"data"` } @@ -69,7 +69,7 @@ func (s *Server) emit(evt events.Event) { s.muClients.Lock() defer s.muClients.Unlock() - jsonEvt := EventJSON{evt.Type(), evt} + jsonEvt := eventJSON{evt.Type(), evt} s.logger.Info("sending event to clients", "clients", len(s.clients), diff --git a/contribs/gnodev/pkg/emitter/server_test.go b/contribs/gnodev/pkg/emitter/server_test.go index 8795d2da048..4725378dbda 100644 --- a/contribs/gnodev/pkg/emitter/server_test.go +++ b/contribs/gnodev/pkg/emitter/server_test.go @@ -40,7 +40,7 @@ func TestServer_ServeHTTP(t *testing.T) { sendEvt := events.Custom("TEST") svr.Emit(sendEvt) // simulate reload - var recvEvt EventJSON + var recvEvt eventJSON err = c.ReadJSON(&recvEvt) require.NoError(t, err) assert.Equal(t, sendEvt.Type(), recvEvt.Type) diff --git a/contribs/gnofaucet/go.mod b/contribs/gnofaucet/go.mod index c56c0b7d425..0662de5f82f 100644 --- a/contribs/gnofaucet/go.mod +++ b/contribs/gnofaucet/go.mod @@ -5,8 +5,8 @@ go 1.22 toolchain go1.22.4 require ( - github.com/gnolang/faucet v0.3.2 - github.com/gnolang/gno v0.1.1 + github.com/gnolang/faucet v0.2.1 + github.com/gnolang/gno v0.1.0-nightly.20240627 github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 golang.org/x/time v0.5.0 @@ -19,10 +19,9 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect - github.com/go-chi/chi/v5 v5.1.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-chi/chi/v5 v5.0.12 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect @@ -30,27 +29,27 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/cors v1.11.0 // indirect github.com/rs/xid v1.5.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.opentelemetry.io/otel v1.27.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.26.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.27.0 // indirect + go.opentelemetry.io/otel/sdk v1.27.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect + go.opentelemetry.io/otel/trace v1.27.0 // indirect + go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap/exp v0.2.0 // indirect - golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect - golang.org/x/mod v0.19.0 // indirect - golang.org/x/net v0.27.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/term v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect + google.golang.org/grpc v1.64.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/contribs/gnofaucet/go.sum b/contribs/gnofaucet/go.sum index 1508cdae1e6..29dc3efcb76 100644 --- a/contribs/gnofaucet/go.sum +++ b/contribs/gnofaucet/go.sum @@ -45,17 +45,17 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gnolang/faucet v0.3.2 h1:3QBrdmnQszRaAZbxgO5xDDm3czNa0L/RFmhnCkbxy5I= -github.com/gnolang/faucet v0.3.2/go.mod h1:/wbw9h4ooMzzyNBuM0X+ol7CiPH2OFjAFF3bYAXqA7U= -github.com/gnolang/gno v0.1.1 h1:t41S0SWIUa3syI7XpRAuCneCgRc8gOJ2g8DkUedF72U= -github.com/gnolang/gno v0.1.1/go.mod h1:BTaBNeaoY/W95NN6QA4RCoQ6Z7mi8M+Zb1I1wMWGg2w= +github.com/gnolang/faucet v0.2.1 h1:ohYzZEuweqwTJBiutZbWFgb4w2slI6/JKobGPmiwG0g= +github.com/gnolang/faucet v0.2.1/go.mod h1:cOWkLBbgJ9mjOiYW4DBrZ0P5m0+14pTLaERF7v/5b+4= +github.com/gnolang/gno v0.1.0-nightly.20240627 h1:ZfVzzr2nadX5NLsZ76WN2CLb7TTuMJMwCdqTBZXVLGo= +github.com/gnolang/gno v0.1.0-nightly.20240627/go.mod h1:WCOCLF55BgFd2cw/Rrqa4zk9nK4AVVvbrPKprhkG4Wo= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8= -github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= -github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -74,8 +74,6 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= @@ -121,22 +119,22 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLmmtjRke7LPDQ3lvpFz+kNEH43faFhzW7v8BFIEydg= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0/go.mod h1:TC1pyCt6G9Sjb4bQpShH+P5R53pO6ZuGnHuuln9xMeE= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08= -go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= +go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.26.0 h1:+hm+I+KigBy3M24/h1p/NHkUx/evbLH0PNcjpMyCHc4= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.26.0/go.mod h1:NjC8142mLvvNT6biDpaMjyz78kyEHIwAJlSX0N9P5KI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 h1:CIHWikMsN3wO+wq1Tp5VGdVRTcON+DmOJSfDjXypKOc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0/go.mod h1:TNupZ6cxqyFEpLXAZW7On+mLFL0/g0TE3unIYL91xWc= +go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= +go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= +go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= +go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= +go.opentelemetry.io/otel/sdk/metric v1.27.0 h1:5uGNOlpXi+Hbo/DRoI31BSb1v+OGcpv2NemcCrOL8gI= +go.opentelemetry.io/otel/sdk/metric v1.27.0/go.mod h1:we7jJVrYN2kh3mVBlswtPU22K0SA+769l93J6bsyvqw= +go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= +go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= +go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -148,19 +146,19 @@ go.uber.org/zap/exp v0.2.0/go.mod h1:t0gqAIdh1MfKv9EwN/dLwfZnJxe9ITAZN78HEWPFWDQ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -173,34 +171,34 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/contribs/gnokeykc/go.mod b/contribs/gnokeykc/go.mod index a8e235a5c5a..9531b94a628 100644 --- a/contribs/gnokeykc/go.mod +++ b/contribs/gnokeykc/go.mod @@ -14,7 +14,7 @@ require ( require ( github.com/alessio/shellescape v1.4.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect - github.com/btcsuite/btcd/btcutil v1.1.6 // indirect + github.com/btcsuite/btcd/btcutil v1.1.5 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect @@ -29,35 +29,35 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/peterbourgon/ff/v3 v3.4.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rs/xid v1.6.0 // indirect + github.com/rs/xid v1.5.0 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect - go.opentelemetry.io/otel v1.29.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/sdk v1.29.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.26.0 // indirect + golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect - golang.org/x/mod v0.20.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/contribs/gnokeykc/go.sum b/contribs/gnokeykc/go.sum index b3bfadb3468..20c847e59f8 100644 --- a/contribs/gnokeykc/go.sum +++ b/contribs/gnokeykc/go.sum @@ -1,22 +1,20 @@ -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7Nzl7WHaOTlTr5hIrR4n1NM4v9n4Kw= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= -github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= -github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= -github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= -github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= @@ -86,8 +84,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -124,17 +122,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= -github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -145,22 +138,22 @@ github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= -go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= -go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 h1:k6fQVDQexDE+3jG2SfCQjnHS7OamcP73YMoxEVq5B6k= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0/go.mod h1:t4BrYLHU450Zo9fnydWlIuswB1bm7rM8havDpWOJeDo= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 h1:xvhQxJ/C9+RTnAj5DpTg7LSM1vbbMTiXt7e9hsfqHNw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0/go.mod h1:Fcvs2Bz1jkDM+Wf5/ozBGmi3tQ/c9zPKLnsipnfhGAo= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/sdk/metric v1.29.0 h1:K2CfmJohnRgvZ9UAj2/FhIf/okdWcNdBwe1m8xFXiSY= -go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLmmtjRke7LPDQ3lvpFz+kNEH43faFhzW7v8BFIEydg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0/go.mod h1:TC1pyCt6G9Sjb4bQpShH+P5R53pO6ZuGnHuuln9xMeE= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08= +go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -168,19 +161,19 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -191,23 +184,23 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/docs/concepts/portal-loop.md b/docs/concepts/portal-loop.md index adc341e3ae4..d96738bdddf 100644 --- a/docs/concepts/portal-loop.md +++ b/docs/concepts/portal-loop.md @@ -67,20 +67,3 @@ has some drawbacks: Gno will fail to be replayed, meaning **data will be lost**. - Since transactions are archived and replayed during genesis, block height & timestamp cannot be relied upon. - -### Deploying to the Portal Loop - -There are two ways to deploy code to the Portal Loop: - -1. *automatic* - all packages in found in the `examples/gno.land/{p,r}/` directory in the [Gno monorepo](https://github.com/gnolang/gno) get added to the - new genesis each cycle, -2. *permissionless* - this includes replayed transactions with `addpkg`, and - new transactions you can issue with `gnokey maketx addpkg`. - -Since the packages in `examples/gno.land/{p,r}` are deployed first, -permissionless deployments get superseded when packages with identical `pkgpath` -get merged into `examples/`. - -The above mechanism is also how the `examples/` on the Portal Loop -get collaboratively iterated upon, which is its main mission. - diff --git a/docs/getting-started/local-setup/creating-a-keypair.md b/docs/getting-started/local-setup/creating-a-keypair.md deleted file mode 100644 index 983d732a0fd..00000000000 --- a/docs/getting-started/local-setup/creating-a-keypair.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -id: creating-a-keypair ---- - -# Creating a Keypair - -## Overview - -In this tutorial, you will learn how to create your Gno keypair using -[`gnokey`](../../gno-tooling/cli/gnokey/gnokey.md). - -Keypairs are the foundation of how users interact with blockchains; and Gno is -no exception. By using a 12-word or 24-word [mnemonic phrase](https://www.zimperium.com/glossary/mnemonic-seed/) -as a source of randomness, users can derive a private and a public key. -These two keys can then be used further; a public key derives an address which is -a unique identifier of a user on the blockchain, while a private key is used for -signing messages and transactions for the aforementioned address, proving a user -has ownership over it. - -Let's see how we can use `gnokey` to generate a Gno keypair locally. - -## Generating a keypair - -The `gnokey add` command allows you to generate a new keypair locally. Simply -run the command, while adding a name for your keypair: - -```bash -gnokey add MyKey -``` - -![gnokey-add-random](../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-add-random.gif) - -After running the command, `gnokey` will ask you to enter a password that will be -used to encrypt your keypair to the disk. Then, it will show you the following -information: -- Your public key, as well as the Gno address derived from it, starting with `g1...`, -- Your randomly generated 12-word mnemonic phrase which was used to derive the keypair. - -:::warning Safeguard your mnemonic phrase! - -A **mnemonic phrase** is like your master password; you can use it over and over -to derive the same keypairs. This is why it is crucial to store it in a safe, -offline place - writing the phrase on a piece of paper and hiding it is highly -recommended. **If it gets lost, it is unrecoverable.** - -::: - -`gnokey` will generate a keybase in which it will store information about your -keypairs. The keybase directory path is stored under the `-home` flag in `gnokey`. - -### Gno addresses - -Your **Gno address** is like your unique identifier on the network; an address -is visible in the caller stack of an application, it is included in each -transaction you create with your keypair, and anyone who knows your address can -send you [coins](../../concepts/stdlibs/coin.md), etc. - -## Conclusion - -That's it 🎉 - -You've successfully created your first Gno keypair. Check out -[Browsing gno.land](./browsing-gnoland.md) and -[Interacting with gno.land](./interacting-with-gnoland.md) to see how you can -use it. - -If you wish to learn more about `gnokey` specifically, check out the -[gnokey section](../../gno-tooling/cli/gnokey/gnokey.md). - - - - - - - - - diff --git a/docs/getting-started/local-setup/installation.md b/docs/getting-started/local-setup/installation.md index 272d0069ee5..58f71f93026 100644 --- a/docs/getting-started/local-setup/installation.md +++ b/docs/getting-started/local-setup/installation.md @@ -35,7 +35,7 @@ git clone https://github.com/gnolang/gno.git There are three tools that should be used for getting started with Gno development: - `gno` - the GnoVM binary - `gnodev` - the Gno [development helper](../../gno-tooling/cli/gnodev.md) -- `gnokey` - the Gno [keypair manager](../../gno-tooling/cli/gnokey/working-with-key-pairs.md) +- `gnokey` - the Gno [keypair manager](working-with-key-pairs.md) To install all three tools, simply run the following in the root of the repo: ```bash @@ -87,7 +87,7 @@ You should get the following output: `gnokey` is the gno.land keypair management CLI tool. It allows you to create keypairs, sign transactions, and broadcast them to gno.land chains. Read more -about `gnokey` [here](../../gno-tooling/cli/gnokey/gnokey.md). +about `gnokey` [here](../../gno-tooling/cli/gnokey.md). To verify that the `gnokey` binary is installed system-wide, you can run: @@ -106,5 +106,5 @@ That's it 🎉 You have successfully built out and installed the necessary tools for Gno development! -In further documents, you will gain a better understanding of how they are used +In further documents, you will gain a better understanding on how they are used to make Gno work. diff --git a/docs/getting-started/local-setup/interacting-with-gnoland.md b/docs/getting-started/local-setup/interacting-with-gnoland.md index 6b4b8213228..e07c839d691 100644 --- a/docs/getting-started/local-setup/interacting-with-gnoland.md +++ b/docs/getting-started/local-setup/interacting-with-gnoland.md @@ -10,10 +10,10 @@ You will understand how to use your keypair to send transactions to realms and packages, send native coins, and more. ## Prerequisites - - **`gnokey` installed.** Reference the -[Local Setup](installation.md) guide for steps -- **A keypair in `gnokey`.** Reference the [Creating a key pair](creating-a-keypair.md) guide for steps +[Local Setup](installation.md#3-installing-other-gno-tools) guide for steps +- **A keypair in `gnokey`.** Reference the +[Working with Key Pairs](working-with-key-pairs.md#adding-a-private-key-using-a-mnemonic) guide for steps ## 1. Get testnet GNOTs For interacting with any gno.land chain, you will need a certain amount of GNOTs @@ -21,7 +21,8 @@ to pay gas fees with. For this example, we will use the [Portal Loop](../../concepts/testnets.md#portal-loop) testnet. We can access the Portal Loop faucet through the -[Gno Faucet Hub](https://faucet.gno.land). +[Gno Faucet Hub](https://faucet.gno.land), or by accessing the faucet directly at +[gno.land/faucet](https://gno.land/faucet). ![faucet-hub](../../assets/getting-started/local-setup/interacting-with-gnoland/faucet-hub.png) @@ -34,7 +35,7 @@ After inputting your address and solving the captcha, you can check if you have following `gnokey` command: ```bash -gnokey query bank/balances/ --remote "https://rpc.gno.land:443" +gnokey query bank/balances/ --remote "https://rpc.gno.land:443" ``` If the faucet request was successful, you should see something similar to the @@ -47,7 +48,6 @@ data: "10000000ugnot" ``` ## 2. Visit a realm - For this example, we will use the [Userbook realm](https://gno.land/r/demo/userbook). The Userbook realm is a simple app that allows users to sign up, and keeps track of when they signed up. It also displays the currently signed-up users and the block @@ -55,8 +55,8 @@ height at which they have signed up. ![userbook-default](../../assets/getting-started/local-setup/interacting-with-gnoland/userbook-default.png) -> Note: block heights in this case are unreliable because of the way the Portal Loop -> network works. +> Note: block heights are not correct because of the way the Portal Loop testnet +> works. > Read more [here](../../concepts/portal-loop.md). To see what functions are available to call on the Userbook realm, click @@ -67,7 +67,7 @@ the `[help]` button. By choosing one of the two `gnokey` commands and inputting your address (or keypair name) in the top bar, you will have a ready command to paste into your terminal. For example, the following command will call the `SignUp` function with the -keypair `MyKey`: +keypair `MyKeypair`: ``` gnokey maketx call \ @@ -79,11 +79,11 @@ gnokey maketx call \ -broadcast \ -chainid "portal-loop" \ -remote "https://rpc.gno.land:443" \ -MyKey +MyKeypair ``` -To see what each option and flag in this command does, check out `gnokey` in the -[tooling section](../../gno-tooling/cli/gnokey/gnokey.md). +To see what each option and flag in this command does, read the `gnokey` +[reference page](../../gno-tooling/cli/gnokey.md). ## Conclusion @@ -92,6 +92,6 @@ That's it! Congratulations on executing your first transaction on a Gno network! If the previous transaction was successful, you should be able to see your address on the main page of the Userbook realm. -This concludes the "Local Setup" section. For next steps, see the +This concludes the "Local Setup" tutorial. For next steps, see the [How-to guides section](../../how-to-guides/how-to-guides.md), where you will learn how to write your first realm, package, and much more. diff --git a/docs/gno-tooling/cli/gnokey/working-with-key-pairs.md b/docs/getting-started/local-setup/working-with-key-pairs.md similarity index 75% rename from docs/gno-tooling/cli/gnokey/working-with-key-pairs.md rename to docs/getting-started/local-setup/working-with-key-pairs.md index ba03ca569b4..23516c44e6c 100644 --- a/docs/gno-tooling/cli/gnokey/working-with-key-pairs.md +++ b/docs/getting-started/local-setup/working-with-key-pairs.md @@ -5,16 +5,14 @@ id: working-with-key-pairs # Working with Key Pairs ## Overview - In this tutorial, you will learn how to manage private user keys, which are required for interacting with the gno.land blockchain. You will understand what mnemonics are, how they are used, and how you can make interaction seamless with Gno. ## Prerequisites - -- **`gnokey` installed.** Reference the - [Local Setup](../../../getting-started/local-setup/installation.md#2-installing-the-required-tools) guide for steps +- **`gnokey` installed.** Reference the +[Local Setup](installation.md#2-installing-the-required-tools-) guide for steps ## Listing available keys `gnokey` works by creating a local directory in the filesystem for storing @@ -33,27 +31,27 @@ Example output: USAGE [flags] [...] -gno.land keychain & client +Manages private keys for the node SUBCOMMANDS - add adds key to the keybase - delete deletes a key from the keybase - generate generates a bip39 mnemonic - export exports private key armor - import imports encrypted private key armor - list lists all keys in the keybase - sign signs the given tx document and saves it to disk - verify verifies the document signature - query makes an ABCI query - broadcast broadcasts a signed document - maketx composes a tx document to sign + add Adds key to the keybase + delete Deletes a key from the keybase + generate Generates a bip39 mnemonic + export Exports private key armor + import Imports encrypted private key armor + list Lists all keys in the keybase + sign Signs the document + verify Verifies the document signature + query Makes an ABCI query + broadcast Broadcasts a signed document + maketx Composes a tx document to sign FLAGS - -config ... config file (optional) - -home $XDG_CONFIG/gno home directory - -insecure-password-stdin=false WARNING! take password from stdin - -quiet=false suppress output during execution - -remote 127.0.0.1:26657 remote node URL + -config ... config file (optional) + -home $XDG_CONFIG/gno home directory + -insecure-password-stdin=false WARNING! take password from stdin + -quiet=false suppress output during execution + -remote 127.0.0.1:26657 remote node URL ``` In this example, the directory where `gnokey` will store working data @@ -99,7 +97,7 @@ To generate the mnemonic phrase in the console, you can run: gnokey generate ``` -![gnokey generate](../../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-generate.gif) +![gnokey generate](../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-generate.gif) ## Adding a random private key If we wanted to add a new private key to the keystore, we can run the following @@ -117,7 +115,7 @@ After you enter the password, the `gnokey` tool will add the key to the keystore and return the accompanying [mnemonic phrase](https://en.bitcoin.it/wiki/Seed_phrase), which you should remember somewhere if you want to recover the key at a future point in time. -![gnokey add random](../../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-add-random.gif) +![gnokey add random](../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-add-random.gif) You can check that the key was indeed added to the keystore, by listing available keys: @@ -126,7 +124,7 @@ keys: gnokey list ``` -![gnokey list](../../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-list.gif) +![gnokey list](../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-list.gif) ## Adding a private key using a mnemonic To add a private key to the `gnokey` keystore [using an existing mnemonic](#generating-a-bip39-mnemonic), @@ -142,7 +140,7 @@ Of course, you can replace `MyKey` with whatever name you want for your key. By following the prompts to encrypt the key on disk, and providing a BIP39 mnemonic, we can successfully add the key to the keystore. -![gnokey add mnemonic](../../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-add-mnemonic.gif) +![gnokey add mnemonic](../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-add-mnemonic.gif) ## Deleting a private key To delete a private key from the `gnokey` keystore, we need to know the name or @@ -177,7 +175,7 @@ Follow the prompts presented in the terminal. Namely, you will be asked to decrypt the key in the keystore, and later to encrypt the armor file on disk. It is worth noting that you can also export unencrypted key armor, using the `--unsafe` flag. -![gnokey export](../../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-export.gif) +![gnokey export](../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-export.gif) ## Importing a private key If you have an exported private key file, you can import it into `gnokey` fairly @@ -197,11 +195,4 @@ encryption password for storing the key in the keystore. After executing the previous command, the `gnokey` keystore will have imported `ImportedKey`. -![gnokey import](../../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-import.gif) - -## Conclusion - -That's it! 🎉 - -In this tutorial, you've learned to use `gnokey` for managing Gno keypairs. - +![gnokey import](../../assets/getting-started/local-setup/creating-a-key-pair/gnokey-import.gif) diff --git a/docs/gno-infrastructure/validators/setting-up-a-new-chain.md b/docs/gno-infrastructure/validators/setting-up-a-new-chain.md index 0411fa3b02a..5d440a86684 100644 --- a/docs/gno-infrastructure/validators/setting-up-a-new-chain.md +++ b/docs/gno-infrastructure/validators/setting-up-a-new-chain.md @@ -93,7 +93,7 @@ Let's break down the most important default settings: :::info Resetting the chain As mentioned, the working directory for the node is located in `data-dir`. To reset the chain, you need -to delete this directory and `genesis.json`, then start the node up again. If you are using the default node configuration, you can run +to delete this directory and start the node up again. If you are using the default node configuration, you can run `make fclean` from the `gno.land` sub-folder to delete the `gnoland-data` working directory. ::: diff --git a/docs/gno-tooling/cli/faucet/faucet.md b/docs/gno-tooling/cli/faucet/faucet.md index b069a19740a..4d32f86e9ef 100644 --- a/docs/gno-tooling/cli/faucet/faucet.md +++ b/docs/gno-tooling/cli/faucet/faucet.md @@ -22,7 +22,7 @@ The Gno faucet works by designating a single address as a faucet address that wi Ensure the faucet account will have enough funds by [premining its balance](../../../gno-infrastructure/premining-balances.md) to a high value. In case you do not have an existing address added to `gnokey`, you can consult -the [Working with Key Pairs](../gnokey/working-with-key-pairs.md) guide. +the [Working with Key Pairs](../../../getting-started/local-setup/working-with-key-pairs.md) guide. ## 2. Start the local chain diff --git a/docs/gno-tooling/cli/gnodev.md b/docs/gno-tooling/cli/gnodev.md index f9491fea803..4a1880822fc 100644 --- a/docs/gno-tooling/cli/gnodev.md +++ b/docs/gno-tooling/cli/gnodev.md @@ -105,7 +105,7 @@ A specific deposit amount can also be set with the following pattern: gnodev ./myrealm?deposit=42ugnot ``` -This pattern can be expanded to accommodate both options: +This patten can be expanded to accommodate both options: ``` gnodev ./myrealm?creator=&deposit= diff --git a/docs/gno-tooling/cli/gnokey.md b/docs/gno-tooling/cli/gnokey.md new file mode 100644 index 00000000000..bf110faec5f --- /dev/null +++ b/docs/gno-tooling/cli/gnokey.md @@ -0,0 +1,323 @@ +--- +id: gno-tooling-gnokey +--- + +# gnokey + +Used for account & key management and general interactions with the Gnoland blockchain. + +## Generate a New Seed Phrase + +Generate a new seed phrase and add it to your keybase with the following command. + +```bash +gnokey generate +``` + +## Add a New Key + +You can add a new private key to the keybase using the following command. + +```bash +gnokey add {KEY_NAME} +``` + +#### **Options** + +| Name | Type | Description | +|-------------|------------|----------------------------------------------------------------------------------------| +| `account` | UInt | Account number for HD derivation. | +| `dryrun` | Boolean | Performs action, but doesn't add key to local keystore. | +| `index` | UInt | Address index number for HD derivation. | +| `ledger` | Boolean | Stores a local reference to a private key on a Ledger device. | +| `multisig` | String \[] | Constructs and stores a multisig public key (implies `--pubkey`). | +| `nobackup` | Boolean | Doesn't print out seed phrase (if others are watching the terminal). | +| `nosort` | Boolean | Keys passed to `--multisig` are taken in the order they're supplied. | +| `pubkey` | String | Parses a public key in bech32 format and save it to disk. | +| `recover` | Boolean | Provides seed phrase to recover existing key instead of creating. | +| `threshold` | Int | K out of N required signatures. For use in conjunction with --multisig (default: `1`). | + +> **Test Seed Phrase:** source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast + +### Using a ledger device + +You can add a ledger device using the following command + +> [!NOTE] +> Before running this command make sure your ledger device is connected, with the cosmos app installed and open in it. + +```bash +gnokey add {LEDGER_KEY_NAME} --ledger +``` + +## List all Known Keys + +List all keys stored in your keybase with the following command. + +```bash +gnokey list +``` + +## Delete a Key + +Delete a key from your keybase with the following command. + +```bash +gnokey delete {KEY_NAME} +``` + +#### **Options** + +| Name | Type | Description | +|---------|---------|------------------------------| +| `yes` | Boolean | Skips confirmation prompt. | +| `force` | Boolean | Removes key unconditionally. | + + +## Export a Private Key (Encrypted & Unencrypted) + +Export a private key's (encrypted or unencrypted) armor using the following command. + +```bash +gnokey export +``` + +#### **Options** + +| Name | Type | Description | +|---------------|--------|---------------------------------------------| +| `key` | String | Name or Bech32 address of the private key | +| `output-path` | String | The desired output path for the armor file | +| `unsafe` | Bool | Export the private key armor as unencrypted | + + +## Import a Private Key (Encrypted & Unencrypted) + +Import a private key's (encrypted or unencrypted) armor with the following command. + +```bash +gnokey import +``` + +#### **Options** + +| Name | Type | Description | +|--------------|--------|---------------------------------------------| +| `armor-path` | String | The path to the encrypted armor file. | +| `name` | String | The name of the private key. | +| `unsafe` | Bool | Import the private key armor as unencrypted | + + +## Make an ABCI Query + +Make an ABCI Query with the following command. + +```bash +gnokey query {QUERY_PATH} +``` + +#### **Query** + +| Query Path | Description | Example | +|---------------------------|--------------------------------------------------------------------|----------------------------------------------------------------------------------------| +| `auth/accounts/{ADDRESS}` | Returns information about an account. | `gnokey query auth/accounts/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` | +| `bank/balances/{ADDRESS}` | Returns balances of an account. | `gnokey query bank/balances/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` | +| `vm/qfuncs` | Returns public facing function signatures as JSON. | `gnokey query vm/qfuncs --data "gno.land/r/demo/boards"` | +| `vm/qfile` | Returns the file bytes, or list of files if directory. | `gnokey query vm/qfile --data "gno.land/r/demo/boards"` | +| `vm/qrender` | Calls .Render(path) in readonly mode. | `gnokey query vm/qrender --data "gno.land/r/demo/boards:"` | +| `vm/qeval` | Evaluates any expression in readonly mode and returns the results. | `gnokey query vm/qeval --data "gno.land/r/demo/boards.GetBoardIDFromName("my_board")"` | +| `vm/store` | (not yet supported) Fetches items from the store. | - | +| `vm/package` | (not yet supported) Fetches a package's files. | - | + +#### **Options** + +| Name | Type | Description | +|----------|-----------|------------------------------------------| +| `data` | UInt8 \[] | Queries data bytes. | + + +## Sign and Broadcast a Transaction + +You can sign and broadcast a transaction with the following command. + +```bash +gnokey maketx {SUB_COMMAND} {ADDRESS or KeyName} +``` + +#### **Subcommands** + +| Name | Description | +|----------|------------------------------| +| `addpkg` | Uploads a new package. | +| `call` | Calls a public function. | +| `send` | The amount of coins to send. | + +### `addpkg` + +This subcommand lets you upload a new package. + +```bash +gnokey maketx addpkg \ + -deposit="1ugnot" \ + -gas-fee="1ugnot" \ + -gas-wanted="5000000" \ + -pkgpath={Registered Realm path} \ + -pkgdir={Package folder path} \ + {ADDRESS} \ + > unsigned.tx +``` + +#### **SignBroadcast Options** + +| Name | Type | Description | +|--------------|---------|----------------------------------------------------------------------------------------| +| `gas-wanted` | Int64 | The maximum amount of gas to use for the transaction. | +| `gas-fee` | String | The gas fee to pay for the transaction. | +| `memo` | String | Any descriptive text. | +| `broadcast` | Boolean | Broadcasts the transaction. | +| `chainid` | String | The chainid to sign for (should only be used with `--broadcast`) | +| `simulate` | String | One of `test` (default), `skip` or `only` (should only be used with `--broadcast`)[^1] | + +#### **makeTx AddPackage Options** + +| Name | Type | Description | +|-----------|--------|---------------------------------------| +| `pkgpath` | String | The package path (required). | +| `pkgdir` | String | The path to package files (required). | +| `deposit` | String | The amount of coins to send. | + +### `call` + +This subcommand lets you call any exported function. + +```bash +# Register +gnokey maketx call \ + -gas-fee="1ugnot" \ + -gas-wanted="5000000" \ + -pkgpath="gno.land/r/demo/users" \ + -send="200000000ugnot" \ + -func="Register" \ + -args="" \ + -args={NAME} \ + -args="" \ + {ADDRESS} \ + > unsigned.tx +``` + +:::warning `call` is a state-changing message + +All exported functions, including `Render()`, can be called in two main ways: +`call` and [`query vm/qeval`](#query). + +With `call`, any state change that happened in the function being called will be +applied and persisted in on the blockchain, and the gas used for this call will +be subtracted from the caller balance. + +As opposed to this, an ABCI query, such as `vm/qeval` will not persist state +changes and does not cost gas, only evaluating the expression in read-only mode. + +::: + +#### **SignBroadcast Options** + +| Name | Type | Description | +|--------------|---------|----------------------------------------------------------------------------------------| +| `gas-wanted` | Int64 | The maximum amount of gas to use for the transaction. | +| `gas-fee` | String | The gas fee to pay for the transaction. | +| `memo` | String | Any descriptive text. | +| `broadcast` | Boolean | Broadcasts the transaction. | +| `chainid` | String | The chainid to sign for (should only be used with `--broadcast`) | +| `simulate` | String | One of `test` (default), `skip` or `only` (should only be used with `--broadcast`)[^1] | + +#### **makeTx Call Options** + +| Name | Type | Description | +|-----------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------| +| `send` | String | The amount of coins to send. | +| `pkgpath` | String | The package path (required). | +| `func` | String | The contract to call (required). | +| `args` | String | An argument of the function being called. Can be used multiple times in a single `call` command to accommodate possible multiple function arguments. | + +:::info +Currently, only primitive types are supported as `-args` parameters. This limitation will be addressed in the future. +Alternatively, see how `maketx run` works. +::: + +### `send` + +This subcommand lets you send a native currency to an address. + +```bash +gnokey maketx send \ + -gas-fee="1ugnot" \ + -gas-wanted="5000000" \ + -send={SEND_AMOUNT} \ + -to={TO_ADDRESS} \ + {ADDRESS} \ + > unsigned.tx +``` + +#### **SignBroadcast Options** + +| Name | Type | Description | +|--------------|---------|----------------------------------------------------------------------------------------| +| `gas-wanted` | Int64 | The maximum amount of gas to use for the transaction. | +| `gas-fee` | String | The gas fee to pay for the transaction. | +| `memo` | String | Any descriptive text. | +| `broadcast` | Boolean | Broadcasts the transaction. | +| `chainid` | String | The chainid to sign for (should only be used with `--broadcast`) | +| `simulate` | String | One of `test` (default), `skip` or `only` (should only be used with `--broadcast`)[^1] | + +#### **makeTx Send Options** + +| Name | Type | Description | +|--------|--------|--------------------------| +| `send` | String | Amount of coins to send. | +| `to` | String | The destination address. | + + +## Sign a Document + +Sign a document with the following command. + +```bash +gnokey sign +``` + +#### **Options** + +| Name | Type | Description | +|------------------|---------|------------------------------------------------------------| +| `txpath` | String | The path to file of tx to sign (default: `-`). | +| `chainid` | String | The chainid to sign for (default: `dev`). | +| `number` | UInt | The account number of the account to sign with (required) | +| `sequence` | UInt | The sequence number of the account to sign with (required) | +| `show-signbytes` | Boolean | Shows signature bytes. | + + +## Verify a Document Signature + +Verify a document signature with the following command. + +```bash +gnokey verify +``` + +#### **Options** + +| Name | Type | Description | +|-----------|--------|------------------------------------------| +| `docpath` | String | The path of the document file to verify. | + +## Broadcast a Signed Document + +Broadcast a signed document with the following command. + +```bash +gnokey broadcast {signed transaction file document} +``` + +[^1]: `only` simulates the transaction as a "dry run" (ie. without committing to + the chain), `test` performs simulation and, if successful, commits the + transaction, `skip` skips simulation entirely and commits directly. diff --git a/docs/gno-tooling/cli/gnokey/full-security-tx.md b/docs/gno-tooling/cli/gnokey/full-security-tx.md deleted file mode 100644 index bccddb30b8a..00000000000 --- a/docs/gno-tooling/cli/gnokey/full-security-tx.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -id: full-security-tx ---- - -# Making an airgapped transaction - -## Prerequisites - -- **`gnokey` installed.** Reference the - [Local Setup](../../../getting-started/local-setup/installation.md#2-installing-the-required-tools) guide for steps - -## Overview - -`gnokey` provides a way to create a transaction, sign it, and later -broadcast it to a chain in the most secure fashion. This approach, while more -complicated than the standard approach shown [in a previous tutorial](./state-changing-calls.md), -grants full control and provides [airgap](https://en.wikipedia.org/wiki/Air_gap_(networking)) -support. - -By separating the signing and the broadcasting steps of submitting a transaction, -users can make sure that the signing happens in a secure, offline environment, -keeping private keys away from possible exposure to attacks coming from the -internet. - -The intended purpose of this functionality is to provide maximum security when -signing and broadcasting a transaction. In practice, this procedure should take -place on two separate machines controlled by the holder of the keys, one with -access to the internet (`Machine A`), and the other one without (`Machine B`), -with the separation of steps as follows: -1. `Machine A`: Fetch account information from the chain -2. `Machine B`: Create an unsigned transaction locally -3. `Machine B`: Sign the transaction -4. `Machine A`: Broadcast the transaction - -## 1. Fetching account information from the chain - -First, we need to fetch data for the account we are using to sign the transaction, -using the [auth/accounts](./querying-a-network.md#authaccounts) query: - -```bash -gnokey query auth/accounts/ -remote "https://rpc.gno.land:443" -``` - -We need to extract the account number and sequence from the output: - -```bash -height: 0 -data: { - "BaseAccount": { - "address": "g1zzqd6phlfx0a809vhmykg5c6m44ap9756s7cjj", - "coins": "10000000ugnot", - "public_key": null, - "account_number": "468", - "sequence": "0" - } -} -``` - -In this case, the account number is `468`, and the sequence (nonce) is `0`. We -will need these values to sign the transaction later. These pieces of information -are crucial during the signing process, as they are included in the signature -of the transaction, preventing replay attacks. - -## 2. Creating an unsigned transaction locally - -To create the transaction you want, you can use the [`call` API](./state-changing-calls.md#call), -without the `-broadcast` flag, while redirecting the output to a local file: - -```bash -gnokey maketx call \ --pkgpath "gno.land/r/demo/userbook" \ --func "SignUp" \ --gas-fee 1000000ugnot \ --gas-wanted 2000000 \ -mykey > userbook.tx -``` - -This will create a `userbook.tx` file with a null `signature` field. -Now we are ready to sign the transaction. - -## 3. Signing the transaction - -To add a signature to the transaction, we can use the `gnokey sign` subcommand. -To sign, we must set the correct flags for the subcommand: -- `-tx-path` - path to the transaction file to sign, in our case, `userbook.tx` -- `-chainid` - id of the chain to sign for -- `-account-number` - number of the account fetched previously -- `-account-sequence` - sequence of the account fetched previously - -```bash -gnokey sign \ --tx-path userbook.tx \ --chainid "portal-loop" \ --account-number 468 \ --account-sequence 0 \ -mykey -``` - -After inputting the correct values, `gnokey` will ask for the password to decrypt -the keypair. Once we input the password, we should receive the message that the -signing was completed. If we open the `userbook.tx` file, we will be able to see -that the signature field has been populated. - -We are now ready to broadcast this transaction to the chain. - -## 4. Broadcasting the transaction - -To broadcast the signed transaction to the chain, we can use the `gnokey broadcast` -subcommand, giving it the path to the signed transaction: - -```bash -gnokey broadcast -remote "https://rpc.gno.land:443" userbook.tx -``` - -In this case, we do not need to specify a keypair, as the transaction has already -been signed in a previous step and `gnokey` is only sending it to the RPC endpoint. - -## Verifying a transaction's signature - -To verify a transaction's signature is correct, you can use the `gnokey verify` -subcommand. We can provide the path to the transaction document using the `-docpath` -flag, provide the key we signed the transaction with, and the signature itself. -Make sure the signature is in the `hex` format. - -```bash -gnokey verify -docpath userbook.tx mykey -``` - -## Conclusion - -That's it! 🎉 - -In this tutorial, you've learned to use `gnokey` for creating maximum-security -transactions in an airgapped manner. diff --git a/docs/gno-tooling/cli/gnokey/gnokey.md b/docs/gno-tooling/cli/gnokey/gnokey.md deleted file mode 100644 index 7344f9b539c..00000000000 --- a/docs/gno-tooling/cli/gnokey/gnokey.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -id: gnokey ---- - -# `gnokey` - -## Overview - -In this section, you will learn how to use the `gnokey` binary. `gnokey` is the -gno.land CLI keychain and client, and it allows you to do 4 main things: -- Manage Gno keypairs -- Send state-changing calls (transactions) -- Query a gno.land network -- Sign and broadcast transactions with [airgap protection](https://en.wikipedia.org/wiki/Air_gap_(networking)) - -Check out the rest of this section to learn how to do all of these. diff --git a/docs/gno-tooling/cli/gnokey/querying-a-network.md b/docs/gno-tooling/cli/gnokey/querying-a-network.md deleted file mode 100644 index 1bb1bb8275f..00000000000 --- a/docs/gno-tooling/cli/gnokey/querying-a-network.md +++ /dev/null @@ -1,233 +0,0 @@ ---- -id: querying-a-network ---- - -# Querying a gno.land network - -## Prerequisites - -- **`gnokey` installed.** Reference the - [Local Setup](../../../getting-started/local-setup/installation.md#2-installing-the-required-tools) guide for steps - -## Overview - -gno.land and `gnokey` support ABCI queries. Using ABCI queries, you can query the state of -a gno.land network without spending any gas. All queries need to be pointed towards -a specific remote address from which the state will be retrieved. - -To send ABCI queries, you can use the `gnokey query` subcommand, and provide it -with the appropriate query. The `query` subcommand allows us to send different -types of queries to a gno.land network. - -Below is a list of queries a user can make with `gnokey`: -- `auth/accounts/{ADDRESS}` - returns information about an account -- `bank/balances/{ADDRESS}` - returns balances of an account -- `vm/qfuncs` - returns the exported functions for a given pkgpath -- `vm/qfile` - returns package contents for a given pkgpath -- `vm/qeval` - evaluates an expression in read-only mode on and returns the results -- `vm/qrender` - shorthand for evaluating `vm/qeval Render("")` for a given pkgpath - -Let's see how we can use them. - -## `auth/accounts` - -We can obtain information about a specific address using this subquery. To call it, -we can run the following command: - -```bash -gnokey query auth/accounts/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -remote https://rpc.gno.land:443 -``` - -With this, we are asking the Portal Loop network to deliver information about the -specified address. If everything went correctly, we should get output similar to the following: - -```bash -height: 0 -data: { - "BaseAccount": { - "address": "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5", - "coins": "227984898927ugnot", - "public_key": { - "@type": "/tm.PubKeySecp256k1", - "value": "A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y" - }, - "account_number": "0", - "sequence": "12" - } -} -``` - -The return data will contain the following fields: -- `height` - the height at which the query was executed. This is currently not - supported and is `0` by default. -- `data` - contains the result of the query. - -The `data` field returns a `BaseAccount`, which is the main struct used in [TM2](../../../concepts/tendermint2.md) -to hold account data. It contains the following information: -- `address` - the address of the account -- `coins` - the list of coins the account owns -- `public_key` - the TM2 public key of the account, from which the address is derived -- `account_number` - a unique identifier for the account on the gno.land chain -- `sequence` - a nonce, used for protection against replay attacks - -## `bank/balances` - -With this query, we can fetch [coin](../../../concepts/stdlibs/coin.md) balances -of a specific account. To call it, we can run the following command: - -```bash -gnokey query bank/balances/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -remote https://rpc.gno.land:443 -``` - -If everything went correctly, we should get an output similar to the following: - -```bash -height: 0 -data: "227984898927ugnot" -``` - -The data field will contain the coins the address owns. - -## `vm/qfuncs` - -Using the `vm/qfuncs` query, we can fetch exported functions from a specific package -path. To specify the path we want to query, we can use the `-data` flag: - -```bash -gnokey query vm/qfuncs --data "gno.land/r/demo/wugnot" -remote https://rpc.gno.land:443 -``` - -The output is a string containing all exported functions for the `wugnot` realm: - -```json -height: 0 -data: [ - { - "FuncName": "Deposit", - "Params": null, - "Results": null - }, - { - "FuncName": "Withdraw", - "Params": [ - { - "Name": "amount", - "Type": "uint64", - "Value": "" - } - ], - "Results": null - }, - // other functions -] -``` - -## `vm/qfile` - -With the `vm/qfile` query, we can fetch files and their content found on a -specific package path. To specify the path we want to query, we can use the -`-data` flag: - -```bash -gnokey query vm/qfile -data "gno.land/r/demo/wugnot" -remote https://rpc.gno.land:443 -``` - -If the `-data` field contains only the package path, the output is a list of all -files found within the `wugnot` realm: - -```bash -height: 0 -data: gno.mod -wugnot.gno -z0_filetest.gno -``` - -If the `-data` field also specifies a file name after the path, the source code -of the file will be retrieved: - -```bash -gnokey query vm/qfile -data "gno.land/r/demo/wugnot/wugnot.gno" -remote https://rpc.gno.land:443 -``` - -Output: -```bash -height: 0 -data: package wugnot - -import ( - "std" - "strings" - - "gno.land/p/demo/grc/grc20" - "gno.land/p/demo/ufmt" - pusers "gno.land/p/demo/users" - "gno.land/r/demo/users" -) - -var ( - banker *grc20.Banker = grc20.NewBanker("wrapped GNOT", "wugnot", 0) - Token = banker.Token() -) - -const ( - ugnotMinDeposit uint64 = 1000 - wugnotMinDeposit uint64 = 1 -) -... -``` - -## `vm/qeval` - -`vm/qeval` allows us to evaluate a call to an exported function without using gas, -in read-only mode. For example: - -```bash -gnokey query vm/qeval -remote https://rpc.gno.land:443 -data "gno.land/r/demo/wugnot.BalanceOf(\"g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\")" -``` - -This command will return the `wugnot` balance of the above address without using gas. -Properly escaping quotation marks for string arguments is currently required. - -Currently, `vm/qeval` only supports primitive types in expressions. - -## `vm/qrender` - -`vm/qrender` is an alias for executing `vm/qeval` on the `Render("")` function. -We can use it like this: - -```bash -gnokey query vm/qrender --data "gno.land/r/demo/wugnot:" -remote https://rpc.gno.land:443 -``` - -Running this command will display the current `Render()` output of the WUGNOT -realm, which is also displayed by default on the [realm's page](https://gno.land/r/demo/wugnot): - -```bash -height: 0 -data: # wrapped GNOT ($wugnot) - -* **Decimals**: 0 -* **Total supply**: 5012404 -* **Known accounts**: 2 -``` - -:::info Specifying a path to `Render()` - -To call the `vm/qrender` query with a specific path, use the `:` syntax. -For example, the `wugnot` realm provides a way to display the balance of a specific -address in its `Render()` function. We can fetch the balance of an account by -providing the following custom pattern to the `wugnot` realm: - -```bash -gnokey query vm/qrender --data "gno.land/r/demo/wugnot:balance/g125em6arxsnj49vx35f0n0z34putv5ty3376fg5" -remote https://rpc.gno.land:443 -``` - -To see how this was achieved, check out `wugnot`'s `Render()` function. -::: - -## Conclusion - -That's it! 🎉 - -In this tutorial, you've learned to use `gnokey` to query a gno.land -network. diff --git a/docs/gno-tooling/cli/gnokey/state-changing-calls.md b/docs/gno-tooling/cli/gnokey/state-changing-calls.md deleted file mode 100644 index 79a777cca51..00000000000 --- a/docs/gno-tooling/cli/gnokey/state-changing-calls.md +++ /dev/null @@ -1,466 +0,0 @@ ---- -id: state-changing-calls ---- - -# Making state-changing calls (transactions) - -## Prerequisites - -- **`gnokey` installed.** Reference the - [Local Setup](../../../getting-started/local-setup/installation.md#2-installing-the-required-tools) guide for steps - -## Overview - -In Gno, there are four types of messages that can change on-chain state: -- `AddPackage` - adds new code to the chain -- `Call` - calls a specific path and function on the chain -- `Send` - sends coins from one address to another -- `Run` - executes a Gno script against on-chain code - -A gno.land transaction contains two main things: -- A base configuration where variables such as `gas-fee`, `gas-wanted`, and others - are defined -- A list of messages to execute on the chain - -Currently, `gnokey` supports single-message transactions, while multiple-message -transactions can be created in Go programs, supported by the -[gnoclient](../../../reference/gnoclient/gnoclient.md) package. - -We will need some testnet coins (GNOTs) for each state-changing call. Visit the [Faucet -Hub](https://faucet.gno.land) to get GNOTs for the Gno testnets that are currently live. - -Let's delve deeper into each of these message types. - -## `AddPackage` - -In case you want to upload new code to the chain, you can use the `AddPackage` -message type. You can send an `AddPackage` transaction with `gnokey` using the -following command: - -```bash -gnokey maketx addpkg -``` - -To understand how to use this subcommand better, let's write a simple "Hello world" -[pure package](../../../concepts/packages.md). First, let's create a folder which will -store our example code. - -```bash -└── example/ -``` - -Then, let's create a `hello_world.gno` file under the `p/` folder: - -```bash -cd example -mkdir p/ && cd p -touch hello_world.gno -``` - -Now, we should have the following folder structure: - -```bash -└── example/ -│ └── p/ -│ └── hello_world.gno -``` - -In the `hello_world.gno` file, add the following code: - -```go -package hello_world - -func Hello() string { - return "Hello, world!" -} -``` - -We are now ready to upload this package to the chain. To do this, we must set the -correct flags for the `addpkg` subcommand. - -The `addpkg` subcommmand uses the following flags and arguments: -- `-pkgpath` - on-chain path where your code will be uploaded to -- `-pkgdir` - local path where your is located -- `-broadcast` - enables broadcasting the transaction to the chain -- `-send` - a deposit amount of GNOT to send along with the transaction -- `-gas-wanted` - the upper limit for units of gas for the execution of the - transaction -- `-gas-fee` - amount of GNOTs to pay per gas unit -- `-chain-id` - id of the chain that we are sending the transaction to -- `-remote` - specifies the remote node RPC listener address - -The `-pkgpath` and `-pkgdir` flags are unique to the `addpkg` subcommand, while -`-broadcast`,`-send`, `-gas-wanted`, `-gas-fee`, `-chain-id`, and `-remote` are -used for setting the base transaction configuration. These flags will be repeated -throughout the tutorial. - -Next, let's configure the `addpkg` subcommand to publish this package to the -[Portal Loop](../../../concepts/portal-loop.md) testnet. Assuming we are in -the `example/p/` folder, the command will look like this: - -```bash -gnokey maketx addpkg \ --pkgpath "gno.land/p//hello_world" \ --pkgdir "." \ --send "" \ --gas-fee 10000000ugnot \ --gas-wanted 8000000 \ --broadcast \ --chainid portal-loop \ --remote "https://rpc.gno.land:443" -``` - -Once we have added a desired [namespace](../../../concepts/namespaces.md) to upload the package to, we can specify -a keypair name to use to execute the transaction: - -```bash -gnokey maketx addpkg \ --pkgpath "gno.land/p/examplenamespace/hello_world" \ --pkgdir "." \ --send "" \ --gas-fee 10000000ugnot \ --gas-wanted 200000 \ --broadcast \ --chainid portal-loop \ --remote "https://rpc.gno.land:443" -mykey -``` - -If the transaction was successful, you will get output from `gnokey` that is similar to the following: - -``` -OK! -GAS WANTED: 200000 -GAS USED: 117564 -HEIGHT: 3990 -EVENTS: [] -TX HASH: Ni8Oq5dP0leoT/IRkKUKT18iTv8KLL3bH8OFZiV79kM= -``` - -Let's analyze the output, which is standard for any `gnokey` transaction: -- `GAS WANTED: 200000` - the original amount of gas specified for the transaction -- `GAS USED: 117564` - the gas used to execute the transaction -- `HEIGHT: 3990` - the block number at which the transaction was executed at -- `EVENTS: []` - [Gno events](../../../concepts/stdlibs/events.md) emitted by the transaction, in this case, none -- `TX HASH: Ni8Oq5dP0leoT/IRkKUKT18iTv8KLL3bH8OFZiV79kM=` - the hash of the transaction - -Congratulations! You have just uploaded a pure package to the Portal Loop network. -If you wish to deploy to a different network, find the list of all network -configurations in the [Network Configuration](../../../reference/network-config.md) section. - -## `Call` - -The `Call` message type is used to call any exported realm function. -You can send a `Call` transaction with `gnokey` using the following command: - -```bash -gnokey maketx call -``` - -:::info `Call` uses gas - -Using `Call` to call an exported function will use up gas, even if the function -does not modify on-chain state. If you are calling such a function, you can use -the [`query` functionality](./querying-a-network.md) for a read-only call which -does not use gas. - -::: - -For this example, we will call the `wugnot` realm, which wraps GNOTs to a -GRC20-compatible token called `wugnot`. We can find this realm deployed on the -[Portal Loop](../../../concepts/portal-loop.md) testnet, under the `gno.land/r/demo/wugnot` path. - -We will wrap `1000ugnot` into the equivalent in `wugnot`. To do this, we can call -the `Deposit()` function found in the `wugnot` realm. As previously, we will -configure the `maketx call` subcommand: - -```bash -gnokey maketx call \ --pkgpath "gno.land/r/demo/wugnot" \ --func "Deposit" \ --send "1000ugnot" \ --gas-fee 10000000ugnot \ --gas-wanted 2000000 \ --broadcast \ --chainid portal-loop \ --remote "https://rpc.gno.land:443" \ -mykey -``` - -In this command, we have specified three main things: -- The path where the realm lives on-chain with the `-pkgpath` flag -- The function that we want to call on the realm with the `-func` flag -- The amount of `ugnot` we want to send to be wrapped, using the `-send` flag - -Apart from this, we have also specified the Portal Loop chain ID, `portal-loop`, -as well as the Portal Loop remote address, `https://rpc.gno.land:443`. - -After running the command, we can expect an output similar to the following: -```bash -OK! -GAS WANTED: 2000000 -GAS USED: 489528 -HEIGHT: 24142 -EVENTS: [{"type":"Transfer","attrs":[{"key":"from","value":""},{"key":"to","value":"g125em6arxsnj49vx35f0n0z34putv5ty3376fg5"},{"key":"value","value":"1000"}],"pkg_path":"gno.land/r/demo/wugnot","func":"Mint"}] -TX HASH: Ni8Oq5dP0leoT/IRkKUKT18iTv8KLL3bH8OFZiV79kM= -``` - -In this case, we can see that the `Deposit()` function emitted an -[event](../../../concepts/stdlibs/events.md) that tells us more about what -happened during the transaction. - -After broadcasting the transaction, we can verify that we have the amount of `wugnot` we expect. We -can call the `BalanceOf()` function in the same realm: - -```bash -gnokey maketx call \ --pkgpath "gno.land/r/demo/wugnot" \ --func "BalanceOf" \ --args "" \ --gas-fee 10000000ugnot \ --gas-wanted 2000000 \ --broadcast \ --chainid portal-loop \ --remote "https://rpc.gno.land:443" \ -mykey -``` - -If everything was successful, we should get something similar to the following -output: - -``` -(1000 uint64) - -OK! -GAS WANTED: 2000000 -GAS USED: 396457 -HEIGHT: 64839 -EVENTS: [] -TX HASH: gQP9fJYrZMTK3GgRiio3/V35smzg/jJ62q7t4TLpdV4= -``` - -At the top, you will see the output of the transaction, specifying the value and -type of the return argument. - -In this case, we used `maketx call` to call a read-only function, which simply -checks the `wugnot` balance of a specific address. This is discouraged, as -`maketx call` actually uses gas. To call a read-only function without spending gas, -check out the `vm/qeval` query in the [Querying a network](./querying-a-network.md#vmqeval) section. - -## `Send` - -We can use the `Send` message type to access the TM2 [Banker](../../../concepts/stdlibs/banker.md) -directly and transfer coins from one Gno address to another. - -Coins, such as GNOTs, are always formatted in the following way: - -``` - -100ugnot -``` - -For this example, let's transfer some GNOTs. Just like before, we can configure -our `maketx send` subcommand: -```bash -gnokey maketx send \ --to g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 \ --send 100ugnot \ --gas-fee 10000000ugnot \ --gas-wanted 2000000 \ --broadcast \ --chainid portal-loop \ --remote "https://rpc.gno.land:443" \ -mykey -``` - -Here, we have set the `-to` & `-send` flags to match the recipient, in this case -the publicly-known `test1` address, and `100ugnot` for the coins we want to send, -respectively. - -To check the balance of a specific address, check out the `bank/balances` query -in the [Querying a network](./querying-a-network.md#bankbalances) section. - -## `Run` - -With the `Run` message, you can write a snippet of Gno code and run it against -code on the chain. For this example, we will use the [Userbook realm](https://gno.land/r/demo/userbook), -which simply allows you to register the fact that you have interacted with it. -It contains a simple `SignUp()` function, which we will call with `Run`. - -To understand how to use the `Run` message better, let's write a simple `script.gno` -file. First, create a folder which will store our script. - -```bash -└── example/ -``` - -Then, let's create a `script.gno` file: - -```bash -cd example -touch script.gno -``` - -Now, we should have the following folder structure: - -```bash -└── example/ -│ └── script.gno -``` - -In the `script.gno` file, first define the package to be `main`. Then we can import -the Userbook realm and define a `main()` function with no return values which will -be automatically detected and run. In it, we can call the `SignUp()` function. - -```go -package main - -import "gno.land/r/demo/userbook" - -func main() { - println(userbook.SignUp()) -} -``` - -Now we will be able to provide this to the `maketx run` subcommand: -```bash -gnokey maketx run \ --gas-fee 1000000ugnot \ --gas-wanted 20000000 \ --broadcast \ --chainid portal-loop \ --remote "https://rpc.gno.land:443" \ -mykey ./script.gno -``` - -After running this command, the chain will execute the script and apply any state -changes. Additionally, by using `println`, which is only available in the `Run` -& testing context, we will be able to see the return value of the function called. - -### The power of `Run` - -Specifically, the above example could have been replaced with a simple `maketx call` -call. The full potential of run comes out in three specific cases: -1. Calling realm functions multiple times in a loop -2. Calling functions with non-primitive input arguments -3. Calling methods on exported variables - -Let's look at each of these cases in detail. To demonstrate, we'll make a call -to the following example realm: - -```go -package foo - -import "gno.land/p/demo/ufmt" - -var ( - MainFoo *Foo - foos []*Foo -) - -type Foo struct { - bar string - baz int -} - -func init() { - MainFoo = &Foo{bar: "mainBar", baz: 0} -} - -func (f *Foo) String() string { - return ufmt.Sprintf("Foo - (bar: %s) - (baz: %d)\n\n", f.bar, f.baz) -} - -func NewFoo(bar string, baz int) *Foo { - return &Foo{bar: bar, baz: baz} -} - -func AddFoos(multipleFoos []*Foo) { - foos = append(foos, multipleFoos...) -} - -func Render(_ string) string { - var output string - - for _, f := range foos { - output += f.String() - } - - return output -} -``` - -This realm is deployed to [`gno.land/r/docs/examples/run/foo`](https://gno.land/r/docs/examples/run/foo/package.gno) -on the Portal Loop testnet. - -1. Calling realm functions multiple times in a loop: -```go -package main - -import ( - "gno.land/r/docs/examples/run/foo" -) - -func main() { - for i := 0; i < 5; i++ { - println(foo.Render("")) - } -} -``` - -2. Calling functions with non-primitive input arguments: - -Currently, `Call` only supports primitives for arguments. With `Run`, these -limitations are removed; we can execute a function that takes in a struct, array, -or even an array of structs. - -We are unable to call `AddFoos()` with the `Call` message type, while with `Run`, -we can: - -```go -package main - -import ( - "strconv" - - "gno.land/r/docs/examples/run/foo" -) - -func main() { - var multipleFoos []*foo.Foo - - for i := 0; i < 5; i++ { - newFoo := foo.NewFoo( - "bar"+strconv.Itoa(i), - i, - ) - - multipleFoos = append(multipleFoos, newFoo) - } - - foo.AddFoos(multipleFoos) -} - -``` - -3. Calling methods on exported variables: - -```go -package main - -import "gno.land/r/docs/examples/run/foo" - -func main() { - println(foo.MainFoo.String()) -} -``` - -Finally, we can call methods that are on top-level objects in case they exist, -which is not currently possible with the `Call` message. - -## Conclusion - -That's it! 🎉 - -In this tutorial, you've learned to use `gnokey` for sending multiple types of -state-changing calls to a gno.land chain. diff --git a/docs/how-to-guides/connecting-from-go.md b/docs/how-to-guides/connecting-from-go.md index 971007e5cef..4926f700a4d 100644 --- a/docs/how-to-guides/connecting-from-go.md +++ b/docs/how-to-guides/connecting-from-go.md @@ -15,7 +15,7 @@ For this guide, we will build a small Go app that will: ## Prerequisites - A local gno.land keypair generated using -[gnokey](../gno-tooling/cli/gnokey/working-with-key-pairs.md) +[gnokey](../getting-started/local-setup/working-with-key-pairs.md) ## Setup @@ -223,21 +223,11 @@ message type. We will use the wrapped ugnot realm for this example, wrapping `1000000ugnot` (1 $GNOT) for demonstration purposes. ```go -import ( - ... - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" - "github.com/gnolang/gno/tm2/pkg/std" -) -``` - -```go -msg := vm.MsgCall{ - Caller: addr, // address of the caller (signer) - PkgPath: "gno.land/r/demo/wugnot", // wrapped ugnot realm path - Func: "Deposit", // function to call - Args: nil, // arguments in string format - Send: std.Coins{{Denom: ugnot.Denom, Amount: int64(1000000)}}, // coins to send along with transaction +msg := gnoclient.MsgCall{ + PkgPath: "gno.land/r/demo/wugnot", // wrapped ugnot realm path + FuncName: "Deposit", // function to call + Args: nil, // arguments in string format + Send: "1000000ugnot", // coins to send along with transaction } ``` diff --git a/docs/how-to-guides/deploy.md b/docs/how-to-guides/deploy.md index 1e27ccd0cad..620a5664f7c 100644 --- a/docs/how-to-guides/deploy.md +++ b/docs/how-to-guides/deploy.md @@ -129,7 +129,7 @@ given in the `--gas-wanted` flag to cover the deployment cost. Regardless of whether you're deploying a realm or a package, you will be using `gnokey`'s `maketx addpkg` - the usage of `maketx addpkg` in both cases is identical. To read more about the `maketx addpkg` -subcommand, view the `gnokey` [reference](../gno-tooling/cli/gnokey/state-changing-calls.md#addpackage). +subcommand, view the `gnokey` [reference](../gno-tooling/cli/gnokey.md#addpkg). ::: diff --git a/docs/reference/gnoclient/gnoclient.md b/docs/reference/gnoclient/gnoclient.md index 672a3772bb7..0c6c0d87308 100644 --- a/docs/reference/gnoclient/gnoclient.md +++ b/docs/reference/gnoclient/gnoclient.md @@ -14,7 +14,7 @@ APIs for common functionality. - Use local keystore to sign & broadcast transactions containing any type of Gno message - Sign & broadcast transactions with batch messages -- Use [ABCI queries](../../gno-tooling/cli/gnokey/querying-a-network.md) in +- Use [ABCI queries](../../gno-tooling/cli/gnokey.md#make-an-abci-query) in your Go code ## Installation @@ -30,5 +30,5 @@ To see the full reference documentation for the `gnoclient` package, we recommen visiting the [`gnoclient godoc page`](https://gnolang.github.io/gno/github.com/gnolang/gno@v0.0.0/gno.land/pkg/gnoclient.html). For a tutorial on how to use the `gnoclient` package, check out -["How to connect a Go app to gno.land"](../../how-to-guides/connecting-from-go.md). +["How to connect a Go app to gno.land"](../../how-to-guides/connecting-from-go.md) diff --git a/docs/reference/network-config.md b/docs/reference/network-config.md index 6d4fc9ea14a..0dacc8e80d7 100644 --- a/docs/reference/network-config.md +++ b/docs/reference/network-config.md @@ -9,7 +9,7 @@ id: network-config | Portal Loop | https://rpc.gno.land:443 | `portal-loop` | | Test4 | https://rpc.test4.gno.land:443 | `test4` | | Test3 | https://rpc.test3.gno.land:443 | `test3` | -| Staging | https://rpc.staging.gno.land:443 | `staging` | +| Staging | http://rpc.staging.gno.land:36657 | `staging` | ### WebSocket endpoints All networks follow the same pattern for websocket connections: diff --git a/docs/reference/stdlibs/std/chain.md b/docs/reference/stdlibs/std/chain.md index 089de682cfd..f8d3cba13bb 100644 --- a/docs/reference/stdlibs/std/chain.md +++ b/docs/reference/stdlibs/std/chain.md @@ -85,7 +85,7 @@ Returns the original signer of the transaction. #### Usage ```go -caller := std.GetOrigCaller() +caller := std.GetOrigSend() ``` --- diff --git a/examples/gno.land/p/demo/avlhelpers/avlhelpers.gno b/examples/gno.land/p/demo/avlhelpers/avlhelpers.gno deleted file mode 100644 index 27842932dd3..00000000000 --- a/examples/gno.land/p/demo/avlhelpers/avlhelpers.gno +++ /dev/null @@ -1,41 +0,0 @@ -package avlhelpers - -import ( - "gno.land/p/demo/avl" -) - -// Iterate the keys in-order starting from the given prefix. -// It calls the provided callback function for each key-value pair encountered. -// If the callback returns true, the iteration is stopped. -// The prefix and keys are treated as byte strings, ignoring possible multi-byte Unicode runes. -func IterateByteStringKeysByPrefix(tree avl.Tree, prefix string, cb avl.IterCbFn) { - end := "" - n := len(prefix) - // To make the end of the search, increment the final character ASCII by one. - for n > 0 { - if ascii := int(prefix[n-1]); ascii < 0xff { - end = prefix[0:n-1] + string(ascii+1) - break - } - - // The last character is 0xff. Try the previous character. - n-- - } - - tree.Iterate(prefix, end, cb) -} - -// Get a list of keys starting from the given prefix. Limit the -// number of results to maxResults. -// The prefix and keys are treated as byte strings, ignoring possible multi-byte Unicode runes. -func ListByteStringKeysByPrefix(tree avl.Tree, prefix string, maxResults int) []string { - result := []string{} - IterateByteStringKeysByPrefix(tree, prefix, func(key string, value interface{}) bool { - result = append(result, key) - if len(result) >= maxResults { - return true - } - return false - }) - return result -} diff --git a/examples/gno.land/p/demo/avlhelpers/gno.mod b/examples/gno.land/p/demo/avlhelpers/gno.mod deleted file mode 100644 index 559f60975cf..00000000000 --- a/examples/gno.land/p/demo/avlhelpers/gno.mod +++ /dev/null @@ -1,3 +0,0 @@ -module gno.land/p/demo/avlhelpers - -require gno.land/p/demo/avl v0.0.0-latest diff --git a/examples/gno.land/p/demo/avlhelpers/z_0_filetest.gno b/examples/gno.land/p/demo/avlhelpers/z_0_filetest.gno deleted file mode 100644 index 1c7873e297a..00000000000 --- a/examples/gno.land/p/demo/avlhelpers/z_0_filetest.gno +++ /dev/null @@ -1,91 +0,0 @@ -// PKGPATH: gno.land/r/test -package test - -import ( - "encoding/hex" - - "gno.land/p/demo/avl" - "gno.land/p/demo/avlhelpers" - "gno.land/p/demo/ufmt" -) - -func main() { - tree := avl.Tree{} - - { - // Empty tree. - matches := avlhelpers.ListByteStringKeysByPrefix(tree, "", 10) - println(ufmt.Sprintf("# matches: %d", len(matches))) - } - - tree.Set("alice", "") - tree.Set("andy", "") - tree.Set("bob", "") - - { - // Match only alice. - matches := avlhelpers.ListByteStringKeysByPrefix(tree, "al", 10) - println(ufmt.Sprintf("# matches: %d", len(matches))) - println("match: " + matches[0]) - } - - { - // Match alice and andy. - matches := avlhelpers.ListByteStringKeysByPrefix(tree, "a", 10) - println(ufmt.Sprintf("# matches: %d", len(matches))) - println("match: " + matches[0]) - println("match: " + matches[1]) - } - - { - // Match alice and andy limited to 1. - matches := avlhelpers.ListByteStringKeysByPrefix(tree, "a", 1) - println(ufmt.Sprintf("# matches: %d", len(matches))) - println("match: " + matches[0]) - } - - tree = avl.Tree{} - tree.Set("a\xff", "") - tree.Set("a\xff\xff", "") - tree.Set("b", "") - tree.Set("\xff\xff\x00", "") - - { - // Match only "a\xff\xff". - matches := avlhelpers.ListByteStringKeysByPrefix(tree, "a\xff\xff", 10) - println(ufmt.Sprintf("# matches: %d", len(matches))) - println(ufmt.Sprintf("match: %s", hex.EncodeToString([]byte(matches[0])))) - } - - { - // Match "a\xff" and "a\xff\xff". - matches := avlhelpers.ListByteStringKeysByPrefix(tree, "a\xff", 10) - println(ufmt.Sprintf("# matches: %d", len(matches))) - println(ufmt.Sprintf("match: %s", hex.EncodeToString([]byte(matches[0])))) - println(ufmt.Sprintf("match: %s", hex.EncodeToString([]byte(matches[1])))) - } - - { - // Edge case: Match only "\xff\xff\x00". - matches := avlhelpers.ListByteStringKeysByPrefix(tree, "\xff\xff", 10) - println(ufmt.Sprintf("# matches: %d", len(matches))) - println(ufmt.Sprintf("match: %s", hex.EncodeToString([]byte(matches[0])))) - } -} - -// Output: -// # matches: 0 -// # matches: 1 -// match: alice -// # matches: 2 -// match: alice -// match: andy -// # matches: 1 -// match: alice -// # matches: 1 -// match: 61ffff -// # matches: 2 -// match: 61ff -// match: 61ffff -// # matches: 1 -// match: ffff00 diff --git a/examples/gno.land/p/demo/entropy/entropy.gno b/examples/gno.land/p/demo/entropy/entropy.gno deleted file mode 100644 index 5e35b8c7227..00000000000 --- a/examples/gno.land/p/demo/entropy/entropy.gno +++ /dev/null @@ -1,89 +0,0 @@ -// Entropy generates fully deterministic, cost-effective, and hard to guess -// numbers. -// -// It is designed both for single-usage, like seeding math/rand or for being -// reused which increases the entropy and its cost effectiveness. -// -// Disclaimer: this package is unsafe and won't prevent others to guess values -// in advance. -// -// It uses the Bernstein's hash djb2 to be CPU-cycle efficient. -package entropy - -import ( - "math" - "std" - "time" -) - -type Instance struct { - value uint32 -} - -func New() *Instance { - r := Instance{value: 5381} - r.addEntropy() - return &r -} - -func FromSeed(seed uint32) *Instance { - r := Instance{value: seed} - r.addEntropy() - return &r -} - -func (i *Instance) Seed() uint32 { - return i.value -} - -func (i *Instance) djb2String(input string) { - for _, c := range input { - i.djb2Uint32(uint32(c)) - } -} - -// super fast random algorithm. -// http://www.cse.yorku.ca/~oz/hash.html -func (i *Instance) djb2Uint32(input uint32) { - i.value = (i.value << 5) + i.value + input -} - -// AddEntropy uses various runtime variables to add entropy to the existing seed. -func (i *Instance) addEntropy() { - // FIXME: reapply the 5381 initial value? - - // inherit previous entropy - // nothing to do - - // handle callers - { - caller1 := std.GetCallerAt(1).String() - i.djb2String(caller1) - caller2 := std.GetCallerAt(2).String() - i.djb2String(caller2) - } - - // height - { - height := std.GetHeight() - if height >= math.MaxUint32 { - height -= math.MaxUint32 - } - i.djb2Uint32(uint32(height)) - } - - // time - { - secs := time.Now().Second() - i.djb2Uint32(uint32(secs)) - nsecs := time.Now().Nanosecond() - i.djb2Uint32(uint32(nsecs)) - } - - // FIXME: compute other hard-to-guess but deterministic variables, like real gas? -} - -func (i *Instance) Value() uint32 { - i.addEntropy() - return i.value -} diff --git a/examples/gno.land/p/demo/entropy/entropy_test.gno b/examples/gno.land/p/demo/entropy/entropy_test.gno deleted file mode 100644 index 0deb3ab9aa2..00000000000 --- a/examples/gno.land/p/demo/entropy/entropy_test.gno +++ /dev/null @@ -1,46 +0,0 @@ -package entropy - -import ( - "std" - "strconv" - "testing" -) - -func TestInstance(t *testing.T) { - instance := New() - if instance == nil { - t.Errorf("instance should not be nil") - } -} - -func TestInstanceValue(t *testing.T) { - baseEntropy := New() - baseResult := computeValue(t, baseEntropy) - - sameHeightEntropy := New() - sameHeightResult := computeValue(t, sameHeightEntropy) - - if baseResult != sameHeightResult { - t.Errorf("should have the same result: new=%s, base=%s", sameHeightResult, baseResult) - } - - std.TestSkipHeights(1) - differentHeightEntropy := New() - differentHeightResult := computeValue(t, differentHeightEntropy) - - if baseResult == differentHeightResult { - t.Errorf("should have different result: new=%s, base=%s", differentHeightResult, baseResult) - } -} - -func computeValue(t *testing.T, r *Instance) string { - t.Helper() - - out := "" - for i := 0; i < 10; i++ { - val := int(r.Value()) - out += strconv.Itoa(val) + " " - } - - return out -} diff --git a/examples/gno.land/p/demo/entropy/gno.mod b/examples/gno.land/p/demo/entropy/gno.mod deleted file mode 100644 index 9a6db8f5b61..00000000000 --- a/examples/gno.land/p/demo/entropy/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/p/demo/entropy diff --git a/examples/gno.land/p/demo/entropy/z_filetest.gno b/examples/gno.land/p/demo/entropy/z_filetest.gno deleted file mode 100644 index 85ed1b10a3d..00000000000 --- a/examples/gno.land/p/demo/entropy/z_filetest.gno +++ /dev/null @@ -1,56 +0,0 @@ -package main - -import ( - "std" - - "gno.land/p/demo/entropy" -) - -func main() { - // initial - println("---") - r := entropy.New() - println(r.Value()) - println(r.Value()) - println(r.Value()) - println(r.Value()) - println(r.Value()) - - // should be the same - println("---") - r = entropy.New() - println(r.Value()) - println(r.Value()) - println(r.Value()) - println(r.Value()) - println(r.Value()) - - std.TestSkipHeights(1) - println("---") - r = entropy.New() - println(r.Value()) - println(r.Value()) - println(r.Value()) - println(r.Value()) - println(r.Value()) -} - -// Output: -// --- -// 4129293727 -// 2141104956 -// 1950222777 -// 3348280598 -// 438354259 -// --- -// 4129293727 -// 2141104956 -// 1950222777 -// 3348280598 -// 438354259 -// --- -// 49506731 -// 1539580078 -// 2695928529 -// 1895482388 -// 3462727799 diff --git a/examples/gno.land/p/demo/flippandoserver/flippandoserver.gno b/examples/gno.land/p/demo/flippandoserver/flippandoserver.gno new file mode 100644 index 00000000000..2593102ac67 --- /dev/null +++ b/examples/gno.land/p/demo/flippandoserver/flippandoserver.gno @@ -0,0 +1,161 @@ +package flippandoserver + +type GameBoard struct { + Board []int64 `json:"board"` + TileType string `json:"tileType"` + GameTiles []int64 `json:"gameTiles"` + BoardSize int `json:"boardSize"` +} + +type positions struct { + position1 int + position2 int +} + +// position1 - int, postion2 - int + +type inTransit struct { + tokenId int + inTransit bool +} + +// creates game object and initializes board +func CreateGameBoard(tileType string, boardSize int, seed int64) ([]int64, []int64, int) { + // Initialize the board and gameTiles slices based on boardSize + board := make([]int64, boardSize) + + // Initialize the gameTiles slice with a length that is the square root of boardSize + gameTilesLength := int(sqrt(float64(boardSize))) + gameTiles := make([]int64, gameTilesLength) + // @todo make call to generateRandomNumbers, so you can create the actual gameTiles array, + rng := int64(4) + if tileType == "squareGrid" { + rng = int64(16) + } else if tileType == "greyGradient" || tileType == "redGradient" || tileType == "blueGradient" || tileType == "greenGradient" { + rng = int64(8) + } else if tileType == "hexagrams" { + rng = int64(4) + // adjust for bigger board + if len(gameTiles) == 8 { + gameTiles = make([]int64, 4) + } + } else if tileType == "dice" { + rng = int64(6) + // adjust for bigger board + if len(gameTiles) == 8 { + gameTiles = make([]int64, 6) + } + } + // Generating random numbers for gameTiles + generatedNumbers := GenerateRandomNumbers(len(gameTiles), 1, int(rng), seed) + for i, num := range generatedNumbers { + gameTiles[i] = int64(num) + } + + // we're returning discrete value, and do the json marshaling in realm + return board, gameTiles, boardSize; +} + +func FlipTiles(board []int64, solvedBoard []int64, gameTiles []int64, positions []int64, seed int64) ([]int64, []int64) { + // - returns the current game board, and the solved game board + + randomNumberSlice := GenerateRandomNumbers(2, 1, len(gameTiles), seed) + + // Safety check for 'positions' slice + if len(positions) < 2 { + return nil, nil + } + + // Safety check for 'randomNumberSlice' + if randomNumberSlice == nil || len(randomNumberSlice) < 2 { + return nil, nil + } + + // position hasn't been discovered before + if board[positions[0]] == 0 { + board[positions[0]] = gameTiles[randomNumberSlice[0] - 1] + } + + if board[positions[1]] == 0 { + board[positions[1]] = gameTiles[randomNumberSlice[1] -1] + } + + // values are equal, update solved board + if board[positions[0]] == board[positions[1]] { + solvedBoard[positions[0]] = board[positions[0]] + solvedBoard[positions[1]] = board[positions[1]] + } + + // enforce solvability + quantumThreshold := int(sqrt(float64(len(board)))) + unsolvedTiles := 0 + + for j := 0; j < len(board); j++ { + if solvedBoard[j] == 0 { + unsolvedTiles++ + } + } + + if unsolvedTiles <= quantumThreshold { + // replace the board with solvedBoard and redeploy + if board[positions[0]] != board[positions[1]] { + board[positions[0]] = board[positions[1]] + solvedBoard[positions[0]] = board[positions[0]] + solvedBoard[positions[1]] = board[positions[1]] + } + } + + return board, solvedBoard + +} + +func GenerateRandomNumbers(howMany, min, max int, seed int64) []int { + if min > max || howMany <= 0 || (max-min+1) < howMany { + return nil + } + + r := New(seed) + numbers := make([]int, 0, howMany) + seen := make(map[int]bool) + + for len(numbers) < howMany { + randomNumber := r.Intn(max-min+1) + min + + // If the number hasn't been generated before, add it to the slice and the map + if !seen[randomNumber] { + seen[randomNumber] = true + numbers = append(numbers, randomNumber) + } + } + + return numbers +} + + +func sqrt(x float64) float64 { + if x == 0 || x == 1 { + return x + } + + // Start with an initial guess + guess := x / 2.0 + prevGuess := 0.0 + + // Use a small threshold to determine when to stop the approximation + const threshold = 0.00001 + + // Use math.Abs to calculate the absolute value + abs := func(f float64) float64 { + if f < 0 { + return -f + } + return f + } + + for abs(guess-prevGuess) > threshold { + prevGuess = guess + guess = 0.5 * (guess + x/guess) + } + + return guess +} diff --git a/examples/gno.land/p/demo/flippandoserver/flippandoserver_test.gno b/examples/gno.land/p/demo/flippandoserver/flippandoserver_test.gno new file mode 100644 index 00000000000..785a11313ec --- /dev/null +++ b/examples/gno.land/p/demo/flippandoserver/flippandoserver_test.gno @@ -0,0 +1,122 @@ +package flippandoserver + +import ( + "sort" + "math" + "std" + "testing" + "time" + "encoding/json" + "strconv" + "errors" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/ufmt" +) + +func TestCreateGameBoard(t *testing.T) { + tests := []struct { + name string + tileType string + boardSize int + seed int64 + maxTileVal int + }{ + {"SquareGrid", "squareGrid", 4, 12345, 16}, + {"Hexagrams", "hexagrams", 4, 12345, 4}, + {"Dice", "dice", 4, 12345, 6}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + board, gameTiles, size := CreateGameBoard(tt.tileType, tt.boardSize, tt.seed) + + // Test the length of the board + if len(board) != tt.boardSize { + t.Errorf("Expected board length of %d, got %d", tt.boardSize, len(board)) + } + + // Test the length of gameTiles + expectedGameTilesLength := int(sqrt(float64(tt.boardSize))) + if len(gameTiles) != expectedGameTilesLength { + t.Errorf("Expected gameTiles length of %d, got %d", expectedGameTilesLength, len(gameTiles)) + } + + // Check if gameTiles values are within the expected range + for _, tile := range gameTiles { + if tile < 1 || tile > int64(tt.maxTileVal) { + t.Errorf("gameTiles contains a value out of expected range (1 to %d): got %d", tt.maxTileVal, tile) + } + } + + // Check if the gameTiles values are unique + uniqueTiles := make(map[int64]bool) + for _, tile := range gameTiles { + if uniqueTiles[tile] { + t.Errorf("Duplicate tile found in gameTiles: %d", tile) + } + uniqueTiles[tile] = true + } + + // Test the returned board size + if size != tt.boardSize { + t.Errorf("Expected returned board size to be %d, got %d", tt.boardSize, size) + } + }) + } +} + +func TestGenerateRandomNumbers(t *testing.T) { + tests := []struct { + howMany int + min int + max int + seed int64 + expect int + }{ + {5, 1, 10, 123, 5}, + {3, 5, 7, 456, 3}, + {10, 1, 5, 789, 0}, + {0, 1, 10, 101, 0}, + {-2, 1, 10, 112, 0}, + {5, 10, 5, 123, 0}, + } + + for _, tt := range tests { + got := GenerateRandomNumbers(tt.howMany, tt.min, tt.max, tt.seed) + + if len(got) != tt.expect { + t.Errorf("expected %d numbers but got %d", tt.expect, len(got)) + } + + // Check for uniqueness + numSet := make(map[int]bool) + for _, num := range got { + if numSet[num] { + t.Errorf("duplicate number found: %d", num) + } + numSet[num] = true + } + + // Check if numbers are within range + for _, num := range got { + if num < tt.min || num > tt.max { + t.Errorf("number %d out of range [%d, %d]", num, tt.min, tt.max) + } + } + } +} + + +// Helper function to compare two slices for equality +func sliceEqual(a, b []int64) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} diff --git a/examples/gno.land/p/demo/flippandoserver/fliprand.gno b/examples/gno.land/p/demo/flippandoserver/fliprand.gno new file mode 100644 index 00000000000..3b1f52a0bf5 --- /dev/null +++ b/examples/gno.land/p/demo/flippandoserver/fliprand.gno @@ -0,0 +1,590 @@ +package flippandoserver + +// this is a refactoring of the math/rand implementation with the goal of +// generating "good-enough" randomness, while eliminating the dependency +// from the actual math/rand package. +// +// once we have access to a reliable verifiable randmness source, this +// package should be replaced / refactored + +import ( + "std" + "time" +) + +type Instance struct { + seed int64 +} + +// In the rand package: + +func New(seed int64) *Instance { + r := Instance{seed: seed} + r.addEntropy() + return &r +} + +func FromSeed(seed int64) *Instance { + r := Instance{seed: seed} + r.addEntropy() + return &r +} + +func (i *Instance) Seed() int64 { + return i.seed +} + +func (i *Instance) djb2String(input string) { + for _, c := range input { + i.djb2Int64(int64(c)) + } +} + +// super fast random algorithm. +// http://www.cse.yorku.ca/~oz/hash.html +func (i *Instance) djb2Int64(input int64) { + i.seed = (i.seed << 5) + i.seed + input +} + +// AddEntropy uses various runtime variables to add entropy to the existing seed. +func (i *Instance) addEntropy() { + // FIXME: reapply the 5381 initial value? + + // inherit previous entropy + // nothing to do + + // handle callers + { + caller1 := std.GetCallerAt(1).String() + i.djb2String(caller1) + caller2 := std.GetCallerAt(2).String() + i.djb2String(caller2) + } + + // height + { + height := std.GetHeight() + i.djb2Int64(height) + } + + // time + { + secs := time.Now().Second() + i.djb2Int64(int64(secs)) + nsecs := time.Now().Nanosecond() + i.djb2Int64(int64(nsecs)) + } + + // FIXME: compute other hard-to-guess but deterministic variables, like real gas? +} + +func (i *Instance) Float32() float32 { + i.addEntropy() + return NewRand(NewSource(i.seed)).Float32() +} + +func (i *Instance) Float64() float64 { + i.addEntropy() + return NewRand(NewSource(i.seed)).Float64() +} + +func (i *Instance) Int() int { + i.addEntropy() + return NewRand(NewSource(i.seed)).Int() +} + +func (i *Instance) Intn(n int) int { + i.addEntropy() + return NewRand(NewSource(i.seed)).Intn(n) +} + +func (i *Instance) Int63() int64 { + i.addEntropy() + return NewRand(NewSource(i.seed)).Int63() +} + +func (i *Instance) Int63n(n int64) int64 { + i.addEntropy() + return NewRand(NewSource(i.seed)).Int63n(n) +} + +func (i *Instance) Int31() int32 { + i.addEntropy() + return NewRand(NewSource(i.seed)).Int31() +} + +func (i *Instance) Int31n(n int32) int32 { + i.addEntropy() + return NewRand(NewSource(i.seed)).Int31n(n) +} + +func (i *Instance) Uint32() uint32 { + i.addEntropy() + return NewRand(NewSource(i.seed)).Uint32() +} + +func (i *Instance) Uint64() uint64 { + i.addEntropy() + return NewRand(NewSource(i.seed)).Uint64() +} + +func (i *Instance) Read(p []byte) (n int, err error) { + i.addEntropy() + return NewRand(NewSource(i.seed)).Read(p) +} + +func (i *Instance) Shuffle(n int, swap func(i, j int)) { + i.addEntropy() + NewRand(NewSource(i.seed)).Shuffle(n, swap) +} + + +// below is the relevant part of the code from the math/rand implementation +// Copyright retained + +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package rand implements pseudo-random number generators unsuitable for +// security-sensitive work. +// +// Random numbers are generated by a [Source], usually wrapped in a [Rand]. +// Both types should be used by a single goroutine at a time: sharing among +// multiple goroutines requires some kind of synchronization. +// +// Top-level functions, such as [Float64] and [Int], +// are safe for concurrent use by multiple goroutines. +// +// This package's outputs might be easily predictable regardless of how it's +// seeded. For random numbers suitable for security-sensitive work, see the +// crypto/rand package. + +// A Source represents a source of uniformly-distributed +// pseudo-random int64 values in the range [0, 1<<63). +// +// A Source is not safe for concurrent use by multiple goroutines. +type Source interface { + Int63() int64 + Seed(seed int64) +} + +// A Source64 is a Source that can also generate +// uniformly-distributed pseudo-random uint64 values in +// the range [0, 1<<64) directly. +// If a Rand r's underlying Source s implements Source64, +// then r.Uint64 returns the result of one call to s.Uint64 +// instead of making two calls to s.Int63. +type Source64 interface { + Source + Uint64() uint64 +} + +// NewSource returns a new pseudo-random Source seeded with the given value. +// Unlike the default Source used by top-level functions, this source is not +// safe for concurrent use by multiple goroutines. +// The returned Source implements Source64. +func NewSource(seed int64) Source { + return newSource(seed) +} + +func newSource(seed int64) *rngSource { + var rng rngSource + rng.Seed(seed) + return &rng +} + +// A Rand is a source of random numbers. +type Rand struct { + src Source + s64 Source64 // non-nil if src is source64 + + // readVal contains remainder of 63-bit integer used for bytes + // generation during most recent Read call. + // It is saved so next Read call can start where the previous + // one finished. + readVal int64 + // readPos indicates the number of low-order bytes of readVal + // that are still valid. + readPos int8 +} + +// New returns a new Rand that uses random values from src +// to generate other random values. +func NewRand(src Source) *Rand { + s64, _ := src.(Source64) + return &Rand{src: src, s64: s64} +} + +// Seed uses the provided seed value to initialize the generator to a deterministic state. +// Seed should not be called concurrently with any other Rand method. +func (r *Rand) Seed(seed int64) { + /* + if lk, ok := r.src.(*lockedSource); ok { + lk.seedPos(seed, &r.readPos) + return + }*/ + + r.src.Seed(seed) + r.readPos = 0 +} + +// Int63 returns a non-negative pseudo-random 63-bit integer as an int64. +func (r *Rand) Int63() int64 { return r.src.Int63() } + +// Uint32 returns a pseudo-random 32-bit value as a uint32. +func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) } + +// Uint64 returns a pseudo-random 64-bit value as a uint64. +func (r *Rand) Uint64() uint64 { + if r.s64 != nil { + return r.s64.Uint64() + } + return uint64(r.Int63())>>31 | uint64(r.Int63())<<32 +} + +// Int31 returns a non-negative pseudo-random 31-bit integer as an int32. +func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) } + +// Int returns a non-negative pseudo-random int. +func (r *Rand) Int() int { + u := uint(r.Int63()) + return int(u << 1 >> 1) // clear sign bit if int == int32 +} + +// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) Int63n(n int64) int64 { + if n <= 0 { + panic("invalid argument to Int63n") + } + if n&(n-1) == 0 { // n is power of two, can mask + return r.Int63() & (n - 1) + } + max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) + v := r.Int63() + for v > max { + v = r.Int63() + } + return v % n +} + +// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) Int31n(n int32) int32 { + if n <= 0 { + panic("invalid argument to Int31n") + } + if n&(n-1) == 0 { // n is power of two, can mask + return r.Int31() & (n - 1) + } + max := int32((1 << 31) - 1 - (1<<31)%uint32(n)) + v := r.Int31() + for v > max { + v = r.Int31() + } + return v % n +} + +// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). +// n must be > 0, but int31n does not check this; the caller must ensure it. +// int31n exists because Int31n is inefficient, but Go 1 compatibility +// requires that the stream of values produced by math/rand remain unchanged. +// int31n can thus only be used internally, by newly introduced APIs. +// +// For implementation details, see: +// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction +// https://lemire.me/blog/2016/06/30/fast-random-shuffling +func (r *Rand) int31n(n int32) int32 { + v := r.Uint32() + prod := uint64(v) * uint64(n) + low := uint32(prod) + if low < uint32(n) { + thresh := uint32(-n) % uint32(n) + for low < thresh { + v = r.Uint32() + prod = uint64(v) * uint64(n) + low = uint32(prod) + } + } + return int32(prod >> 32) +} + +// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n). +// It panics if n <= 0. +func (r *Rand) Intn(n int) int { + if n <= 0 { + panic("invalid argument to Intn") + } + if n <= 1<<31-1 { + return int(r.Int31n(int32(n))) + } + return int(r.Int63n(int64(n))) +} + +// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0). +func (r *Rand) Float64() float64 { + // A clearer, simpler implementation would be: + // return float64(r.Int63n(1<<53)) / (1<<53) + // However, Go 1 shipped with + // return float64(r.Int63()) / (1 << 63) + // and we want to preserve that value stream. + // + // There is one bug in the value stream: r.Int63() may be so close + // to 1<<63 that the division rounds up to 1.0, and we've guaranteed + // that the result is always less than 1.0. + // + // We tried to fix this by mapping 1.0 back to 0.0, but since float64 + // values near 0 are much denser than near 1, mapping 1 to 0 caused + // a theoretically significant overshoot in the probability of returning 0. + // Instead of that, if we round up to 1, just try again. + // Getting 1 only happens 1/2⁵³ of the time, so most clients + // will not observe it anyway. +again: + f := float64(r.Int63()) / (1 << 63) + if f == 1 { + goto again // resample; this branch is taken O(never) + } + return f +} + +// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0). +func (r *Rand) Float32() float32 { + // Same rationale as in Float64: we want to preserve the Go 1 value + // stream except we want to fix it not to return 1.0 + // This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64). +again: + f := float32(r.Float64()) + if f == 1 { + goto again // resample; this branch is taken O(very rarely) + } + return f +} + +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers +// in the half-open interval [0,n). +func (r *Rand) Perm(n int) []int { + m := make([]int, n) + // In the following loop, the iteration when i=0 always swaps m[0] with m[0]. + // A change to remove this useless iteration is to assign 1 to i in the init + // statement. But Perm also effects r. Making this change will affect + // the final state of r. So this change can't be made for compatibility + // reasons for Go 1. + for i := 0; i < n; i++ { + j := r.Intn(i + 1) + m[i] = m[j] + m[j] = i + } + return m +} + +// Shuffle pseudo-randomizes the order of elements. +// n is the number of elements. Shuffle panics if n < 0. +// swap swaps the elements with indexes i and j. +func (r *Rand) Shuffle(n int, swap func(i, j int)) { + if n < 0 { + panic("invalid argument to Shuffle") + } + + // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + // Shuffle really ought not be called with n that doesn't fit in 32 bits. + // Not only will it take a very long time, but with 2³¹! possible permutations, + // there's no way that any PRNG can have a big enough internal state to + // generate even a minuscule percentage of the possible permutations. + // Nevertheless, the right API signature accepts an int n, so handle it as best we can. + i := n - 1 + for ; i > 1<<31-1-1; i-- { + j := int(r.Int63n(int64(i + 1))) + swap(i, j) + } + for ; i > 0; i-- { + j := int(r.int31n(int32(i + 1))) + swap(i, j) + } +} + +// Read generates len(p) random bytes and writes them into p. It +// always returns len(p) and a nil error. +// Read should not be called concurrently with any other Rand method. +func (r *Rand) Read(p []byte) (n int, err error) { + /* + if lk, ok := r.src.(*lockedSource); ok { + return lk.read(p, &r.readVal, &r.readPos) + }*/ + return read(p, r.src, &r.readVal, &r.readPos) +} + +func read(p []byte, src Source, readVal *int64, readPos *int8) (n int, err error) { + pos := *readPos + val := *readVal + rng, _ := src.(*rngSource) + for n = 0; n < len(p); n++ { + if pos == 0 { + if rng != nil { + val = rng.Int63() + } else { + val = src.Int63() + } + pos = 7 + } + p[n] = byte(val) + val >>= 8 + pos-- + } + *readPos = pos + *readVal = val + return +} + +/* + * Top-level convenience functions + */ + +var globalRand = NewRand(new(rngSource)) + +// Seed uses the provided seed value to initialize the default Source to a +// deterministic state. Seed values that have the same remainder when +// divided by 2³¹-1 generate the same pseudo-random sequence. +// Seed, unlike the Rand.Seed method, is safe for concurrent use. +// +// If Seed is not called, the generator is seeded randomly at program startup. +// +// Prior to Go 1.20, the generator was seeded like Seed(1) at program startup. +// To force the old behavior, call Seed(1) at program startup. +// Alternately, set GODEBUG=randautoseed=0 in the environment +// before making any calls to functions in this package. +// +// Deprecated: Programs that call Seed and then expect a specific sequence +// of results from the global random source (using functions such as Int) +// can be broken when a dependency changes how much it consumes +// from the global random source. To avoid such breakages, programs +// that need a specific result sequence should use NewRand(NewSource(seed)) +// to obtain a random generator that other packages cannot access. +func Seed(seed int64) { globalRand.Seed(seed) } + +// Int63 returns a non-negative pseudo-random 63-bit integer as an int64 +// from the default Source. +func Int63() int64 { return globalRand.Int63() } + +// Uint32 returns a pseudo-random 32-bit value as a uint32 +// from the default Source. +func Uint32() uint32 { return globalRand.Uint32() } + +// Uint64 returns a pseudo-random 64-bit value as a uint64 +// from the default Source. +func Uint64() uint64 { return globalRand.Uint64() } + +// Int31 returns a non-negative pseudo-random 31-bit integer as an int32 +// from the default Source. +func Int31() int32 { return globalRand.Int31() } + +// Int returns a non-negative pseudo-random int from the default Source. +func Int() int { return globalRand.Int() } + +// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func Int63n(n int64) int64 { return globalRand.Int63n(n) } + +// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func Int31n(n int32) int32 { return globalRand.Int31n(n) } + +// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n) +// from the default Source. +// It panics if n <= 0. +func Intn(n int) int { return globalRand.Intn(n) } + +// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0) +// from the default Source. +func Float64() float64 { return globalRand.Float64() } + +// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0) +// from the default Source. +func Float32() float32 { return globalRand.Float32() } + +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers +// in the half-open interval [0,n) from the default Source. +func Perm(n int) []int { return globalRand.Perm(n) } + +// Shuffle pseudo-randomizes the order of elements using the default Source. +// n is the number of elements. Shuffle panics if n < 0. +// swap swaps the elements with indexes i and j. +func Shuffle(n int, swap func(i, j int)) { globalRand.Shuffle(n, swap) } + +// Read generates len(p) random bytes from the default Source and +// writes them into p. It always returns len(p) and a nil error. +// Read, unlike the Rand.Read method, is safe for concurrent use. +// +// Deprecated: For almost all use cases, crypto/rand.Read is more appropriate. +func Read(p []byte) (n int, err error) { return globalRand.Read(p) } + +// NormFloat64 returns a normally distributed float64 in the range +// [-math.MaxFloat64, +math.MaxFloat64] with +// standard normal distribution (mean = 0, stddev = 1) +// from the default Source. +// To produce a different normal distribution, callers can +// adjust the output using: +// +// sample = NormFloat64() * desiredStdDev + desiredMean +func NormFloat64() float64 { return globalRand.NormFloat64() } + +func (r *Rand) NormFloat64() float64 { + z := r.Float64()*2 - 1 + r.Float64()*2 - 1 + radius := z*z + for radius >= 1 || radius == 0 { + z = r.Float64()*2 - 1 + r.Float64()*2 - 1 + radius = z*z + } + return z * (-2 * ln(radius) / radius) +} + +// while not having access to math package at all +func ln(x float64) float64 { + const negativeInfinity = -1e308 + const NaN = -99999.0 + + if x == 0 { + return negativeInfinity // Return a very large negative value for ln(0) + } + if x < 0 { + return NaN // Return a special value for negative values + } + + // Adjust large values into a suitable range for Maclaurin series + if x > 2 { + return -ln(1/x) + } + + // Maclaurin series for ln(1 + x) around 0 + x -= 1 // Adjust x for the expansion around 1 + result := 0.0 + term := x + for i := 1; i < 100; i++ { // Use 100 terms. You can adjust this for more accuracy. + if i%2 == 1 { + result += term / float64(i) + } else { + result -= term / float64(i) + } + term *= x + } + + return result +} + + +// ExpFloat64 returns an exponentially distributed float64 in the range +// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter +// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source. +// To produce a distribution with a different rate parameter, +// callers can adjust the output using: +// +// sample = ExpFloat64() / desiredRateParameter +//func ExpFloat64() float64 { return globalRand.ExpFloat64() } + +func (r *Rand) ExpFloat64() float64 { + return globalRand.ExpFloat64() +} + + diff --git a/examples/gno.land/p/demo/flippandoserver/gno.mod b/examples/gno.land/p/demo/flippandoserver/gno.mod new file mode 100644 index 00000000000..b1032f242e8 --- /dev/null +++ b/examples/gno.land/p/demo/flippandoserver/gno.mod @@ -0,0 +1 @@ +module "gno.land/p/demo/flippandoserver" \ No newline at end of file diff --git a/examples/gno.land/p/demo/flippandoserver/rng.gno b/examples/gno.land/p/demo/flippandoserver/rng.gno new file mode 100644 index 00000000000..ddd1fbc45b1 --- /dev/null +++ b/examples/gno.land/p/demo/flippandoserver/rng.gno @@ -0,0 +1,250 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flippandoserver + +/* + * Uniform distribution + * + * algorithm by + * DP Mitchell and JA Reeds + */ + +const ( + rngLen = 607 + rngTap = 273 + rngMax = 1 << 63 + rngMask = rngMax - 1 + int32max = (1 << 31) - 1 +) + +// rngCooked used for seeding. See gen_cooked.go for details. +var rngCooked [rngLen]int64 = [...]int64{ + -4181792142133755926, -4576982950128230565, 1395769623340756751, 5333664234075297259, + -6347679516498800754, 9033628115061424579, 7143218595135194537, 4812947590706362721, + 7937252194349799378, 5307299880338848416, 8209348851763925077, -7107630437535961764, + 4593015457530856296, 8140875735541888011, -5903942795589686782, -603556388664454774, + -7496297993371156308, 113108499721038619, 4569519971459345583, -4160538177779461077, + -6835753265595711384, -6507240692498089696, 6559392774825876886, 7650093201692370310, + 7684323884043752161, -8965504200858744418, -2629915517445760644, 271327514973697897, + -6433985589514657524, 1065192797246149621, 3344507881999356393, -4763574095074709175, + 7465081662728599889, 1014950805555097187, -4773931307508785033, -5742262670416273165, + 2418672789110888383, 5796562887576294778, 4484266064449540171, 3738982361971787048, + -4699774852342421385, 10530508058128498, -589538253572429690, -6598062107225984180, + 8660405965245884302, 10162832508971942, -2682657355892958417, 7031802312784620857, + 6240911277345944669, 831864355460801054, -1218937899312622917, 2116287251661052151, + 2202309800992166967, 9161020366945053561, 4069299552407763864, 4936383537992622449, + 457351505131524928, -8881176990926596454, -6375600354038175299, -7155351920868399290, + 4368649989588021065, 887231587095185257, -3659780529968199312, -2407146836602825512, + 5616972787034086048, -751562733459939242, 1686575021641186857, -5177887698780513806, + -4979215821652996885, -1375154703071198421, 5632136521049761902, -8390088894796940536, + -193645528485698615, -5979788902190688516, -4907000935050298721, -285522056888777828, + -2776431630044341707, 1679342092332374735, 6050638460742422078, -2229851317345194226, + -1582494184340482199, 5881353426285907985, 812786550756860885, 4541845584483343330, + -6497901820577766722, 4980675660146853729, -4012602956251539747, -329088717864244987, + -2896929232104691526, 1495812843684243920, -2153620458055647789, 7370257291860230865, + -2466442761497833547, 4706794511633873654, -1398851569026877145, 8549875090542453214, + -9189721207376179652, -7894453601103453165, 7297902601803624459, 1011190183918857495, + -6985347000036920864, 5147159997473910359, -8326859945294252826, 2659470849286379941, + 6097729358393448602, -7491646050550022124, -5117116194870963097, -896216826133240300, + -745860416168701406, 5803876044675762232, -787954255994554146, -3234519180203704564, + -4507534739750823898, -1657200065590290694, 505808562678895611, -4153273856159712438, + -8381261370078904295, 572156825025677802, 1791881013492340891, 3393267094866038768, + -5444650186382539299, 2352769483186201278, -7930912453007408350, -325464993179687389, + -3441562999710612272, -6489413242825283295, 5092019688680754699, -227247482082248967, + 4234737173186232084, 5027558287275472836, 4635198586344772304, -536033143587636457, + 5907508150730407386, -8438615781380831356, 972392927514829904, -3801314342046600696, + -4064951393885491917, -174840358296132583, 2407211146698877100, -1640089820333676239, + 3940796514530962282, -5882197405809569433, 3095313889586102949, -1818050141166537098, + 5832080132947175283, 7890064875145919662, 8184139210799583195, -8073512175445549678, + -7758774793014564506, -4581724029666783935, 3516491885471466898, -8267083515063118116, + 6657089965014657519, 5220884358887979358, 1796677326474620641, 5340761970648932916, + 1147977171614181568, 5066037465548252321, 2574765911837859848, 1085848279845204775, + -5873264506986385449, 6116438694366558490, 2107701075971293812, -7420077970933506541, + 2469478054175558874, -1855128755834809824, -5431463669011098282, -9038325065738319171, + -6966276280341336160, 7217693971077460129, -8314322083775271549, 7196649268545224266, + -3585711691453906209, -5267827091426810625, 8057528650917418961, -5084103596553648165, + -2601445448341207749, -7850010900052094367, 6527366231383600011, 3507654575162700890, + 9202058512774729859, 1954818376891585542, -2582991129724600103, 8299563319178235687, + -5321504681635821435, 7046310742295574065, -2376176645520785576, -7650733936335907755, + 8850422670118399721, 3631909142291992901, 5158881091950831288, -6340413719511654215, + 4763258931815816403, 6280052734341785344, -4979582628649810958, 2043464728020827976, + -2678071570832690343, 4562580375758598164, 5495451168795427352, -7485059175264624713, + 553004618757816492, 6895160632757959823, -989748114590090637, 7139506338801360852, + -672480814466784139, 5535668688139305547, 2430933853350256242, -3821430778991574732, + -1063731997747047009, -3065878205254005442, 7632066283658143750, 6308328381617103346, + 3681878764086140361, 3289686137190109749, 6587997200611086848, 244714774258135476, + -5143583659437639708, 8090302575944624335, 2945117363431356361, -8359047641006034763, + 3009039260312620700, -793344576772241777, 401084700045993341, -1968749590416080887, + 4707864159563588614, -3583123505891281857, -3240864324164777915, -5908273794572565703, + -3719524458082857382, -5281400669679581926, 8118566580304798074, 3839261274019871296, + 7062410411742090847, -8481991033874568140, 6027994129690250817, -6725542042704711878, + -2971981702428546974, -7854441788951256975, 8809096399316380241, 6492004350391900708, + 2462145737463489636, -8818543617934476634, -5070345602623085213, -8961586321599299868, + -3758656652254704451, -8630661632476012791, 6764129236657751224, -709716318315418359, + -3403028373052861600, -8838073512170985897, -3999237033416576341, -2920240395515973663, + -2073249475545404416, 368107899140673753, -6108185202296464250, -6307735683270494757, + 4782583894627718279, 6718292300699989587, 8387085186914375220, 3387513132024756289, + 4654329375432538231, -292704475491394206, -3848998599978456535, 7623042350483453954, + 7725442901813263321, 9186225467561587250, -5132344747257272453, -6865740430362196008, + 2530936820058611833, 1636551876240043639, -3658707362519810009, 1452244145334316253, + -7161729655835084979, -7943791770359481772, 9108481583171221009, -3200093350120725999, + 5007630032676973346, 2153168792952589781, 6720334534964750538, -3181825545719981703, + 3433922409283786309, 2285479922797300912, 3110614940896576130, -2856812446131932915, + -3804580617188639299, 7163298419643543757, 4891138053923696990, 580618510277907015, + 1684034065251686769, 4429514767357295841, -8893025458299325803, -8103734041042601133, + 7177515271653460134, 4589042248470800257, -1530083407795771245, 143607045258444228, + 246994305896273627, -8356954712051676521, 6473547110565816071, 3092379936208876896, + 2058427839513754051, -4089587328327907870, 8785882556301281247, -3074039370013608197, + -637529855400303673, 6137678347805511274, -7152924852417805802, 5708223427705576541, + -3223714144396531304, 4358391411789012426, 325123008708389849, 6837621693887290924, + 4843721905315627004, -3212720814705499393, -3825019837890901156, 4602025990114250980, + 1044646352569048800, 9106614159853161675, -8394115921626182539, -4304087667751778808, + 2681532557646850893, 3681559472488511871, -3915372517896561773, -2889241648411946534, + -6564663803938238204, -8060058171802589521, 581945337509520675, 3648778920718647903, + -4799698790548231394, -7602572252857820065, 220828013409515943, -1072987336855386047, + 4287360518296753003, -4633371852008891965, 5513660857261085186, -2258542936462001533, + -8744380348503999773, 8746140185685648781, 228500091334420247, 1356187007457302238, + 3019253992034194581, 3152601605678500003, -8793219284148773595, 5559581553696971176, + 4916432985369275664, -8559797105120221417, -5802598197927043732, 2868348622579915573, + -7224052902810357288, -5894682518218493085, 2587672709781371173, -7706116723325376475, + 3092343956317362483, -5561119517847711700, 972445599196498113, -1558506600978816441, + 1708913533482282562, -2305554874185907314, -6005743014309462908, -6653329009633068701, + -483583197311151195, 2488075924621352812, -4529369641467339140, -4663743555056261452, + 2997203966153298104, 1282559373026354493, 240113143146674385, 8665713329246516443, + 628141331766346752, -4651421219668005332, -7750560848702540400, 7596648026010355826, + -3132152619100351065, 7834161864828164065, 7103445518877254909, 4390861237357459201, + -4780718172614204074, -319889632007444440, 622261699494173647, -3186110786557562560, + -8718967088789066690, -1948156510637662747, -8212195255998774408, -7028621931231314745, + 2623071828615234808, -4066058308780939700, -5484966924888173764, -6683604512778046238, + -6756087640505506466, 5256026990536851868, 7841086888628396109, 6640857538655893162, + -8021284697816458310, -7109857044414059830, -1689021141511844405, -4298087301956291063, + -4077748265377282003, -998231156719803476, 2719520354384050532, 9132346697815513771, + 4332154495710163773, -2085582442760428892, 6994721091344268833, -2556143461985726874, + -8567931991128098309, 59934747298466858, -3098398008776739403, -265597256199410390, + 2332206071942466437, -7522315324568406181, 3154897383618636503, -7585605855467168281, + -6762850759087199275, 197309393502684135, -8579694182469508493, 2543179307861934850, + 4350769010207485119, -4468719947444108136, -7207776534213261296, -1224312577878317200, + 4287946071480840813, 8362686366770308971, 6486469209321732151, -5605644191012979782, + -1669018511020473564, 4450022655153542367, -7618176296641240059, -3896357471549267421, + -4596796223304447488, -6531150016257070659, -8982326463137525940, -4125325062227681798, + -1306489741394045544, -8338554946557245229, 5329160409530630596, 7790979528857726136, + 4955070238059373407, -4304834761432101506, -6215295852904371179, 3007769226071157901, + -6753025801236972788, 8928702772696731736, 7856187920214445904, -4748497451462800923, + 7900176660600710914, -7082800908938549136, -6797926979589575837, -6737316883512927978, + 4186670094382025798, 1883939007446035042, -414705992779907823, 3734134241178479257, + 4065968871360089196, 6953124200385847784, -7917685222115876751, -7585632937840318161, + -5567246375906782599, -5256612402221608788, 3106378204088556331, -2894472214076325998, + 4565385105440252958, 1979884289539493806, -6891578849933910383, 3783206694208922581, + 8464961209802336085, 2843963751609577687, 3030678195484896323, -4429654462759003204, + 4459239494808162889, 402587895800087237, 8057891408711167515, 4541888170938985079, + 1042662272908816815, -3666068979732206850, 2647678726283249984, 2144477441549833761, + -3417019821499388721, -2105601033380872185, 5916597177708541638, -8760774321402454447, + 8833658097025758785, 5970273481425315300, 563813119381731307, -6455022486202078793, + 1598828206250873866, -4016978389451217698, -2988328551145513985, -6071154634840136312, + 8469693267274066490, 125672920241807416, -3912292412830714870, -2559617104544284221, + -486523741806024092, -4735332261862713930, 5923302823487327109, -9082480245771672572, + -1808429243461201518, 7990420780896957397, 4317817392807076702, 3625184369705367340, + -6482649271566653105, -3480272027152017464, -3225473396345736649, -368878695502291645, + -3981164001421868007, -8522033136963788610, 7609280429197514109, 3020985755112334161, + -2572049329799262942, 2635195723621160615, 5144520864246028816, -8188285521126945980, + 1567242097116389047, 8172389260191636581, -2885551685425483535, -7060359469858316883, + -6480181133964513127, -7317004403633452381, 6011544915663598137, 5932255307352610768, + 2241128460406315459, -8327867140638080220, 3094483003111372717, 4583857460292963101, + 9079887171656594975, -384082854924064405, -3460631649611717935, 4225072055348026230, + -7385151438465742745, 3801620336801580414, -399845416774701952, -7446754431269675473, + 7899055018877642622, 5421679761463003041, 5521102963086275121, -4975092593295409910, + 8735487530905098534, -7462844945281082830, -2080886987197029914, -1000715163927557685, + -4253840471931071485, -5828896094657903328, 6424174453260338141, 359248545074932887, + -5949720754023045210, -2426265837057637212, 3030918217665093212, -9077771202237461772, + -3186796180789149575, 740416251634527158, -2142944401404840226, 6951781370868335478, + 399922722363687927, -8928469722407522623, -1378421100515597285, -8343051178220066766, + -3030716356046100229, -8811767350470065420, 9026808440365124461, 6440783557497587732, + 4615674634722404292, 539897290441580544, 2096238225866883852, 8751955639408182687, + -7316147128802486205, 7381039757301768559, 6157238513393239656, -1473377804940618233, + 8629571604380892756, 5280433031239081479, 7101611890139813254, 2479018537985767835, + 7169176924412769570, -1281305539061572506, -7865612307799218120, 2278447439451174845, + 3625338785743880657, 6477479539006708521, 8976185375579272206, -3712000482142939688, + 1326024180520890843, 7537449876596048829, 5464680203499696154, 3189671183162196045, + 6346751753565857109, -8982212049534145501, -6127578587196093755, -245039190118465649, + -6320577374581628592, 7208698530190629697, 7276901792339343736, -7490986807540332668, + 4133292154170828382, 2918308698224194548, -7703910638917631350, -3929437324238184044, + -4300543082831323144, -6344160503358350167, 5896236396443472108, -758328221503023383, + -1894351639983151068, -307900319840287220, -6278469401177312761, -2171292963361310674, + 8382142935188824023, 9103922860780351547, 4152330101494654406, +} + +type rngSource struct { + tap int // index into vec + feed int // index into vec + vec [rngLen]int64 // current feedback register +} + +// seed rng x[n+1] = 48271 * x[n] mod (2**31 - 1) +func seedrand(x int32) int32 { + const ( + A = 48271 + Q = 44488 + R = 3399 + ) + + hi := x / Q + lo := x % Q + x = A*lo - R*hi + if x < 0 { + x += int32max + } + return x +} + +// Seed uses the provided seed value to initialize the generator to a deterministic state. +func (rng *rngSource) Seed(seed int64) { + rng.tap = 0 + rng.feed = rngLen - rngTap + + seed = seed % int32max + if seed < 0 { + seed += int32max + } + if seed == 0 { + seed = 89482311 + } + + x := int32(seed) + for i := -20; i < rngLen; i++ { + x = seedrand(x) + if i >= 0 { + var u int64 + u = int64(x) << 40 + x = seedrand(x) + u ^= int64(x) << 20 + x = seedrand(x) + u ^= int64(x) + u ^= rngCooked[i] + rng.vec[i] = u + } + } +} + +// Int63 returns a non-negative pseudo-random 63-bit integer as an int64. +func (rng *rngSource) Int63() int64 { + return int64(rng.Uint64() & rngMask) +} + +// Uint64 returns a non-negative pseudo-random 64-bit integer as a uint64. +func (rng *rngSource) Uint64() uint64 { + rng.tap-- + if rng.tap < 0 { + rng.tap += rngLen + } + + rng.feed-- + if rng.feed < 0 { + rng.feed += rngLen + } + + x := rng.vec[rng.feed] + rng.vec[rng.tap] + rng.vec[rng.feed] = x + return uint64(x) +} diff --git a/examples/gno.land/p/demo/fqname/fqname.gno b/examples/gno.land/p/demo/fqname/fqname.gno deleted file mode 100644 index d28453e5c1b..00000000000 --- a/examples/gno.land/p/demo/fqname/fqname.gno +++ /dev/null @@ -1,72 +0,0 @@ -// Package fqname provides utilities for handling fully qualified identifiers in -// Gno. A fully qualified identifier typically includes a package path followed -// by a dot (.) and then the name of a variable, function, type, or other -// package-level declaration. -package fqname - -import "strings" - -// Parse splits a fully qualified identifier into its package path and name -// components. It handles cases with and without slashes in the package path. -// -// pkgpath, name := fqname.Parse("gno.land/p/demo/avl.Tree") -// ufmt.Sprintf("Package: %s, Name: %s\n", id.Package, id.Name) -// // Output: Package: gno.land/p/demo/avl, Name: Tree -func Parse(fqname string) (pkgpath, name string) { - // Find the index of the last slash. - lastSlashIndex := strings.LastIndex(fqname, "/") - if lastSlashIndex == -1 { - // No slash found, handle it as a simple package name with dot notation. - dotIndex := strings.LastIndex(fqname, ".") - if dotIndex == -1 { - return fqname, "" - } - return fqname[:dotIndex], fqname[dotIndex+1:] - } - - // Get the part after the last slash. - afterSlash := fqname[lastSlashIndex+1:] - - // Check for a dot in the substring after the last slash. - dotIndex := strings.Index(afterSlash, ".") - if dotIndex == -1 { - // No dot found after the last slash - return fqname, "" - } - - // Split at the dot to separate the base and the suffix. - base := fqname[:lastSlashIndex+1+dotIndex] - suffix := afterSlash[dotIndex+1:] - - return base, suffix -} - -// Construct a qualified identifier. -// -// fqName := fqname.Construct("gno.land/r/demo/foo20", "GRC20") -// fmt.Println("Fully Qualified Name:", fqName) -// // Output: gno.land/r/demo/foo20.GRC20 -func Construct(pkgpath, name string) string { - // TODO: ensure pkgpath is valid - and as such last part does not contain a dot. - if name == "" { - return pkgpath - } - return pkgpath + "." + name -} - -// RenderLink creates a formatted link for a fully qualified identifier. -// If the package path starts with "gno.land", it converts it to a markdown link. -// If the domain is different or missing, it returns the input as is. -func RenderLink(pkgPath, slug string) string { - if strings.HasPrefix(pkgPath, "gno.land") { - pkgLink := strings.TrimPrefix(pkgPath, "gno.land") - if slug != "" { - return "[" + pkgPath + "](" + pkgLink + ")." + slug - } - return "[" + pkgPath + "](" + pkgLink + ")" - } - if slug != "" { - return pkgPath + "." + slug - } - return pkgPath -} diff --git a/examples/gno.land/p/demo/fqname/fqname_test.gno b/examples/gno.land/p/demo/fqname/fqname_test.gno deleted file mode 100644 index 55a220776be..00000000000 --- a/examples/gno.land/p/demo/fqname/fqname_test.gno +++ /dev/null @@ -1,74 +0,0 @@ -package fqname - -import ( - "testing" - - "gno.land/p/demo/uassert" -) - -func TestParse(t *testing.T) { - tests := []struct { - input string - expectedPkgPath string - expectedName string - }{ - {"gno.land/p/demo/avl.Tree", "gno.land/p/demo/avl", "Tree"}, - {"gno.land/p/demo/avl", "gno.land/p/demo/avl", ""}, - {"gno.land/p/demo/avl.Tree.Node", "gno.land/p/demo/avl", "Tree.Node"}, - {"gno.land/p/demo/avl/nested.Package.Func", "gno.land/p/demo/avl/nested", "Package.Func"}, - {"path/filepath.Split", "path/filepath", "Split"}, - {"path.Split", "path", "Split"}, - {"path/filepath", "path/filepath", ""}, - {"path", "path", ""}, - {"", "", ""}, - } - - for _, tt := range tests { - pkgpath, name := Parse(tt.input) - uassert.Equal(t, tt.expectedPkgPath, pkgpath, "Package path did not match") - uassert.Equal(t, tt.expectedName, name, "Name did not match") - } -} - -func TestConstruct(t *testing.T) { - tests := []struct { - pkgpath string - name string - expected string - }{ - {"gno.land/r/demo/foo20", "GRC20", "gno.land/r/demo/foo20.GRC20"}, - {"gno.land/r/demo/foo20", "", "gno.land/r/demo/foo20"}, - {"path", "", "path"}, - {"path", "Split", "path.Split"}, - {"path/filepath", "", "path/filepath"}, - {"path/filepath", "Split", "path/filepath.Split"}, - {"", "JustName", ".JustName"}, - {"", "", ""}, - } - - for _, tt := range tests { - result := Construct(tt.pkgpath, tt.name) - uassert.Equal(t, tt.expected, result, "Constructed FQName did not match expected") - } -} - -func TestRenderLink(t *testing.T) { - tests := []struct { - pkgPath string - slug string - expected string - }{ - {"gno.land/p/demo/avl", "Tree", "[gno.land/p/demo/avl](/p/demo/avl).Tree"}, - {"gno.land/p/demo/avl", "", "[gno.land/p/demo/avl](/p/demo/avl)"}, - {"github.com/a/b", "C", "github.com/a/b.C"}, - {"example.com/pkg", "Func", "example.com/pkg.Func"}, - {"gno.land/r/demo/foo20", "GRC20", "[gno.land/r/demo/foo20](/r/demo/foo20).GRC20"}, - {"gno.land/r/demo/foo20", "", "[gno.land/r/demo/foo20](/r/demo/foo20)"}, - {"", "", ""}, - } - - for _, tt := range tests { - result := RenderLink(tt.pkgPath, tt.slug) - uassert.Equal(t, tt.expected, result, "Rendered link did not match expected") - } -} diff --git a/examples/gno.land/p/demo/fqname/gno.mod b/examples/gno.land/p/demo/fqname/gno.mod deleted file mode 100644 index 1282e262303..00000000000 --- a/examples/gno.land/p/demo/fqname/gno.mod +++ /dev/null @@ -1,3 +0,0 @@ -module gno.land/p/demo/fqname - -require gno.land/p/demo/uassert v0.0.0-latest diff --git a/examples/gno.land/p/demo/grc/grc20/token.gno b/examples/gno.land/p/demo/grc/grc20/token.gno index c9e125261b5..e13599e90bb 100644 --- a/examples/gno.land/p/demo/grc/grc20/token.gno +++ b/examples/gno.land/p/demo/grc/grc20/token.gno @@ -2,12 +2,14 @@ package grc20 import ( "std" + + "gno.land/p/demo/grc/exts" ) // token implements the Token interface. // // It is generated with Banker.Token(). -// It can safely be exposed publicly. +// It can safely be explosed publicly. type token struct { banker *Banker } @@ -43,3 +45,44 @@ func (t *token) TransferFrom(from, to std.Address, amount uint64) error { } return t.banker.Transfer(from, to, amount) } + +type Token2 interface { + exts.TokenMetadata + + // Returns the amount of tokens in existence. + TotalSupply() uint64 + + // Returns the amount of tokens owned by `account`. + BalanceOf(account std.Address) uint64 + + // Moves `amount` tokens from the caller's account to `to`. + // + // Returns an error if the operation failed. + Transfer(to std.Address, amount uint64) error + + // Returns the remaining number of tokens that `spender` will be + // allowed to spend on behalf of `owner` through {transferFrom}. This is + // zero by default. + // + // This value changes when {approve} or {transferFrom} are called. + Allowance(owner, spender std.Address) uint64 + + // Sets `amount` as the allowance of `spender` over the caller's tokens. + // + // Returns an error if the operation failed. + // + // IMPORTANT: Beware that changing an allowance with this method brings the risk + // that someone may use both the old and the new allowance by unfortunate + // transaction ordering. One possible solution to mitigate this race + // condition is to first reduce the spender's allowance to 0 and set the + // desired value afterwards: + // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + Approve(spender std.Address, amount uint64) error + + // Moves `amount` tokens from `from` to `to` using the + // allowance mechanism. `amount` is then deducted from the caller's + // allowance. + // + // Returns an error if the operation failed. + TransferFrom(from, to std.Address, amount uint64) error +} diff --git a/examples/gno.land/p/demo/grc/grc721/errors.gno b/examples/gno.land/p/demo/grc/grc721/errors.gno index 2d512db350d..be78990a059 100644 --- a/examples/gno.land/p/demo/grc/grc721/errors.gno +++ b/examples/gno.land/p/demo/grc/grc721/errors.gno @@ -13,6 +13,7 @@ var ( ErrTransferFromIncorrectOwner = errors.New("transfer from incorrect owner") ErrTransferToNonGRC721Receiver = errors.New("transfer to non GRC721Receiver implementer") ErrCallerIsNotOwnerOrApproved = errors.New("caller is not token owner or approved") + ErrTokenURINotSet = errors.New("tokeURIs not set") ErrTokenIdAlreadyExists = errors.New("token id already exists") // ERC721Royalty diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno index 8926fe1d6de..ce05426f585 100644 --- a/examples/gno.land/p/demo/int256/arithmetic.gno +++ b/examples/gno.land/p/demo/int256/arithmetic.gno @@ -5,23 +5,23 @@ import "gno.land/p/demo/uint256" func (z *Int) Add(x, y *Int) *Int { z.initiateAbs() + neg := x.neg + if x.neg == y.neg { - // If both numbers have the same sign, add their absolute values - z.abs.Add(x.abs, y.abs) - z.neg = x.neg + // x + y == x + y + // (-x) + (-y) == -(x + y) + z.abs = z.abs.Add(x.abs, y.abs) } else { - switch x.abs.Cmp(y.abs) { - case 1: // x > y - z.abs.Sub(x.abs, y.abs) - z.neg = x.neg - case -1: // x < y - z.abs.Sub(y.abs, x.abs) - z.neg = y.neg - case 0: // x == y - z.abs = uint256.NewUint(0) + // x + (-y) == x - y == -(y - x) + // (-x) + y == y - x == -(x - y) + if x.abs.Cmp(y.abs) >= 0 { + z.abs = z.abs.Sub(x.abs, y.abs) + } else { + neg = !neg + z.abs = z.abs.Sub(y.abs, x.abs) } } - + z.neg = neg // 0 has no sign return z } @@ -66,27 +66,22 @@ func AddDeltaOverflow(z, x *uint256.Uint, y *Int) bool { func (z *Int) Sub(x, y *Int) *Int { z.initiateAbs() + neg := x.neg if x.neg != y.neg { - // If sign are different, add the absolute values - z.abs.Add(x.abs, y.abs) - z.neg = x.neg + // x - (-y) == x + y + // (-x) - y == -(x + y) + z.abs = z.abs.Add(x.abs, y.abs) } else { - switch x.abs.Cmp(y.abs) { - case 1: // x > y - z.abs.Sub(x.abs, y.abs) - z.neg = x.neg - case -1: // x < y - z.abs.Sub(y.abs, x.abs) - z.neg = !x.neg - case 0: // x == y - z.abs = uint256.NewUint(0) + // x - y == x - y == -(y - x) + // (-x) - (-y) == y - x == -(x - y) + if x.abs.Cmp(y.abs) >= 0 { + z.abs = z.abs.Sub(x.abs, y.abs) + } else { + neg = !neg + z.abs = z.abs.Sub(y.abs, x.abs) } } - - // Ensure zero is always positive - if z.abs.IsZero() { - z.neg = false - } + z.neg = neg // 0 has no sign return z } @@ -112,7 +107,7 @@ func (z *Int) Mul(x, y *Int) *Int { z.initiateAbs() z.abs = z.abs.Mul(x.abs, y.abs) - z.neg = x.neg != y.neg && !z.abs.IsZero() // 0 has no sign + z.neg = x.neg != y.neg // 0 has no sign return z } @@ -131,13 +126,12 @@ func (z *Int) MulUint256(x *Int, y *uint256.Uint) *Int { func (z *Int) Div(x, y *Int) *Int { z.initiateAbs() - if y.abs.IsZero() { - panic("division by zero") - } - z.abs.Div(x.abs, y.abs) - z.neg = (x.neg != y.neg) && !z.abs.IsZero() // 0 has no sign - + if x.neg == y.neg { + z.neg = false + } else { + z.neg = true + } return z } diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gno b/examples/gno.land/p/demo/int256/arithmetic_test.gno index 4cfa306890a..c4aeb18e3c5 100644 --- a/examples/gno.land/p/demo/int256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/int256/arithmetic_test.gno @@ -15,9 +15,8 @@ func TestAdd(t *testing.T) { {"1", "1", "2"}, {"1", "2", "3"}, // NEGATIVE - {"-1", "1", "0"}, + {"-1", "1", "-0"}, // TODO: remove negative sign for 0 ?? {"1", "-1", "0"}, - {"3", "-3", "0"}, {"-1", "-1", "-2"}, {"-1", "-2", "-3"}, {"-1", "3", "2"}, @@ -189,10 +188,10 @@ func TestSub(t *testing.T) { {"1", "1", "0"}, {"-1", "1", "-2"}, {"1", "-1", "2"}, - {"-1", "-1", "0"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0"}, + {"-1", "-1", "-0"}, + {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", "-0"}, {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "-115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - {x: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", y: "1", want: "0"}, + {x: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", y: "1", want: "-0"}, } for _, tc := range tests { @@ -352,45 +351,46 @@ func TestMulUint256(t *testing.T) { func TestDiv(t *testing.T) { tests := []struct { - x, y, expected string + x, y, want string }{ - {"1", "1", "1"}, {"0", "1", "0"}, - {"-1", "1", "-1"}, - {"1", "-1", "-1"}, - {"-1", "-1", "1"}, - {"-6", "3", "-2"}, - {"10", "-2", "-5"}, - {"-10", "3", "-3"}, - {"7", "3", "2"}, - {"-7", "3", "-2"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "2", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // Max uint256 / 2 + {"0", "-1", "-0"}, + {"10", "0", "0"}, + {"10", "1", "10"}, + {"10", "-1", "-10"}, + {"-10", "0", "-0"}, + {"-10", "1", "-10"}, + {"-10", "-1", "10"}, + {"10", "-3", "-3"}, + {"10", "3", "3"}, } - for _, tt := range tests { - t.Run(tt.x+"/"+tt.y, func(t *testing.T) { - x := MustFromDecimal(tt.x) - y := MustFromDecimal(tt.y) - result := Zero().Div(x, y) - if result.ToString() != tt.expected { - t.Errorf("Div(%s, %s) = %s, want %s", tt.x, tt.y, result.ToString(), tt.expected) - } - if result.abs.IsZero() && result.neg { - t.Errorf("Div(%s, %s) resulted in negative zero", tt.x, tt.y) - } - }) - } + for _, tc := range tests { + x, err := FromDecimal(tc.x) + if err != nil { + t.Error(err) + continue + } - t.Run("Division by zero", func(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("Div(1, 0) did not panic") - } - }() - x := MustFromDecimal("1") - y := MustFromDecimal("0") - Zero().Div(x, y) - }) + y, err := FromDecimal(tc.y) + if err != nil { + t.Error(err) + continue + } + + want, err := FromDecimal(tc.want) + if err != nil { + t.Error(err) + continue + } + + got := New() + got.Div(x, y) + + if got.Neq(want) { + t.Errorf("Div(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + } + } } func TestDivUint256(t *testing.T) { diff --git a/examples/gno.land/p/demo/int256/conversion.gno b/examples/gno.land/p/demo/int256/conversion.gno index 9e264e7e46b..ee6e7560f15 100644 --- a/examples/gno.land/p/demo/int256/conversion.gno +++ b/examples/gno.land/p/demo/int256/conversion.gno @@ -82,6 +82,5 @@ func (z *Int) ToString() string { if z.neg { return "-" + t } - return t } diff --git a/examples/gno.land/p/demo/int256/conversion_test.gno b/examples/gno.land/p/demo/int256/conversion_test.gno index b085a77a15a..da54c226669 100644 --- a/examples/gno.land/p/demo/int256/conversion_test.gno +++ b/examples/gno.land/p/demo/int256/conversion_test.gno @@ -169,66 +169,3 @@ func TestSetUint256(t *testing.T) { } } } - -func TestToString(t *testing.T) { - tests := []struct { - name string - setup func() *Int - expected string - }{ - { - name: "Zero from subtraction", - setup: func() *Int { - minusThree := MustFromDecimal("-3") - three := MustFromDecimal("3") - return Zero().Add(minusThree, three) - }, - expected: "0", - }, - { - name: "Zero from right shift", - setup: func() *Int { - return Zero().Rsh(One(), 1234) - }, - expected: "0", - }, - { - name: "Positive number", - setup: func() *Int { - return MustFromDecimal("42") - }, - expected: "42", - }, - { - name: "Negative number", - setup: func() *Int { - return MustFromDecimal("-42") - }, - expected: "-42", - }, - { - name: "Large positive number", - setup: func() *Int { - return MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935") - }, - expected: "115792089237316195423570985008687907853269984665640564039457584007913129639935", - }, - { - name: "Large negative number", - setup: func() *Int { - return MustFromDecimal("-115792089237316195423570985008687907853269984665640564039457584007913129639935") - }, - expected: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - z := tt.setup() - result := z.ToString() - if result != tt.expected { - t.Errorf("ToString() = %s, want %s", result, tt.expected) - } - }) - } -} diff --git a/examples/gno.land/p/demo/merkle/merkle.gno b/examples/gno.land/p/demo/merkle/merkle.gno index f4fcc4dad40..54b878bffb1 100644 --- a/examples/gno.land/p/demo/merkle/merkle.gno +++ b/examples/gno.land/p/demo/merkle/merkle.gno @@ -19,17 +19,6 @@ type Node struct { position uint8 } -func NewNode(hash []byte, position uint8) Node { - return Node{ - hash: hash, - position: position, - } -} - -func (n Node) Position() uint8 { - return n.position -} - func (n Node) Hash() string { return hex.EncodeToString(n.hash[:]) } diff --git a/examples/gno.land/p/demo/ownable/errors.gno b/examples/gno.land/p/demo/ownable/errors.gno index 89776a6cf12..ffbf6ab3f6f 100644 --- a/examples/gno.land/p/demo/ownable/errors.gno +++ b/examples/gno.land/p/demo/ownable/errors.gno @@ -3,6 +3,6 @@ package ownable import "errors" var ( - ErrUnauthorized = errors.New("ownable: caller is not owner") - ErrInvalidAddress = errors.New("ownable: new owner address is invalid") + ErrUnauthorized = errors.New("unauthorized; caller is not owner") + ErrInvalidAddress = errors.New("new owner address is invalid") ) diff --git a/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable.gno b/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable.gno deleted file mode 100644 index f9f0ea15dd9..00000000000 --- a/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable.gno +++ /dev/null @@ -1,90 +0,0 @@ -// Package authorizable is an extension of p/demo/ownable; -// It allows the user to instantiate an Authorizable struct, which extends -// p/demo/ownable with a list of users that are authorized for something. -// By using authorizable, you have a superuser (ownable), as well as another -// authorization level, which can be used for adding moderators or similar to your realm. -package authorizable - -import ( - "std" - - "gno.land/p/demo/avl" - "gno.land/p/demo/ownable" - "gno.land/p/demo/ufmt" -) - -type Authorizable struct { - *ownable.Ownable // owner in ownable is superuser - authorized *avl.Tree // std.Addr > struct{}{} -} - -func NewAuthorizable() *Authorizable { - a := &Authorizable{ - ownable.New(), - avl.NewTree(), - } - - // Add owner to auth list - a.authorized.Set(a.Owner().String(), struct{}{}) - return a -} - -func NewAuthorizableWithAddress(addr std.Address) *Authorizable { - a := &Authorizable{ - ownable.NewWithAddress(addr), - avl.NewTree(), - } - - // Add owner to auth list - a.authorized.Set(a.Owner().String(), struct{}{}) - return a -} - -func (a *Authorizable) AddToAuthList(addr std.Address) error { - if err := a.CallerIsOwner(); err != nil { - return ErrNotSuperuser - } - - if _, exists := a.authorized.Get(addr.String()); exists { - return ErrAlreadyInList - } - - a.authorized.Set(addr.String(), struct{}{}) - - return nil -} - -func (a *Authorizable) DeleteFromAuthList(addr std.Address) error { - if err := a.CallerIsOwner(); err != nil { - return ErrNotSuperuser - } - - if !a.authorized.Has(addr.String()) { - return ErrNotInAuthList - } - - if _, removed := a.authorized.Remove(addr.String()); !removed { - str := ufmt.Sprintf("authorizable: could not remove %s from auth list", addr.String()) - panic(str) - } - - return nil -} - -func (a Authorizable) CallerOnAuthList() error { - caller := std.PrevRealm().Addr() - - if !a.authorized.Has(caller.String()) { - return ErrNotInAuthList - } - - return nil -} - -func (a Authorizable) AssertOnAuthList() { - caller := std.PrevRealm().Addr() - - if !a.authorized.Has(caller.String()) { - panic(ErrNotInAuthList) - } -} diff --git a/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable_test.gno b/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable_test.gno deleted file mode 100644 index 10a5e411bdb..00000000000 --- a/examples/gno.land/p/demo/ownable/exts/authorizable/authorizable_test.gno +++ /dev/null @@ -1,116 +0,0 @@ -package authorizable - -import ( - "std" - "testing" - - "gno.land/p/demo/testutils" - "gno.land/p/demo/uassert" -) - -var ( - alice = testutils.TestAddress("alice") - bob = testutils.TestAddress("bob") - charlie = testutils.TestAddress("charlie") -) - -func TestNewAuthorizable(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - std.TestSetOrigCaller(alice) // TODO(bug, issue #2371): should not be needed - - a := NewAuthorizable() - got := a.Owner() - - if alice != got { - t.Fatalf("Expected %s, got: %s", alice, got) - } -} - -func TestNewAuthorizableWithAddress(t *testing.T) { - a := NewAuthorizableWithAddress(alice) - - got := a.Owner() - - if alice != got { - t.Fatalf("Expected %s, got: %s", alice, got) - } -} - -func TestCallerOnAuthList(t *testing.T) { - a := NewAuthorizableWithAddress(alice) - std.TestSetRealm(std.NewUserRealm(alice)) - std.TestSetOrigCaller(alice) - - if err := a.CallerOnAuthList(); err == ErrNotInAuthList { - t.Fatalf("expected alice to be on the list") - } -} - -func TestNotCallerOnAuthList(t *testing.T) { - a := NewAuthorizableWithAddress(alice) - std.TestSetRealm(std.NewUserRealm(bob)) - std.TestSetOrigCaller(bob) - - if err := a.CallerOnAuthList(); err == nil { - t.Fatalf("expected bob to not be on the list") - } -} - -func TestAddToAuthList(t *testing.T) { - a := NewAuthorizableWithAddress(alice) - std.TestSetRealm(std.NewUserRealm(alice)) - std.TestSetOrigCaller(alice) - - if err := a.AddToAuthList(bob); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - std.TestSetRealm(std.NewUserRealm(bob)) - std.TestSetOrigCaller(bob) - - if err := a.AddToAuthList(bob); err == nil { - t.Fatalf("Expected AddToAuth to error while bob called it, but it didn't") - } -} - -func TestDeleteFromList(t *testing.T) { - a := NewAuthorizableWithAddress(alice) - std.TestSetRealm(std.NewUserRealm(alice)) - std.TestSetOrigCaller(alice) - - if err := a.AddToAuthList(bob); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - if err := a.AddToAuthList(charlie); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - std.TestSetRealm(std.NewUserRealm(bob)) - std.TestSetOrigCaller(bob) - - // Try an unauthorized deletion - if err := a.DeleteFromAuthList(alice); err == nil { - t.Fatalf("Expected DelFromAuth to error with %v", err) - } - - std.TestSetRealm(std.NewUserRealm(alice)) - std.TestSetOrigCaller(alice) - - if err := a.DeleteFromAuthList(charlie); err != nil { - t.Fatalf("Expected no error, got %v", err) - } -} - -func TestAssertOnList(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - std.TestSetOrigCaller(alice) - a := NewAuthorizableWithAddress(alice) - - std.TestSetRealm(std.NewUserRealm(bob)) - std.TestSetOrigCaller(bob) - - uassert.PanicsWithMessage(t, ErrNotInAuthList.Error(), func() { - a.AssertOnAuthList() - }) -} diff --git a/examples/gno.land/p/demo/ownable/exts/authorizable/errors.gno b/examples/gno.land/p/demo/ownable/exts/authorizable/errors.gno deleted file mode 100644 index 4ba5983bccb..00000000000 --- a/examples/gno.land/p/demo/ownable/exts/authorizable/errors.gno +++ /dev/null @@ -1,9 +0,0 @@ -package authorizable - -import "errors" - -var ( - ErrNotInAuthList = errors.New("authorizable: caller is not in authorized list") - ErrNotSuperuser = errors.New("authorizable: caller is not superuser") - ErrAlreadyInList = errors.New("authorizable: address is already in authorized list") -) diff --git a/examples/gno.land/p/demo/ownable/exts/authorizable/gno.mod b/examples/gno.land/p/demo/ownable/exts/authorizable/gno.mod deleted file mode 100644 index f36823f3f71..00000000000 --- a/examples/gno.land/p/demo/ownable/exts/authorizable/gno.mod +++ /dev/null @@ -1,9 +0,0 @@ -module gno.land/p/demo/ownable/exts/authorizable - -require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/ownable v0.0.0-latest - gno.land/p/demo/testutils v0.0.0-latest - gno.land/p/demo/uassert v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest -) diff --git a/examples/gno.land/p/demo/ownable/ownable.gno b/examples/gno.land/p/demo/ownable/ownable.gno index a77b22461a9..75ebcde0a28 100644 --- a/examples/gno.land/p/demo/ownable/ownable.gno +++ b/examples/gno.land/p/demo/ownable/ownable.gno @@ -1,6 +1,8 @@ package ownable -import "std" +import ( + "std" +) const OwnershipTransferEvent = "OwnershipTransfer" @@ -17,9 +19,7 @@ func New() *Ownable { } func NewWithAddress(addr std.Address) *Ownable { - return &Ownable{ - owner: addr, - } + return &Ownable{owner: addr} } // TransferOwnership transfers ownership of the Ownable struct to a new address @@ -40,7 +40,6 @@ func (o *Ownable) TransferOwnership(newOwner std.Address) error { "from", string(prevOwner), "to", string(newOwner), ) - return nil } @@ -65,7 +64,6 @@ func (o *Ownable) DropOwnership() error { return nil } -// Owner returns the owner address from Ownable func (o Ownable) Owner() std.Address { return o.owner } @@ -75,11 +73,9 @@ func (o Ownable) CallerIsOwner() error { if std.PrevRealm().Addr() == o.owner { return nil } - return ErrUnauthorized } -// AssertCallerIsOwner panics if the caller is not the owner func (o Ownable) AssertCallerIsOwner() { if std.PrevRealm().Addr() != o.owner { panic(ErrUnauthorized) diff --git a/examples/gno.land/p/demo/ownable/ownable_test.gno b/examples/gno.land/p/demo/ownable/ownable_test.gno index a9d97154f45..6217948d587 100644 --- a/examples/gno.land/p/demo/ownable/ownable_test.gno +++ b/examples/gno.land/p/demo/ownable/ownable_test.gno @@ -9,60 +9,52 @@ import ( ) var ( - alice = testutils.TestAddress("alice") - bob = testutils.TestAddress("bob") + firstCaller = testutils.TestAddress("first") + secondCaller = testutils.TestAddress("second") ) func TestNew(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - std.TestSetOrigCaller(alice) // TODO(bug): should not be needed + std.TestSetRealm(std.NewUserRealm(firstCaller)) + std.TestSetOrigCaller(firstCaller) // TODO(bug): should not be needed o := New() got := o.Owner() - if alice != got { - t.Fatalf("Expected %s, got: %s", alice, got) - } + uassert.Equal(t, firstCaller, got) } func TestNewWithAddress(t *testing.T) { - o := NewWithAddress(alice) + o := NewWithAddress(firstCaller) got := o.Owner() - if alice != got { - t.Fatalf("Expected %s, got: %s", alice, got) - } + uassert.Equal(t, firstCaller, got) } func TestOwner(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) + std.TestSetRealm(std.NewUserRealm(firstCaller)) o := New() - expected := alice + expected := firstCaller got := o.Owner() uassert.Equal(t, expected, got) } func TestTransferOwnership(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) + std.TestSetRealm(std.NewUserRealm(firstCaller)) o := New() - err := o.TransferOwnership(bob) - if err != nil { - t.Fatalf("TransferOwnership failed, %v", err) - } + err := o.TransferOwnership(secondCaller) + uassert.NoError(t, err, "TransferOwnership failed") got := o.Owner() - if bob != got { - t.Fatalf("Expected: %s, got: %s", bob, got) - } + uassert.Equal(t, secondCaller, got) } func TestCallerIsOwner(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) + std.TestSetRealm(std.NewUserRealm(firstCaller)) o := New() - unauthorizedCaller := bob + unauthorizedCaller := secondCaller std.TestSetRealm(std.NewUserRealm(unauthorizedCaller)) std.TestSetOrigCaller(unauthorizedCaller) // TODO(bug): should not be needed @@ -72,7 +64,7 @@ func TestCallerIsOwner(t *testing.T) { } func TestDropOwnership(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) + std.TestSetRealm(std.NewUserRealm(firstCaller)) o := New() @@ -86,25 +78,23 @@ func TestDropOwnership(t *testing.T) { // Errors func TestErrUnauthorized(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - std.TestSetOrigCaller(alice) // TODO(bug): should not be needed + std.TestSetRealm(std.NewUserRealm(firstCaller)) + std.TestSetOrigCaller(firstCaller) // TODO(bug): should not be needed o := New() - std.TestSetRealm(std.NewUserRealm(bob)) - std.TestSetOrigCaller(bob) // TODO(bug): should not be needed + std.TestSetRealm(std.NewUserRealm(secondCaller)) + std.TestSetOrigCaller(secondCaller) // TODO(bug): should not be needed - err := o.TransferOwnership(alice) - if err != ErrUnauthorized { - t.Fatalf("Should've been ErrUnauthorized, was %v", err) - } + err := o.TransferOwnership(firstCaller) + uassert.ErrorContains(t, err, ErrUnauthorized.Error()) err = o.DropOwnership() uassert.ErrorContains(t, err, ErrUnauthorized.Error()) } func TestErrInvalidAddress(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) + std.TestSetRealm(std.NewUserRealm(firstCaller)) o := New() diff --git a/examples/gno.land/p/demo/subscription/doc.gno b/examples/gno.land/p/demo/subscription/doc.gno deleted file mode 100644 index 9cc102fcc9a..00000000000 --- a/examples/gno.land/p/demo/subscription/doc.gno +++ /dev/null @@ -1,66 +0,0 @@ -// Package subscription provides a flexible system for managing both recurring and -// lifetime subscriptions in Gno applications. It enables developers to handle -// payment-based access control for services or products. The library supports -// both subscriptions requiring periodic payments (recurring) and one-time payments -// (lifetime). Subscriptions are tracked using an AVL tree for efficient management -// of subscription statuses. -// -// Usage: -// -// Import the required sub-packages (`recurring` and/or `lifetime`) to manage specific -// subscription types. The methods provided allow users to subscribe, check subscription -// status, and manage payments. -// -// Recurring Subscription: -// -// Recurring subscriptions require periodic payments to maintain access. -// Users pay to extend their access for a specific duration. -// -// Example: -// -// // Create a recurring subscription requiring 100 ugnot every 30 days -// recSub := recurring.NewRecurringSubscription(time.Hour * 24 * 30, 100) -// -// // Process payment for the recurring subscription -// recSub.Subscribe() -// -// // Gift a recurring subscription to another user -// recSub.GiftSubscription(recipientAddress) -// -// // Check if a user has a valid subscription -// recSub.HasValidSubscription(addr) -// -// // Get the expiration date of the subscription -// recSub.GetExpiration(caller) -// -// // Update the subscription amount to 200 ugnot -// recSub.UpdateAmount(200) -// -// // Get the current subscription amount -// recSub.GetAmount() -// -// Lifetime Subscription: -// -// Lifetime subscriptions require a one-time payment for permanent access. -// Once paid, users have indefinite access without further payments. -// -// Example: -// -// // Create a lifetime subscription costing 500 ugnot -// lifeSub := lifetime.NewLifetimeSubscription(500) -// -// // Process payment for lifetime access -// lifeSub.Subscribe() -// -// // Gift a lifetime subscription to another user -// lifeSub.GiftSubscription(recipientAddress) -// -// // Check if a user has a valid subscription -// lifeSub.HasValidSubscription(addr) -// -// // Update the lifetime subscription amount to 1000 ugnot -// lifeSub.UpdateAmount(1000) -// -// // Get the current lifetime subscription amount -// lifeSub.GetAmount() -package subscription diff --git a/examples/gno.land/p/demo/subscription/gno.mod b/examples/gno.land/p/demo/subscription/gno.mod deleted file mode 100644 index ea60a4c628a..00000000000 --- a/examples/gno.land/p/demo/subscription/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/p/demo/subscription diff --git a/examples/gno.land/p/demo/subscription/lifetime/errors.gno b/examples/gno.land/p/demo/subscription/lifetime/errors.gno deleted file mode 100644 index faeda4cd9fe..00000000000 --- a/examples/gno.land/p/demo/subscription/lifetime/errors.gno +++ /dev/null @@ -1,10 +0,0 @@ -package lifetime - -import "errors" - -var ( - ErrNoSub = errors.New("lifetime subscription: no active subscription found") - ErrAmt = errors.New("lifetime subscription: payment amount does not match the required subscription amount") - ErrAlreadySub = errors.New("lifetime subscription: this address already has an active lifetime subscription") - ErrNotAuthorized = errors.New("lifetime subscription: action not authorized") -) diff --git a/examples/gno.land/p/demo/subscription/lifetime/gno.mod b/examples/gno.land/p/demo/subscription/lifetime/gno.mod deleted file mode 100644 index 0084aa714c5..00000000000 --- a/examples/gno.land/p/demo/subscription/lifetime/gno.mod +++ /dev/null @@ -1,8 +0,0 @@ -module gno.land/p/demo/subscription/lifetime - -require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/ownable v0.0.0-latest - gno.land/p/demo/testutils v0.0.0-latest - gno.land/p/demo/uassert v0.0.0-latest -) diff --git a/examples/gno.land/p/demo/subscription/lifetime/lifetime.gno b/examples/gno.land/p/demo/subscription/lifetime/lifetime.gno deleted file mode 100644 index 8a4c10b687b..00000000000 --- a/examples/gno.land/p/demo/subscription/lifetime/lifetime.gno +++ /dev/null @@ -1,81 +0,0 @@ -package lifetime - -import ( - "std" - - "gno.land/p/demo/avl" - "gno.land/p/demo/ownable" -) - -// LifetimeSubscription represents a subscription that requires only a one-time payment. -// It grants permanent access to a service or product. -type LifetimeSubscription struct { - ownable.Ownable - amount int64 - subs *avl.Tree // std.Address -> bool -} - -// NewLifetimeSubscription creates and returns a new lifetime subscription. -func NewLifetimeSubscription(amount int64) *LifetimeSubscription { - return &LifetimeSubscription{ - Ownable: *ownable.New(), - amount: amount, - subs: avl.NewTree(), - } -} - -// processSubscription handles the subscription process for a given receiver. -func (ls *LifetimeSubscription) processSubscription(receiver std.Address) error { - amount := std.GetOrigSend() - - if amount.AmountOf("ugnot") != ls.amount { - return ErrAmt - } - - _, exists := ls.subs.Get(receiver.String()) - - if exists { - return ErrAlreadySub - } - - ls.subs.Set(receiver.String(), true) - - return nil -} - -// Subscribe processes the payment for a lifetime subscription. -func (ls *LifetimeSubscription) Subscribe() error { - caller := std.PrevRealm().Addr() - return ls.processSubscription(caller) -} - -// GiftSubscription allows the caller to pay for a lifetime subscription for another user. -func (ls *LifetimeSubscription) GiftSubscription(receiver std.Address) error { - return ls.processSubscription(receiver) -} - -// HasValidSubscription checks if the given address has an active lifetime subscription. -func (ls *LifetimeSubscription) HasValidSubscription(addr std.Address) error { - _, exists := ls.subs.Get(addr.String()) - - if !exists { - return ErrNoSub - } - - return nil -} - -// UpdateAmount allows the owner of the LifetimeSubscription contract to update the subscription price. -func (ls *LifetimeSubscription) UpdateAmount(newAmount int64) error { - if err := ls.CallerIsOwner(); err != nil { - return ErrNotAuthorized - } - - ls.amount = newAmount - return nil -} - -// GetAmount returns the current subscription price. -func (ls *LifetimeSubscription) GetAmount() int64 { - return ls.amount -} diff --git a/examples/gno.land/p/demo/subscription/lifetime/lifetime_test.gno b/examples/gno.land/p/demo/subscription/lifetime/lifetime_test.gno deleted file mode 100644 index efbae90c11c..00000000000 --- a/examples/gno.land/p/demo/subscription/lifetime/lifetime_test.gno +++ /dev/null @@ -1,105 +0,0 @@ -package lifetime - -import ( - "std" - "testing" - - "gno.land/p/demo/testutils" - "gno.land/p/demo/uassert" -) - -var ( - alice = testutils.TestAddress("alice") - bob = testutils.TestAddress("bob") - charlie = testutils.TestAddress("charlie") -) - -func TestLifetimeSubscription(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - ls := NewLifetimeSubscription(1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err := ls.Subscribe() - uassert.NoError(t, err, "Expected ProcessPayment to succeed") - - err = ls.HasValidSubscription(std.PrevRealm().Addr()) - uassert.NoError(t, err, "Expected Alice to have access") -} - -func TestLifetimeSubscriptionGift(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - ls := NewLifetimeSubscription(1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err := ls.GiftSubscription(bob) - uassert.NoError(t, err, "Expected ProcessPaymentGift to succeed for Bob") - - err = ls.HasValidSubscription(bob) - uassert.NoError(t, err, "Expected Bob to have access") - - err = ls.HasValidSubscription(charlie) - uassert.Error(t, err, "Expected Charlie to fail access check") -} - -func TestUpdateAmountAuthorization(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - ls := NewLifetimeSubscription(1000) - - err := ls.UpdateAmount(2000) - uassert.NoError(t, err, "Expected Alice to succeed in updating amount") - - std.TestSetOrigCaller(bob) - - err = ls.UpdateAmount(3000) - uassert.Error(t, err, "Expected Bob to fail when updating amount") -} - -func TestIncorrectPaymentAmount(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - ls := NewLifetimeSubscription(1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 500}}, nil) - err := ls.Subscribe() - uassert.Error(t, err, "Expected payment to fail with incorrect amount") -} - -func TestMultipleSubscriptionAttempts(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - ls := NewLifetimeSubscription(1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err := ls.Subscribe() - uassert.NoError(t, err, "Expected first subscription to succeed") - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err = ls.Subscribe() - uassert.Error(t, err, "Expected second subscription to fail as Alice is already subscribed") -} - -func TestGiftSubscriptionWithIncorrectAmount(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - ls := NewLifetimeSubscription(1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 500}}, nil) - err := ls.GiftSubscription(bob) - uassert.Error(t, err, "Expected gift subscription to fail with incorrect amount") - - err = ls.HasValidSubscription(bob) - uassert.Error(t, err, "Expected Bob to not have access after incorrect gift subscription") -} - -func TestUpdateAmountEffectiveness(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - ls := NewLifetimeSubscription(1000) - - err := ls.UpdateAmount(2000) - uassert.NoError(t, err, "Expected Alice to succeed in updating amount") - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err = ls.Subscribe() - uassert.Error(t, err, "Expected subscription to fail with old amount after update") - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 2000}}, nil) - err = ls.Subscribe() - uassert.NoError(t, err, "Expected subscription to succeed with new amount") -} diff --git a/examples/gno.land/p/demo/subscription/recurring/errors.gno b/examples/gno.land/p/demo/subscription/recurring/errors.gno deleted file mode 100644 index 76a55e069bf..00000000000 --- a/examples/gno.land/p/demo/subscription/recurring/errors.gno +++ /dev/null @@ -1,11 +0,0 @@ -package recurring - -import "errors" - -var ( - ErrNoSub = errors.New("recurring subscription: no active subscription found") - ErrSubExpired = errors.New("recurring subscription: your subscription has expired") - ErrAmt = errors.New("recurring subscription: payment amount does not match the required subscription amount") - ErrAlreadySub = errors.New("recurring subscription: this address already has an active subscription") - ErrNotAuthorized = errors.New("recurring subscription: action not authorized") -) diff --git a/examples/gno.land/p/demo/subscription/recurring/gno.mod b/examples/gno.land/p/demo/subscription/recurring/gno.mod deleted file mode 100644 index d3cf8a044f8..00000000000 --- a/examples/gno.land/p/demo/subscription/recurring/gno.mod +++ /dev/null @@ -1,8 +0,0 @@ -module gno.land/p/demo/subscription/recurring - -require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/ownable v0.0.0-latest - gno.land/p/demo/testutils v0.0.0-latest - gno.land/p/demo/uassert v0.0.0-latest -) diff --git a/examples/gno.land/p/demo/subscription/recurring/recurring.gno b/examples/gno.land/p/demo/subscription/recurring/recurring.gno deleted file mode 100644 index b5277bd716e..00000000000 --- a/examples/gno.land/p/demo/subscription/recurring/recurring.gno +++ /dev/null @@ -1,104 +0,0 @@ -package recurring - -import ( - "std" - "time" - - "gno.land/p/demo/avl" - "gno.land/p/demo/ownable" -) - -// RecurringSubscription represents a subscription that requires periodic payments. -// It includes the duration of the subscription and the amount required per period. -type RecurringSubscription struct { - ownable.Ownable - duration time.Duration - amount int64 - subs *avl.Tree // std.Address -> time.Time -} - -// NewRecurringSubscription creates and returns a new recurring subscription. -func NewRecurringSubscription(duration time.Duration, amount int64) *RecurringSubscription { - return &RecurringSubscription{ - Ownable: *ownable.New(), - duration: duration, - amount: amount, - subs: avl.NewTree(), - } -} - -// HasValidSubscription verifies if the caller has an active recurring subscription. -func (rs *RecurringSubscription) HasValidSubscription(addr std.Address) error { - expTime, exists := rs.subs.Get(addr.String()) - if !exists { - return ErrNoSub - } - - if time.Now().After(expTime.(time.Time)) { - return ErrSubExpired - } - - return nil -} - -// processSubscription processes the payment for a given receiver and renews or adds their subscription. -func (rs *RecurringSubscription) processSubscription(receiver std.Address) error { - amount := std.GetOrigSend() - - if amount.AmountOf("ugnot") != rs.amount { - return ErrAmt - } - - expTime, exists := rs.subs.Get(receiver.String()) - - // If the user is already a subscriber but his subscription has expired, authorize renewal - if exists { - expiration := expTime.(time.Time) - if time.Now().Before(expiration) { - return ErrAlreadySub - } - } - - // Renew or add subscription - newExpiration := time.Now().Add(rs.duration) - rs.subs.Set(receiver.String(), newExpiration) - - return nil -} - -// Subscribe handles the payment for the caller's subscription. -func (rs *RecurringSubscription) Subscribe() error { - caller := std.PrevRealm().Addr() - - return rs.processSubscription(caller) -} - -// GiftSubscription allows the user to pay for a subscription for another user (receiver). -func (rs *RecurringSubscription) GiftSubscription(receiver std.Address) error { - return rs.processSubscription(receiver) -} - -// GetExpiration returns the expiration date of the recurring subscription for a given caller. -func (rs *RecurringSubscription) GetExpiration(addr std.Address) (time.Time, error) { - expTime, exists := rs.subs.Get(addr.String()) - if !exists { - return time.Time{}, ErrNoSub - } - - return expTime.(time.Time), nil -} - -// UpdateAmount allows the owner of the subscription contract to change the required subscription amount. -func (rs *RecurringSubscription) UpdateAmount(newAmount int64) error { - if err := rs.CallerIsOwner(); err != nil { - return ErrNotAuthorized - } - - rs.amount = newAmount - return nil -} - -// GetAmount returns the current amount required for each subscription period. -func (rs *RecurringSubscription) GetAmount() int64 { - return rs.amount -} diff --git a/examples/gno.land/p/demo/subscription/recurring/recurring_test.gno b/examples/gno.land/p/demo/subscription/recurring/recurring_test.gno deleted file mode 100644 index e8bca15c0bf..00000000000 --- a/examples/gno.land/p/demo/subscription/recurring/recurring_test.gno +++ /dev/null @@ -1,134 +0,0 @@ -package recurring - -import ( - "std" - "testing" - "time" - - "gno.land/p/demo/testutils" - "gno.land/p/demo/uassert" -) - -var ( - alice = testutils.TestAddress("alice") - bob = testutils.TestAddress("bob") - charlie = testutils.TestAddress("charlie") -) - -func TestRecurringSubscription(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - rs := NewRecurringSubscription(time.Hour*24, 1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err := rs.Subscribe() - uassert.NoError(t, err, "Expected ProcessPayment to succeed for Alice") - - err = rs.HasValidSubscription(std.PrevRealm().Addr()) - uassert.NoError(t, err, "Expected Alice to have access") - - expiration, err := rs.GetExpiration(std.PrevRealm().Addr()) - uassert.NoError(t, err, "Expected to get expiration for Alice") -} - -func TestRecurringSubscriptionGift(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - rs := NewRecurringSubscription(time.Hour*24, 1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err := rs.GiftSubscription(bob) - uassert.NoError(t, err, "Expected ProcessPaymentGift to succeed for Bob") - - err = rs.HasValidSubscription(bob) - uassert.NoError(t, err, "Expected Bob to have access") - - err = rs.HasValidSubscription(charlie) - uassert.Error(t, err, "Expected Charlie to fail access check") -} - -func TestRecurringSubscriptionExpiration(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - rs := NewRecurringSubscription(time.Hour, 1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err := rs.Subscribe() - uassert.NoError(t, err, "Expected ProcessPayment to succeed for Alice") - - err = rs.HasValidSubscription(std.PrevRealm().Addr()) - uassert.NoError(t, err, "Expected Alice to have access") - - expiration := time.Now().Add(-time.Hour * 2) - rs.subs.Set(std.PrevRealm().Addr().String(), expiration) - - err = rs.HasValidSubscription(std.PrevRealm().Addr()) - uassert.Error(t, err, "Expected Alice's subscription to be expired") -} - -func TestUpdateAmountAuthorization(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - rs := NewRecurringSubscription(time.Hour*24, 1000) - - err := rs.UpdateAmount(2000) - uassert.NoError(t, err, "Expected Alice to succeed in updating amount") - - std.TestSetOrigCaller(bob) - err = rs.UpdateAmount(3000) - uassert.Error(t, err, "Expected Bob to fail when updating amount") -} - -func TestGetAmount(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - rs := NewRecurringSubscription(time.Hour*24, 1000) - - amount := rs.GetAmount() - uassert.Equal(t, amount, int64(1000), "Expected the initial amount to be 1000 ugnot") - - err := rs.UpdateAmount(2000) - uassert.NoError(t, err, "Expected Alice to succeed in updating amount") - - amount = rs.GetAmount() - uassert.Equal(t, amount, int64(2000), "Expected the updated amount to be 2000 ugnot") -} - -func TestIncorrectPaymentAmount(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - rs := NewRecurringSubscription(time.Hour*24, 1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 500}}, nil) - err := rs.Subscribe() - uassert.Error(t, err, "Expected payment with incorrect amount to fail") -} - -func TestMultiplePaymentsForSameUser(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - rs := NewRecurringSubscription(time.Hour*24, 1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err := rs.Subscribe() - uassert.NoError(t, err, "Expected first ProcessPayment to succeed for Alice") - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err = rs.Subscribe() - uassert.Error(t, err, "Expected second ProcessPayment to fail for Alice due to existing subscription") -} - -func TestRecurringSubscriptionWithMultiplePayments(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - rs := NewRecurringSubscription(time.Hour, 1000) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err := rs.Subscribe() - uassert.NoError(t, err, "Expected first ProcessPayment to succeed for Alice") - - err = rs.HasValidSubscription(std.PrevRealm().Addr()) - uassert.NoError(t, err, "Expected Alice to have access after first payment") - - expiration := time.Now().Add(-time.Hour * 2) - rs.subs.Set(std.PrevRealm().Addr().String(), expiration) - - std.TestSetOrigSend([]std.Coin{{Denom: "ugnot", Amount: 1000}}, nil) - err = rs.Subscribe() - uassert.NoError(t, err, "Expected second ProcessPayment to succeed for Alice") - - err = rs.HasValidSubscription(std.PrevRealm().Addr()) - uassert.NoError(t, err, "Expected Alice to have access after second payment") -} diff --git a/examples/gno.land/p/demo/subscription/subscription.gno b/examples/gno.land/p/demo/subscription/subscription.gno deleted file mode 100644 index cc52a2c0e2d..00000000000 --- a/examples/gno.land/p/demo/subscription/subscription.gno +++ /dev/null @@ -1,12 +0,0 @@ -package subscription - -import ( - "std" -) - -// Subscription interface defines standard methods that all subscription types must implement. -type Subscription interface { - HasValidSubscription(std.Address) error - Subscribe() error - UpdateAmount(newAmount int64) error -} diff --git a/examples/gno.land/p/demo/teams/errors.gno b/examples/gno.land/p/demo/teams/errors.gno new file mode 100644 index 00000000000..a0013be32bc --- /dev/null +++ b/examples/gno.land/p/demo/teams/errors.gno @@ -0,0 +1,10 @@ +package teams + +import "errors" + +var ( + ErrTeamAddressAlreadyExists = errors.New("Team address already exists") + ErrTeamNotFound = errors.New("team not found") + ErrUserAlreadyMember = errors.New("user already a member") + ErrUserNotMember = errors.New("user not a member") +) \ No newline at end of file diff --git a/examples/gno.land/p/demo/teams/gno.mod b/examples/gno.land/p/demo/teams/gno.mod new file mode 100644 index 00000000000..6c22416633f --- /dev/null +++ b/examples/gno.land/p/demo/teams/gno.mod @@ -0,0 +1 @@ +module gno.land/p/demo/teams diff --git a/examples/gno.land/p/demo/teams/teams.gno b/examples/gno.land/p/demo/teams/teams.gno new file mode 100644 index 00000000000..19738f750f6 --- /dev/null +++ b/examples/gno.land/p/demo/teams/teams.gno @@ -0,0 +1,167 @@ +package teams + +import ( + "errors" + "std" + "gno.land/p/demo/avl" + "gno.land/p/demo/users" +) + +//---------------------------------------- +// Types + +type Team struct { + Address std.Address + TeamName string + TeamProfile string + Creator std.Address +} + +var ( + Teams avl.Tree // t.Address -> t.TeamName:t.TeamProfile + Members avl.Tree // t.Address -> []*users.User + Creators avl.Tree // t.Creator -> t.Address +) + +type TeamManager struct { + Teams *avl.Tree + Members *avl.Tree + Creators *avl.Tree +} + +func NewTeamManager() *TeamManager { + tm := &TeamManager{ + Teams: avl.NewTree(), + Members: avl.NewTree(), + Creators: avl.NewTree(), + } + return tm +} + +func (tm *TeamManager) AddTeam(t Team) error { + // Check if team already exists + if tm.Teams.Size() != 0 { + _, exist := tm.Teams.Get(t.Address.String()) + if exist { + return ErrTeamAddressAlreadyExists + } + } + + // Add the team + tm.Teams.Set(t.Address.String(), t.TeamName+":"+t.TeamProfile) + tm.Creators.Set(t.Creator.String(), t.Address.String()) + return nil +} + +func (tm *TeamManager) AddUserToTeam(teamAddress std.Address, user users.User) error { + // Check if the team exists + _, teamExists := tm.Teams.Get(teamAddress.String()) + if !teamExists { + return ErrTeamNotFound + } + + // Get current members + members, _ := tm.Members.Get(teamAddress.String()) + var memberList []*users.User + if members != nil { + memberList = members.([]*users.User) + } else { + memberList = []*users.User{} + } + + // Check if user is already a member + for _, member := range memberList { + if member.Address == user.Address { + return ErrUserAlreadyMember + } + } + + // Add user to team + memberList = append(memberList, &user) + tm.Members.Set(teamAddress.String(), memberList) + return nil +} + +func (tm *TeamManager) RemoveUserFromTeam(teamAddress std.Address, userAddress std.Address) error { + // Check if the team exists + _, teamExists := tm.Teams.Get(teamAddress.String()) + if !teamExists { + return ErrTeamNotFound + } + + // Get current members + members, _ := tm.Members.Get(teamAddress.String()) + var memberList []*users.User + if members != nil { + memberList = members.([]*users.User) + } else { + return ErrUserNotMember + } + + // Check if user is a member + userFound := false + for i, member := range memberList { + if member.Address == userAddress { + // Remove user from team + memberList = append(memberList[:i], memberList[i+1:]...) + userFound = true + break + } + } + + if !userFound { + return ErrUserNotMember + } + + // Update members list + tm.Members.Set(teamAddress.String(), memberList) + return nil +} + +func (tm *TeamManager) GetAllUsersInTeam(teamAddress std.Address) ([]users.User, error) { + // Check if the team exists + _, teamExists := tm.Teams.Get(teamAddress.String()) + if !teamExists { + return nil, ErrTeamNotFound + } + + // Get current members + members, _ := tm.Members.Get(teamAddress.String()) + var memberList []*users.User + if members != nil { + memberList = members.([]*users.User) + } else { + return nil, ErrUserNotMember + } + + // Convert []*users.User to []users.User + userList := make([]users.User, len(memberList)) + for i, member := range memberList { + userList[i] = *member + } + + return userList, nil +} + +func (t *Team) Render(tm *TeamManager) string { + str := "## team " + t.TeamName + "\n" + + "\n" + + " * address = " + t.Address.String() + "\n" + + " * creator = " + t.Creator.String() + "\n" + + "\n" + + t.TeamProfile + "\n" + + "\n" + + "### Members\n" + + // Get the members of the team + members, _ := tm.GetAllUsersInTeam(t.Address) + if members != nil { + for _, member := range members { + str += " * " + member.Name + " (" + member.Address.String() + "): " + member.Profile + "\n" + } + } else { + str += "No members found.\n" + } + + return str +} diff --git a/examples/gno.land/p/demo/teams/types.gno b/examples/gno.land/p/demo/teams/types.gno new file mode 100644 index 00000000000..7316dad3a3d --- /dev/null +++ b/examples/gno.land/p/demo/teams/types.gno @@ -0,0 +1,14 @@ +package teams + +type AddressOrTeamName string + +func (aotn AddressOrTeamName) IsName() bool { + return aotn != "" && aotn[0] == '@' +} + +func (aotn AddressOrTeamName) GetName() (string, bool) { + if len(aotn) >= 2 && aotn[0] == '@' { + return string(aotn[1:]), true + } + return "", false +} diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index 2776e93dca9..7b3254ea505 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -379,85 +379,46 @@ func NotEqual(t TestingT, expected, actual interface{}, msgs ...string) bool { return true } -func isNumberEmpty(n interface{}) (isNumber, isEmpty bool) { - switch n := n.(type) { - // NOTE: the cases are split individually, so that n becomes of the - // asserted type; the type of '0' was correctly inferred and converted - // to the corresponding type, int, int8, etc. - case int: - return true, n == 0 - case int8: - return true, n == 0 - case int16: - return true, n == 0 - case int32: - return true, n == 0 - case int64: - return true, n == 0 - case uint: - return true, n == 0 - case uint8: - return true, n == 0 - case uint16: - return true, n == 0 - case uint32: - return true, n == 0 - case uint64: - return true, n == 0 - case float32: - return true, n == 0 - case float64: - return true, n == 0 - } - return false, false -} func Empty(t TestingT, obj interface{}, msgs ...string) bool { t.Helper() - - isNumber, isEmpty := isNumberEmpty(obj) - if isNumber { - if !isEmpty { - return fail(t, msgs, "uassert.Empty: not empty number: %d", obj) + switch val := obj.(type) { + case string: + if val != "" { + return fail(t, msgs, "uassert.Empty: not empty string: %s", val) } - } else { - switch val := obj.(type) { - case string: - if val != "" { - return fail(t, msgs, "uassert.Empty: not empty string: %s", val) - } - case std.Address: - var zeroAddr std.Address - if val != zeroAddr { - return fail(t, msgs, "uassert.Empty: not empty std.Address: %s", string(val)) - } - default: - return fail(t, msgs, "uassert.Empty: unsupported type") + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + if val != 0 { + return fail(t, msgs, "uassert.Empty: not empty number: %d", val) } + case std.Address: + var zeroAddr std.Address + if val != zeroAddr { + return fail(t, msgs, "uassert.Empty: not empty std.Address: %s", string(val)) + } + default: + return fail(t, msgs, "uassert.Empty: unsupported type") } return true } func NotEmpty(t TestingT, obj interface{}, msgs ...string) bool { t.Helper() - isNumber, isEmpty := isNumberEmpty(obj) - if isNumber { - if isEmpty { - return fail(t, msgs, "uassert.NotEmpty: empty number: %d", obj) - } - } else { - switch val := obj.(type) { - case string: - if val == "" { - return fail(t, msgs, "uassert.NotEmpty: empty string: %s", val) - } - case std.Address: - var zeroAddr std.Address - if val == zeroAddr { - return fail(t, msgs, "uassert.NotEmpty: empty std.Address: %s", string(val)) - } - default: - return fail(t, msgs, "uassert.NotEmpty: unsupported type") + switch val := obj.(type) { + case string: + if val == "" { + return fail(t, msgs, "uassert.NotEmpty: empty string: %s", val) + } + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + if val == 0 { + return fail(t, msgs, "uassert.NotEmpty: empty number: %d", val) } + case std.Address: + var zeroAddr std.Address + if val == zeroAddr { + return fail(t, msgs, "uassert.NotEmpty: empty std.Address: %s", string(val)) + } + default: + return fail(t, msgs, "uassert.NotEmpty: unsupported type") } return true } diff --git a/examples/gno.land/p/demo/uassert/uassert_test.gno b/examples/gno.land/p/demo/uassert/uassert_test.gno index 7862eca7305..5ead848fd15 100644 --- a/examples/gno.land/p/demo/uassert/uassert_test.gno +++ b/examples/gno.land/p/demo/uassert/uassert_test.gno @@ -218,7 +218,6 @@ func TestEmpty(t *testing.T) { {"", true}, {0, true}, {int(0), true}, - {int32(0), true}, {int64(0), true}, {uint(0), true}, // XXX: continue @@ -336,7 +335,6 @@ func TestNotEmpty(t *testing.T) { {"", false}, {0, false}, {int(0), false}, - {int32(0), false}, {int64(0), false}, {uint(0), false}, {std.Address(""), false}, diff --git a/examples/gno.land/r/demo/art/gnoface/gno.mod b/examples/gno.land/r/demo/art/gnoface/gno.mod index 072c98f3bd6..eb6f44d4026 100644 --- a/examples/gno.land/r/demo/art/gnoface/gno.mod +++ b/examples/gno.land/r/demo/art/gnoface/gno.mod @@ -1,7 +1,6 @@ module gno.land/r/demo/art/gnoface require ( - gno.land/p/demo/entropy v0.0.0-latest gno.land/p/demo/uassert v0.0.0-latest gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/art/gnoface/gnoface.gno b/examples/gno.land/r/demo/art/gnoface/gnoface.gno index b4bc8e222e5..9e85c5c7387 100644 --- a/examples/gno.land/r/demo/art/gnoface/gnoface.gno +++ b/examples/gno.land/r/demo/art/gnoface/gnoface.gno @@ -2,15 +2,15 @@ package gnoface import ( "math/rand" + "std" "strconv" "strings" - "gno.land/p/demo/entropy" "gno.land/p/demo/ufmt" ) func Render(path string) string { - seed := uint64(entropy.New().Value()) + seed := uint64(std.GetHeight()) path = strings.TrimSpace(path) if path != "" { diff --git a/examples/gno.land/r/demo/art/millipede/millipede.gno b/examples/gno.land/r/demo/art/millipede/millipede.gno index 446c76e5d12..414941b947b 100644 --- a/examples/gno.land/r/demo/art/millipede/millipede.gno +++ b/examples/gno.land/r/demo/art/millipede/millipede.gno @@ -40,7 +40,7 @@ func Render(path string) string { output := "```\n" + Draw(size) + "```\n" if size > minSize { - output += ufmt.Sprintf("[%d](/r/demo/art/millipede:%d)< ", size-1, size-1) + output += ufmt.Sprintf("[%d](/r/demo/art/millpede:%d)< ", size-1, size-1) } if size < maxSize { output += ufmt.Sprintf(" >[%d](/r/demo/art/millipede:%d)", size+1, size+1) diff --git a/examples/gno.land/r/demo/art/millipede/millipede_test.gno b/examples/gno.land/r/demo/art/millipede/millipede_test.gno index 035b611d881..7fb5a5114b9 100644 --- a/examples/gno.land/r/demo/art/millipede/millipede_test.gno +++ b/examples/gno.land/r/demo/art/millipede/millipede_test.gno @@ -35,7 +35,7 @@ func TestRender(t *testing.T) { ╚═(███)═╝ ╚═(███)═╝ ╚═(███)═╝ -` + "```\n[19](/r/demo/art/millipede:19)< >[21](/r/demo/art/millipede:21)", +` + "```\n[19](/r/demo/art/millpede:19)< >[21](/r/demo/art/millipede:21)", }, { path: "4", @@ -45,7 +45,7 @@ func TestRender(t *testing.T) { ╚═(███)═╝ ╚═(███)═╝ ╚═(███)═╝ -` + "```\n[3](/r/demo/art/millipede:3)< >[5](/r/demo/art/millipede:5)", +` + "```\n[3](/r/demo/art/millpede:3)< >[5](/r/demo/art/millipede:5)", }, } diff --git a/examples/gno.land/r/demo/disperse/disperse.gno b/examples/gno.land/r/demo/disperse/disperse.gno deleted file mode 100644 index 0dc833dda95..00000000000 --- a/examples/gno.land/r/demo/disperse/disperse.gno +++ /dev/null @@ -1,99 +0,0 @@ -package disperse - -import ( - "std" - - tokens "gno.land/r/demo/grc20factory" -) - -// Get address of Disperse realm -var realmAddr = std.CurrentRealm().Addr() - -// DisperseUgnot parses receivers and amounts and sends out ugnot -// The function will send out the coins to the addresses and return the leftover coins to the caller -// if there are any to return -func DisperseUgnot(addresses []std.Address, coins std.Coins) { - coinSent := std.GetOrigSend() - caller := std.PrevRealm().Addr() - banker := std.GetBanker(std.BankerTypeOrigSend) - - if len(addresses) != len(coins) { - panic(ErrNumAddrValMismatch) - } - - for _, coin := range coins { - if coin.Amount <= 0 { - panic(ErrNegativeCoinAmount) - } - - if banker.GetCoins(realmAddr).AmountOf(coin.Denom) < coin.Amount { - panic(ErrMismatchBetweenSentAndParams) - } - } - - // Send coins - for i, _ := range addresses { - banker.SendCoins(realmAddr, addresses[i], std.NewCoins(coins[i])) - } - - // Return possible leftover coins - for _, coin := range coinSent { - leftoverAmt := banker.GetCoins(realmAddr).AmountOf(coin.Denom) - if leftoverAmt > 0 { - send := std.Coins{std.NewCoin(coin.Denom, leftoverAmt)} - banker.SendCoins(realmAddr, caller, send) - } - } -} - -// DisperseGRC20 disperses tokens to multiple addresses -// Note that it is necessary to approve the realm to spend the tokens before calling this function -// see the corresponding filetests for examples -func DisperseGRC20(addresses []std.Address, amounts []uint64, symbols []string) { - caller := std.PrevRealm().Addr() - - if (len(addresses) != len(amounts)) || (len(amounts) != len(symbols)) { - panic(ErrArgLenAndSentLenMismatch) - } - - for i := 0; i < len(addresses); i++ { - tokens.TransferFrom(symbols[i], caller, addresses[i], amounts[i]) - } -} - -// DisperseGRC20String receives a string of addresses and a string of tokens -// and parses them to be used in DisperseGRC20 -func DisperseGRC20String(addresses string, tokens string) { - parsedAddresses, err := parseAddresses(addresses) - if err != nil { - panic(err) - } - - parsedAmounts, parsedSymbols, err := parseTokens(tokens) - if err != nil { - panic(err) - } - - DisperseGRC20(parsedAddresses, parsedAmounts, parsedSymbols) -} - -// DisperseUgnotString receives a string of addresses and a string of amounts -// and parses them to be used in DisperseUgnot -func DisperseUgnotString(addresses string, amounts string) { - parsedAddresses, err := parseAddresses(addresses) - if err != nil { - panic(err) - } - - parsedAmounts, err := parseAmounts(amounts) - if err != nil { - panic(err) - } - - coins := make(std.Coins, len(parsedAmounts)) - for i, amount := range parsedAmounts { - coins[i] = std.NewCoin("ugnot", amount) - } - - DisperseUgnot(parsedAddresses, coins) -} diff --git a/examples/gno.land/r/demo/disperse/doc.gno b/examples/gno.land/r/demo/disperse/doc.gno deleted file mode 100644 index 100aa92cb3d..00000000000 --- a/examples/gno.land/r/demo/disperse/doc.gno +++ /dev/null @@ -1,19 +0,0 @@ -// Package disperse provides methods to disperse coins or GRC20 tokens among multiple addresses. -// -// The disperse package is an implementation of an existing service that allows users to send coins or GRC20 tokens to multiple addresses -// on the Ethereum blockchain. -// -// Usage: -// To use disperse, you can either use `DisperseUgnot` to send coins or `DisperseGRC20` to send GRC20 tokens to multiple addresses. -// -// Example: -// Dispersing 200 coins to two addresses: -// - DisperseUgnotString("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0,g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c", "150,50") -// Dispersing 200 worth of a GRC20 token "TEST" to two addresses: -// - DisperseGRC20String("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0,g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c", "150TEST,50TEST") -// -// Reference: -// - [the original dispere app](https://disperse.app/) -// - [the original disperse app on etherscan](https://etherscan.io/address/0xd152f549545093347a162dce210e7293f1452150#code) -// - [the gno disperse web app](https://gno-disperse.netlify.app/) -package disperse // import "gno.land/r/demo/disperse" diff --git a/examples/gno.land/r/demo/disperse/errors.gno b/examples/gno.land/r/demo/disperse/errors.gno deleted file mode 100644 index c054e658651..00000000000 --- a/examples/gno.land/r/demo/disperse/errors.gno +++ /dev/null @@ -1,12 +0,0 @@ -package disperse - -import "errors" - -var ( - ErrNotEnoughCoin = errors.New("disperse: not enough coin sent in") - ErrNumAddrValMismatch = errors.New("disperse: number of addresses and values to send doesn't match") - ErrInvalidAddress = errors.New("disperse: invalid address") - ErrNegativeCoinAmount = errors.New("disperse: coin amount cannot be negative") - ErrMismatchBetweenSentAndParams = errors.New("disperse: mismatch between coins sent and params called") - ErrArgLenAndSentLenMismatch = errors.New("disperse: mismatch between coins sent and args called") -) diff --git a/examples/gno.land/r/demo/disperse/gno.mod b/examples/gno.land/r/demo/disperse/gno.mod deleted file mode 100644 index 0ba9c88810a..00000000000 --- a/examples/gno.land/r/demo/disperse/gno.mod +++ /dev/null @@ -1,3 +0,0 @@ -module gno.land/r/demo/disperse - -require gno.land/r/demo/grc20factory v0.0.0-latest diff --git a/examples/gno.land/r/demo/disperse/util.gno b/examples/gno.land/r/demo/disperse/util.gno deleted file mode 100644 index 7101522572d..00000000000 --- a/examples/gno.land/r/demo/disperse/util.gno +++ /dev/null @@ -1,67 +0,0 @@ -package disperse - -import ( - "std" - "strconv" - "strings" - "unicode" -) - -func parseAddresses(addresses string) ([]std.Address, error) { - var ret []std.Address - - for _, str := range strings.Split(addresses, ",") { - addr := std.Address(str) - if !addr.IsValid() { - return nil, ErrInvalidAddress - } - - ret = append(ret, addr) - } - - return ret, nil -} - -func splitString(input string) (string, string) { - var pos int - for i, char := range input { - if !unicode.IsDigit(char) { - pos = i - break - } - } - return input[:pos], input[pos:] -} - -func parseTokens(tokens string) ([]uint64, []string, error) { - var amounts []uint64 - var symbols []string - - for _, token := range strings.Split(tokens, ",") { - amountStr, symbol := splitString(token) - amount, _ := strconv.Atoi(amountStr) - if amount < 0 { - return nil, nil, ErrNegativeCoinAmount - } - - amounts = append(amounts, uint64(amount)) - symbols = append(symbols, symbol) - } - - return amounts, symbols, nil -} - -func parseAmounts(amounts string) ([]int64, error) { - var ret []int64 - - for _, amt := range strings.Split(amounts, ",") { - amount, _ := strconv.Atoi(amt) - if amount < 0 { - return nil, ErrNegativeCoinAmount - } - - ret = append(ret, int64(amount)) - } - - return ret, nil -} diff --git a/examples/gno.land/r/demo/disperse/z_0_filetest.gno b/examples/gno.land/r/demo/disperse/z_0_filetest.gno deleted file mode 100644 index 62a34cfdf26..00000000000 --- a/examples/gno.land/r/demo/disperse/z_0_filetest.gno +++ /dev/null @@ -1,32 +0,0 @@ -// SEND: 200ugnot - -package main - -import ( - "std" - - "gno.land/r/demo/disperse" -) - -func main() { - disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") - - std.TestSetOrigPkgAddr(disperseAddr) - std.TestSetOrigCaller(mainaddr) - - banker := std.GetBanker(std.BankerTypeRealmSend) - - mainbal := banker.GetCoins(mainaddr) - println("main before:", mainbal) - - banker.SendCoins(mainaddr, disperseAddr, std.Coins{{"ugnot", 200}}) - disperse.DisperseUgnotString("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0,g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c", "150,50") - - mainbal = banker.GetCoins(mainaddr) - println("main after:", mainbal) -} - -// Output: -// main before: 200000200ugnot -// main after: 200000000ugnot diff --git a/examples/gno.land/r/demo/disperse/z_1_filetest.gno b/examples/gno.land/r/demo/disperse/z_1_filetest.gno deleted file mode 100644 index 1e042d320f6..00000000000 --- a/examples/gno.land/r/demo/disperse/z_1_filetest.gno +++ /dev/null @@ -1,32 +0,0 @@ -// SEND: 300ugnot - -package main - -import ( - "std" - - "gno.land/r/demo/disperse" -) - -func main() { - disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") - - std.TestSetOrigPkgAddr(disperseAddr) - std.TestSetOrigCaller(mainaddr) - - banker := std.GetBanker(std.BankerTypeRealmSend) - - mainbal := banker.GetCoins(mainaddr) - println("main before:", mainbal) - - banker.SendCoins(mainaddr, disperseAddr, std.Coins{{"ugnot", 300}}) - disperse.DisperseUgnotString("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0,g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c", "150,50") - - mainbal = banker.GetCoins(mainaddr) - println("main after:", mainbal) -} - -// Output: -// main before: 200000300ugnot -// main after: 200000100ugnot diff --git a/examples/gno.land/r/demo/disperse/z_2_filetest.gno b/examples/gno.land/r/demo/disperse/z_2_filetest.gno deleted file mode 100644 index 163bb2fc1ab..00000000000 --- a/examples/gno.land/r/demo/disperse/z_2_filetest.gno +++ /dev/null @@ -1,25 +0,0 @@ -// SEND: 300ugnot - -package main - -import ( - "std" - - "gno.land/r/demo/disperse" -) - -func main() { - disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") - - std.TestSetOrigPkgAddr(disperseAddr) - std.TestSetOrigCaller(mainaddr) - - banker := std.GetBanker(std.BankerTypeRealmSend) - - banker.SendCoins(mainaddr, disperseAddr, std.Coins{{"ugnot", 100}}) - disperse.DisperseUgnotString("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0,g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c", "150,50") -} - -// Error: -// disperse: mismatch between coins sent and params called diff --git a/examples/gno.land/r/demo/disperse/z_3_filetest.gno b/examples/gno.land/r/demo/disperse/z_3_filetest.gno deleted file mode 100644 index eabed52fb38..00000000000 --- a/examples/gno.land/r/demo/disperse/z_3_filetest.gno +++ /dev/null @@ -1,45 +0,0 @@ -// SEND: 300ugnot - -package main - -import ( - "std" - - "gno.land/r/demo/disperse" - tokens "gno.land/r/demo/grc20factory" -) - -func main() { - disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") - beneficiary1 := std.Address("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0") - beneficiary2 := std.Address("g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c") - - std.TestSetOrigPkgAddr(disperseAddr) - std.TestSetOrigCaller(mainaddr) - - banker := std.GetBanker(std.BankerTypeRealmSend) - - tokens.New("test", "TEST", 4, 0, 0) - tokens.Mint("TEST", mainaddr, 200) - - mainbal := tokens.BalanceOf("TEST", mainaddr) - println("main before:", mainbal) - - tokens.Approve("TEST", disperseAddr, 200) - - disperse.DisperseGRC20String("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0,g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c", "150TEST,50TEST") - - mainbal = tokens.BalanceOf("TEST", mainaddr) - println("main after:", mainbal) - ben1bal := tokens.BalanceOf("TEST", beneficiary1) - println("beneficiary1:", ben1bal) - ben2bal := tokens.BalanceOf("TEST", beneficiary2) - println("beneficiary2:", ben2bal) -} - -// Output: -// main before: 200 -// main after: 0 -// beneficiary1: 150 -// beneficiary2: 50 diff --git a/examples/gno.land/r/demo/disperse/z_4_filetest.gno b/examples/gno.land/r/demo/disperse/z_4_filetest.gno deleted file mode 100644 index ebf4bed4473..00000000000 --- a/examples/gno.land/r/demo/disperse/z_4_filetest.gno +++ /dev/null @@ -1,48 +0,0 @@ -// SEND: 300ugnot - -package main - -import ( - "std" - - "gno.land/r/demo/disperse" - tokens "gno.land/r/demo/grc20factory" -) - -func main() { - disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") - beneficiary1 := std.Address("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0") - beneficiary2 := std.Address("g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c") - - std.TestSetOrigPkgAddr(disperseAddr) - std.TestSetOrigCaller(mainaddr) - - banker := std.GetBanker(std.BankerTypeRealmSend) - - tokens.New("test1", "TEST1", 4, 0, 0) - tokens.Mint("TEST1", mainaddr, 200) - tokens.New("test2", "TEST2", 4, 0, 0) - tokens.Mint("TEST2", mainaddr, 200) - - mainbal := tokens.BalanceOf("TEST1", mainaddr) + tokens.BalanceOf("TEST2", mainaddr) - println("main before:", mainbal) - - tokens.Approve("TEST1", disperseAddr, 200) - tokens.Approve("TEST2", disperseAddr, 200) - - disperse.DisperseGRC20String("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0,g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c", "200TEST1,200TEST2") - - mainbal = tokens.BalanceOf("TEST1", mainaddr) + tokens.BalanceOf("TEST2", mainaddr) - println("main after:", mainbal) - ben1bal := tokens.BalanceOf("TEST1", beneficiary1) + tokens.BalanceOf("TEST2", beneficiary1) - println("beneficiary1:", ben1bal) - ben2bal := tokens.BalanceOf("TEST1", beneficiary2) + tokens.BalanceOf("TEST2", beneficiary2) - println("beneficiary2:", ben2bal) -} - -// Output: -// main before: 400 -// main after: 0 -// beneficiary1: 200 -// beneficiary2: 200 diff --git a/examples/gno.land/r/demo/flippando/airdrop.gno b/examples/gno.land/r/demo/flippando/airdrop.gno new file mode 100644 index 00000000000..52a7c6e6066 --- /dev/null +++ b/examples/gno.land/r/demo/flippando/airdrop.gno @@ -0,0 +1,183 @@ +package flippando + +import ( + "strconv" + "std" + "bytes" + + "gno.land/p/demo/grc/grc721" + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" +) + +var ( + // hardcoding the airdrop account and restricting minting to it + validAirdropAccount std.Address = std.Address("g1mphljw4duhzwqs72hv9grm4k6ufkvts3g7t3t4") + bNFTtokenIDCounter uint64 + mintedNFTs avl.Tree // owner -> []string +) + + +// - generates a GRC721 token with the airdropped board SVG as a tokenURI +// - returns token metadata as string, to be used in client + +func AirdropBasicFlipNFT( + playerRecipient string, + airdropName string, + airdropParentID string, + airdropXPos string, + airdropYPos string, + gameType string, + gameLevel string, + svgData string) (string, string) { + + // - toPlayer is the user receiving the NFT, and the locked FLIP + toPlayer := std.Address(playerRecipient) + + result := "" + nftError := "" + + // Check if the function is called by the valid airdrop account + if validAirdropAccount.String() != std.GetOrigCaller().String() { + return "", "airdrop account not correct" + } + + // Check if the user has already minted the maximum number of NFTs + const maxNFTs = 20 + userMintedNFTs, exists := mintedNFTs.Get(toPlayer.String()) + var mintedList []string + if exists { + mintedList = userMintedNFTs.([]string) + if len(mintedList) >= maxNFTs { + return "", "user has already minted the maximum number of NFTs" + } + } else { + mintedList = []string{} + mintedNFTs.Set(toPlayer.String(), mintedList) + } + + // Mint the NFT + count := FlipBasicNFT.TokenCount() + bNFTtokenIDCounter = count + 1 + tidString := strconv.FormatUint(bNFTtokenIDCounter, 10) + tid := grc721.TokenID(tidString) + // we first mint to airdrop account, to be able to set TokenURI + // then we transfer + mintResultError := FlipBasicNFT.Mint(validAirdropAccount, tid) + + if mintResultError == nil { + gameId := "airdrop/" + airdropName + "/1" + + flipBasicNFTMetaData := &BasicNFTMetaData{ + tokenID: tidString, + name: "Flippando - the Game", + version: "1.0.0", + gameId: gameId, + gameType: gameType, + gameLevel: gameLevel, + svgData: svgData, + airdropName: airdropName, + airdropParentID: airdropParentID, + airdropXPos: airdropXPos, + airdropYPos: airdropYPos, + } + flipBasicNFTMetaDataJSON, err := flipBasicNFTMetaData.MarshalJSON() + if err != nil { + panic("error in marshalling flipBasicNFTMetaData") + } + _, terr := FlipBasicNFT.SetTokenURI(tid, grc721.TokenURI(flipBasicNFTMetaDataJSON)) + if terr != nil { + return "", ufmt.Sprintf("error in SetTokenUR in airdrop, %s", terr.Error()) + } + // transfer the NFT to player + FlipBasicNFT.TransferFrom(validAirdropAccount, toPlayer, tid) + FlipBasicNFT.Approve(GetBasicNFTRealmAddress(), tid) + + // Add NFT to the LockedNFTs avl.Tree + var flipAmount int64 + if gameLevel == "16" { + flipAmount = 1000 + } else if gameLevel == "64" { + flipAmount = 4000 + } + MintAndLockFLIP(toPlayer, tidString, std.NewCoin("FLIP", flipAmount)) + LockedNFTs.Set(tidString, flipAmount) + + // Mint FLIP for the account airdropping, to create liquidity + merr := Mint(airdropAccount, std.NewCoin("FLIP", flipAmount)) + if merr != nil { + return "", ufmt.Sprintf("error in calling Mint in airdrop function, %s", merr.Error()) + } + + // Add minted NFT to the user's minted NFTs list with the format "basicTokenId:airdropParentId:airdropXPos:airdropYPos" + mintedEntry := tidString + ":" + airdropParentID + ":" + airdropXPos + ":" + airdropYPos + if exists { + mintedList = append(mintedList, mintedEntry) + mintedNFTs.Set(toPlayer.String(), mintedList) + } else { + mintedNFTs.Set(toPlayer.String(), []string{mintedEntry}) + } + + result = string(flipBasicNFTMetaDataJSON) + } else { + nftError = ufmt.Sprintf("error in calling Mint in airdrop function, %s", mintResultError.Error()) + } + + res := &nftResult{ + result: result, + nftError: nftError, + } + + createNFTResult, err := res.MarshalJSON() + if err != nil { + panic("error in marshaling result") + } + return string(createNFTResult), nftError +} + +// getters, utils + +func GetAllMintedAirdropNFTs() string { + var allTokenIDs []string + + mintedNFTs.Iterate("", "", func(key string, value interface{}) bool { + + if tId, ok := value.([]string); ok { + allTokenIDs = append(allTokenIDs, tId...) + } + return false // Continue iteration until all nodes have been visited. + }) + + res := &mintedAirdropNFTs{ + TokenIDs: allTokenIDs, + } + + mintedNFTResult, err := res.MarshalJSON() + if err != nil { + panic("error in marshalling result") + } + return string(mintedNFTResult) +} + +func (man mintedAirdropNFTs) MarshalJSON() ([]byte, error) { + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"tokenIDs":[`) + for i, s := range man.TokenIDs { + if i > 0 { + b.WriteString(",") + } + b.WriteString(`"` + s + `"`) + } + b.WriteString(`]`) + + b.WriteByte('}') + + return b.Bytes(), nil +} + +type mintedAirdropNFTs struct { + TokenIDs []string `json:"tokenIDs"` +} diff --git a/examples/gno.land/r/demo/flippando/basicNFT.gno b/examples/gno.land/r/demo/flippando/basicNFT.gno new file mode 100644 index 00000000000..82f883e2fc9 --- /dev/null +++ b/examples/gno.land/r/demo/flippando/basicNFT.gno @@ -0,0 +1,374 @@ +package flippando + +import ( + "strconv" + "std" + "errors" + "strings" + + "gno.land/p/demo/grc/grc721" + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" +) + +var ( + FlipBasicNFT = grc721.NewBasicNFT("Flippando Basic NFT", "BFLP") + basicNFTtokenIDCounter uint64 + LockedNFTs avl.Tree // tokenId -> flipAmount + childOf avl.Tree // tokenId -> parent (composite) tokenId + mintingLock bool +) + +func CreateBasicFlipNFT(player std.Address, gameId string) (string, string) { + // - generates a GRC721 token with the solved board SVG as a tokenURI + // - returns token metadata as string, to be used in client + result := "" + nftError := "" + + games := GetUserGames(player) + // safety checks + if(len(games) == 0){ + result = "{failedSafetyCheck: userHasGames}" + nftError = "{error: user has zero games}" + } + currentGame := games[0] + hasZeroValues := func(s []int64) bool { for _, v := range s { if v == 0 { return true } }; return false }(currentGame.SolvedGameBoard) + if(hasZeroValues){ + result = "{failedSafetyCheck: gameCompletion}" + nftError = "{error: game is not finished}" + } + // Check and acquire the lock + if mintingLock { + return "", "minting in progress" + } + mintingLock = true + defer func() { mintingLock = false }() // Release lock at the end + + count := FlipBasicNFT.TokenCount() + basicNFTtokenIDCounter = count + 1 + tidString := strconv.FormatUint(basicNFTtokenIDCounter, 10) + tid := grc721.TokenID(tidString) + mintResultError := FlipBasicNFT.Mint(player, tid) + if mintResultError == nil { + gameSVGData, errSVG := GenerateGrid(currentGame.SolvedGameBoard, currentGame.TileType) + if errSVG != nil { + result = "{failedSafetyCheck: svgDataCorrupted}" + nftError = "SVG data not generated" + } + flipBasicNFTMetaData := &BasicNFTMetaData{ + tokenID: tidString, + name: "Flippando - the Game", + version: "1.0.0", + gameId: currentGame.ID, + gameType: currentGame.TileType, + gameLevel: strconv.Itoa(len(currentGame.SolvedGameBoard)), + svgData: gameSVGData, + airdropName: "", + airdropParentID: "", + airdropXPos: "", + airdropYPos: "", + } + flipBasicNFTMetaDataJSON, err := flipBasicNFTMetaData.MarshalJSON() + if err != nil { + panic("error in marhasling flipBasicNFTMetaData"); + } + FlipBasicNFT.SetTokenURI(tid, grc721.TokenURI(flipBasicNFTMetaDataJSON)) + // set approval for the realm owner so we can later transfer the NFT + FlipBasicNFT.Approve(std.CurrentRealm().Addr(), tid) + + // add NFT to the LockedNFTs avl.Tree + var flipAmount int64 + if len(currentGame.SolvedGameBoard) == 16 { + flipAmount = 1000 // 1000 uflip = 1 FLIP + } else if len(currentGame.SolvedGameBoard) == 64 { + flipAmount = 4000 // 4000 uflip = 4 FLIP + } + // mint fungible FLIP token + MintAndLockFLIP(player, tidString, std.NewCoin("FLIP", flipAmount)) + LockedNFTs.Set(tidString, flipAmount) + + result = string(flipBasicNFTMetaDataJSON) + } + res := &nftResult{ + result: result, + nftError: nftError, + } + + createNFTResult, err := res.MarshalJSON() + if(err != nil){ + panic("error in minting") + } + return string(createNFTResult), nftError +} + +// returns a string version of the TokenURI +func GetBasicTokenURI(tokenID string) string { + tid := grc721.TokenID(tokenID) + tokenURI, err := FlipBasicNFT.TokenURI(tid) + if err != nil { + return ufmt.Sprintf("error in GetBasicTokenURI in basicNFT, %s", err.Error()) + } + return string(tokenURI); +} + +// basically identical with the other one, but returns BasicNFTMetaData type +func GetTokenMetadata(tokenId string) (BasicNFTMetaData, error) { + uri, gerr := FlipBasicNFT.TokenURI(grc721.TokenID(tokenId)) + + var metadata BasicNFTMetaData + if gerr != nil { + return metadata, gerr + } + metadata, err := ParseBasicNFTMetaData(uri) + if err != nil { + return metadata, err + } + return metadata, nil +} + +func GetParentdOf(tokenId string) string { + parentTokenId, exists := childOf.Get(tokenId) + if exists { + return parentTokenId.(string); + } + return "" +} + +func UnlockAndTransferNFT(from, to std.Address, tid string, parentTid string) error { + tokenId := grc721.TokenID(tid) + + terr := FlipBasicNFT.TransferFrom(from, to, tokenId) + if terr != nil { + return terr + } + // remove from locked NFTs + LockedNFTs.Remove(tid) + childOf.Set(tid, parentTid) + return nil +} + +// it is used in marketplace +func TransferBasicNFTToBuyer(from, to std.Address, tid grc721.TokenID) error { + var approveErr error + var transferErr error + + // Check current approval status + approvedAddress, err := FlipBasicNFT.GetApproved(tid) + if err != nil { + approveErr = errors.New(ufmt.Sprintf("Failed to get approval status: %s", err.Error())) + } + + if approvedAddress != std.CurrentRealm().Addr() { + // Approve the marketplace to transfer the token on behalf of the owner + err = FlipBasicNFT.Approve(std.CurrentRealm().Addr(), tid) + if err != nil { + approveErr = errors.New(ufmt.Sprintf("Failed to approve NFT transfer: %s, approvedAddress: %s", err.Error(), approvedAddress)) + } + } + + // Perform the transfer + err = FlipBasicNFT.TransferFrom(from, to, tid) + if err != nil { + transferErr = errors.New(ufmt.Sprintf("Failed to transfer NFT: %s", err.Error())) + } + + // Combine errors if any + if approveErr != nil && transferErr != nil { + return errors.New(ufmt.Sprintf("%s; %s", approveErr.Error(), transferErr.Error())) + } else if approveErr != nil { + return approveErr + } else if transferErr != nil { + return transferErr + } + + return nil +} + +// it is used after minting a composite NFT +func BurnBasicNFTsAfterMinting(tid grc721.TokenID) error { + err := FlipBasicNFT.Burn(tid) + if err != nil { + return err + } + return nil +} + +func GetOwnerOfBasicNFT(tid string) std.Address { + tokenId := grc721.TokenID(tid) + owner, err := FlipBasicNFT.OwnerOf(tokenId) + if err != nil { + return "can't get owner" + } + return owner +} + +func GetUserBasicFlipNFTs(addr std.Address, readyToUse string) string { + tokenCount := FlipBasicNFT.TokenCount() + tokenURIs := []string{} + userNFTsError := "" + + for i := uint64(1); i < uint64(tokenCount+1); i++ { + tidString := strconv.FormatUint(i, 10) + owner, err := FlipBasicNFT.OwnerOf(grc721.TokenID(tidString)) + // debug + if err != nil { + userNFTsError += err.Error() + } + if err != nil { + if err == ErrInvalidTokenId { + // do we need to do smth else here? + return "invalid token" + } + } + + // check the owner is the addr + if owner == addr { + // if readyToUSe == "yes" we're returning only locked NFTs + _, exists := LockedNFTs.Get(tidString) + if readyToUse == "yes" { + if exists { + tokenURI := GetBasicTokenURI(tidString) + tokenURIs = append(tokenURIs, tokenURI) + } + } else { + if !exists { + tokenURI := GetBasicTokenURI(tidString) + tokenURIs = append(tokenURIs, tokenURI) + } + } + } + } + + fetchedUserNFTs := &userNFTsResult{ + UserNFTs: tokenURIs, + } + + userNFTs, err := fetchedUserNFTs.MarshalJSON() + if(err != nil){ + panic("error in fetching user NFTs") + } + + return string(userNFTs) +} + +func GetBasicNFTsByTokenId(bTokenIDs string) string { + + tokenURIs := []string{} + bTokenIDsArray, _ := ParseString(bTokenIDs) + + for i := int64(0); i < int64(len(bTokenIDsArray)); i++ { + tidString := strconv.FormatUint(uint64(bTokenIDsArray[i]), 10) + + tokenURI := GetBasicTokenURI(tidString) + tokenURIs = append(tokenURIs, tokenURI) + } + + fetchedUserNFTs := &userNFTsResult{ + UserNFTs: tokenURIs, + } + + userNFTs, err := fetchedUserNFTs.MarshalJSON() + if(err != nil){ + panic("error in fetching basic NFTs by tokenIDs") + } + + return string(userNFTs) +} + +func GetAllBasicFlipNFTs(forPlayer std.Address) string { + tokenCount := FlipBasicNFT.TokenCount() + tokenURIs := []string{} + userNFTsError := "" + + for i := uint64(1); i < uint64(tokenCount+1); i++ { + tidString := strconv.FormatUint(i, 10) + owner, err := FlipBasicNFT.OwnerOf(grc721.TokenID(tidString)) + + if err != nil { + userNFTsError += err.Error() + if err == ErrInvalidTokenId { + // do we need to do smth else here? + return "invalid token" + } + } + + // return nfts not belonging to forPlayer + if owner != forPlayer { + // only locked nfts, unlocked can't be reused + _, exists := LockedNFTs.Get(tidString) + + if exists { + tokenURI := GetBasicTokenURI(tidString) + tokenURIs = append(tokenURIs, tokenURI) + } + } + } + + fetchedUserNFTs := &userNFTsResult{ + UserNFTs: tokenURIs, + } + + userNFTs, err := fetchedUserNFTs.MarshalJSON() + if(err != nil){ + panic("error in fetching user NFTs") + } + + return string(userNFTs) +} + +func GetTotalAvailableBasicNFTs() int { + return LockedNFTs.Size() +} + +func GetAllUnlockedNFTs() int { + tokenCount := FlipBasicNFT.TokenCount() + LockedNFTs := LockedNFTs.Size() + totalUnlocked := int(tokenCount) - LockedNFTs + return int(totalUnlocked) +} + +// util + +func GetBasicNFTRealmAddress() std.Address { + return std.CurrentRealm().Addr() +} + + +// util +func ParseBasicNFTMetaData(jsonStr string) (BasicNFTMetaData, error) { + var metadata BasicNFTMetaData + + // Helper function to extract a value from the JSON string by key + extractValue := func(key string) string { + startIndex := strings.Index(jsonStr, `"`+key+`":"`) + if startIndex == -1 { + return "" + } + startIndex += len(key) + 4 // Move to the start of the value + + endIndex := strings.Index(jsonStr[startIndex:], `"`) + if endIndex == -1 { + return "" + } + + return jsonStr[startIndex : startIndex+endIndex] + } + + metadata.tokenID = extractValue("tokenID") + metadata.name = extractValue("name") + metadata.version = extractValue("version") + metadata.gameId = extractValue("gameId") + metadata.gameType = extractValue("gameType") + metadata.gameLevel = extractValue("gameLevel") + metadata.svgData = extractValue("svgData") + metadata.airdropName = extractValue("airdropName") + metadata.airdropParentID = extractValue("airdropParentID") + metadata.airdropXPos = extractValue("airdropXPos") + metadata.airdropYPos = extractValue("airdropYPos") + + return metadata, nil +} + + + + diff --git a/examples/gno.land/r/demo/flippando/compositeNFT.gno b/examples/gno.land/r/demo/flippando/compositeNFT.gno new file mode 100644 index 00000000000..a0df4fca436 --- /dev/null +++ b/examples/gno.land/r/demo/flippando/compositeNFT.gno @@ -0,0 +1,263 @@ +package flippando + +import ( + "errors" + "strconv" + "std" + + "gno.land/p/demo/grc/grc721" + "gno.land/p/demo/ufmt" +) + +var ( + FlipCompositeNFT = grc721.NewBasicNFT("Flippando Composite NFT", "CFLP") + compositeNFTtokenIDCounter uint64 + children map[string]string +) + +/** +* generates the composite NFT for the player, with a canvas having cWidth and cHeight, and tokenIds +* in an array "[1,7,3,8]"" +*/ +func CreateCompositeFlipNFT(player std.Address, cWidth string, cHeight string, bTokenIDsArray string) (string, string) { + result := "" + nftError := "" + + bTokenIDs, _ := ParseString(bTokenIDsArray) + // Initialize the children map if it's nil + if children == nil { + children = make(map[string]string) + } + + // add checks for cWidth, cHeight (enforce canvas size based on number of existing basicNFTs) + // 50 / 2 x 2 - 100 / 3 x 3 - 400 / 4 x 4 - 600 / 5 x 5 - 800 / 6 x 6 - 1000 / 7 x 7 - 1200 / 8 x 8 + // custom error messages + + totalAvailableBasicNFTs := GetTotalAvailableBasicNFTs() + + intWidth, werr := strconv.Atoi(cWidth) + if werr != nil { + return "", "not a valid integer representation for canvas width" + } + + intHeight, herr := strconv.Atoi(cWidth) + if herr != nil { + return "", "not a valid integer representation for canvas height" + } + + if totalAvailableBasicNFTs <= 50 { + if intHeight != 2 && intWidth != 2 { + return "", "invalid canvas width and height for under 50 available basic NFTs" + } + } else if totalAvailableBasicNFTs > 50 && totalAvailableBasicNFTs <= 100 { + if intHeight != 3 && intWidth != 3 { + return "", "invalid canvas width and height for under 100 available basic NFTs" + } + } else if totalAvailableBasicNFTs > 100 && totalAvailableBasicNFTs <= 400 { + if intHeight != 4 && intWidth != 4 { + return "", "invalid canvas width and height for under 400 available basic NFTs" + } + } else if totalAvailableBasicNFTs > 400 && totalAvailableBasicNFTs <= 600 { + if intHeight != 5 && intWidth != 5 { + return "", "invalid canvas width and height for under 600 available basic NFTs" + } + } else if totalAvailableBasicNFTs > 600 && totalAvailableBasicNFTs <= 800 { + if intHeight != 6 && intWidth != 6 { + return "", "invalid canvas width and height for under 800 available basic NFTs" + } + } else if totalAvailableBasicNFTs > 800 && totalAvailableBasicNFTs <= 1000 { + if intHeight != 7 && intWidth != 7 { + return "", "invalid canvas width and height for under 800 available basic NFTs" + } + } else if totalAvailableBasicNFTs > 1000 { + if intHeight != 8 && intWidth != 8 { + return "", "invalid canvas width and height for over 1000 available basic NFTs" + } + } + + // check if any of the bTokenIds is listed in the marketplace + for _, tokenId := range bTokenIDs { + if err := IsBasicTokenIdListed(strconv.FormatInt(tokenId, 10)); err != nil { + return "", "one or more tokenIds are already listed" + } + } + + // check if any of the bTokenIds is part of an airdrop and force the order + + allAirdropNamesIdentical := true + firstAirdropName := "" + var bTokenMetadata []BasicNFTMetaData + + for _, tokenId := range bTokenIDs { + metadata, err := GetTokenMetadata(strconv.FormatInt(tokenId, 10)) + if err != nil { + return "", "error retrieving token metadata" + } + bTokenMetadata = append(bTokenMetadata, metadata) + + if metadata.airdropName != "" { + if firstAirdropName == "" { + firstAirdropName = metadata.airdropName + } else if metadata.airdropName != firstAirdropName { + allAirdropNamesIdentical = false + } + } + } + + if allAirdropNamesIdentical && firstAirdropName != "" { + expectedXPos := 0 + expectedYPos := 0 + gridSize := 0 + + // Determine grid size based on gameLevel + if bTokenMetadata[0].gameLevel == "16" { + gridSize = 4 + } else if bTokenMetadata[0].gameLevel == "64" { + gridSize = 8 + } else { + return "", "unsupported game level" + } + + for _, metadata := range bTokenMetadata { + if metadata.airdropXPos != strconv.Itoa(expectedXPos) || metadata.airdropYPos != strconv.Itoa(expectedYPos) { + return "", "invalid XPos and YPos order for the airdropped NFTs" + } + + if expectedXPos == gridSize-1 { + expectedXPos = 0 + expectedYPos++ + } else { + expectedXPos++ + } + } + } else if !allAirdropNamesIdentical { + return "", "you cannot use an airdropped NFT to build this" + } + + count := FlipCompositeNFT.TokenCount() + compositeNFTtokenIDCounter = count + 1 + tidString := strconv.FormatUint(compositeNFTtokenIDCounter, 10) + tid := grc721.TokenID(tidString) + mintResultError := FlipCompositeNFT.Mint(player, tid) + if mintResultError == nil { + flipCompositeNFTMetaData := &compositeNFTMetaData{ + tokenID: tidString, + name: "Flippando - the Art Gallery", + version: "1.0.0", + canvasWidth: string(cWidth), + canvasHeight: string(cHeight), + bTokenIDs: bTokenIDs, + } + flipCompositeNFTMetaDataJSON, err := flipCompositeNFTMetaData.MarshalJSON() + if err != nil { + panic("error in marshaling flipCompositeNFTMetaData"); + } + + // iterate through the array and transfer the nft with tokenID to player + // unlock the token and transfer it to basic nftOwner FLIP balance + for _, t := range bTokenIDs { + basicTidString := strconv.FormatInt(t, 10) + flipBasicOwner := GetOwnerOfBasicNFT(basicTidString) + uerr := UnlockAndTransferNFT(flipBasicOwner, player, basicTidString, tidString) + if uerr != nil { + return "", ufmt.Sprintf("Failed to UnlockAndTransferNFT: %s, for basicTokenId %s, owner by %s ", uerr.Error(), basicTidString, flipBasicOwner.String()) + } + // release the locked FLIP and make it available to the flip basic NFT owner + ReleaseLockedFLIP(flipBasicOwner, basicTidString) + } + // set compositeNFT tokenURI + FlipCompositeNFT.SetTokenURI(tid, grc721.TokenURI(flipCompositeNFTMetaDataJSON)) + children[tidString] = bTokenIDsArray + // set approval for the realm owner so we can later transfer the NFT + FlipCompositeNFT.Approve(std.CurrentRealm().Addr(), tid) + result = string(flipCompositeNFTMetaDataJSON) + } + res := &nftResult{ + result: result, + nftError: nftError, + } + + createNFTResult, err := res.MarshalJSON() + if(err != nil){ + panic("error in minting") + } + return string(createNFTResult), nftError +} + +// it is used in marketplace +func TransferCompositeNFT(from, to std.Address, tid grc721.TokenID) error { + err := FlipCompositeNFT.TransferFrom(from, to, tid) + if err != nil { + return err + } + return nil +} + +func GetCompositeTokenURI(tokenID string) string { + tid := grc721.TokenID(tokenID) + tokenURI, err := FlipCompositeNFT.TokenURI(tid) + if err != nil { + return "error" + } + return string(tokenURI); +} + +func GetOwnerOfCompositeTokenId(tokenId string) string { + owner, err := FlipCompositeNFT.OwnerOf(grc721.TokenID(tokenId)) + if err != nil { + return "error" + } + return string(owner) +} + +func GetChildrenOf(tokenID string) (string, error) { + childrenOf, exists := children[tokenID] + if !exists { + return "", errors.New("can't get children of this tokenId") + } + return childrenOf, nil +} + +func GetUserCompositeFlipNFTs(addr std.Address) string { + tokenCount := FlipCompositeNFT.TokenCount() + tokenURIs := []string{} + userNFTsError := "" + + for i := uint64(1); i < uint64(tokenCount+1); i++ { + tidString := strconv.FormatUint(i, 10) + owner, err := FlipCompositeNFT.OwnerOf(grc721.TokenID(tidString)) + + if err != nil { + userNFTsError += err.Error() + } + if err != nil { + if err == ErrInvalidTokenId { + // do we need to do smth else here? + return "invalid token" + } + } + + // If the owner matches the address we're looking for, add the TokenID to the slice. + if owner == addr { + tokenURI := GetCompositeTokenURI(tidString) + tokenURIs = append(tokenURIs, tokenURI) + } + } + + fetchedUserNFTs := &userNFTsResult{ + UserNFTs: tokenURIs, + } + + userNFTs, err := fetchedUserNFTs.MarshalJSON() + if(err != nil){ + panic("error in fetching user NFTs") + } + + return string(userNFTs) +} + +// util + +func GetCompositeNFTRealmAddress() std.Address { + return std.CurrentRealm().Addr() +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/flippando/errors.gno b/examples/gno.land/r/demo/flippando/errors.gno new file mode 100644 index 00000000000..f02ee6e214e --- /dev/null +++ b/examples/gno.land/r/demo/flippando/errors.gno @@ -0,0 +1,14 @@ +package flippando + +import "errors" + +var ( + ErrUserHasZeroGame = errors.New("user has zero games") + ErrSVGDataFailed = errors.New("SVG data not generated") + ErrGameNotComplete = errors.New("game not complete, board has gaps") + ErrInvalidTokenId = errors.New("invalid TokenID") + ErrUnlockingRecipientNotFound = errors.New("recipient for unlocking not found") + ErrMarketplaceListingDoesNotExist = errors.New("This listing does not exist") + ErrFlipTokenBalanceOfFailed = errors.New("Error in calling BalanceOf for FLIP") + ErrFlipTokenNotEnoughBalance = errors.New("Not enough FLIP balance for this trade") +) \ No newline at end of file diff --git a/examples/gno.land/r/demo/flippando/flip_marketplace_test.gno b/examples/gno.land/r/demo/flippando/flip_marketplace_test.gno new file mode 100644 index 00000000000..cf6d6b7737e --- /dev/null +++ b/examples/gno.land/r/demo/flippando/flip_marketplace_test.gno @@ -0,0 +1,142 @@ +package flippando + +import ( + "std" + "testing" + + "gno.land/r/demo/users" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/grc/grc721" + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/avl" +) + +var ( + dummyNFTName = "DummyNFT" + dummyNFTSymbol = "DNFT" +) + +/* +func TestListNFT(t *testing.T) { + marketplace, compositeNFT, _ := setupMockMarketplace() + + seller := users.AddressOrName("g1seller") + compositeTokenID := grc721.TokenID("1") + basicTokenIDs := []grc721.TokenID{grc721.TokenID("1"), grc721.TokenID("2")} + + // Mock minting of composite NFT + compositeNFT.mint(seller.Resolve(), compositeTokenID) + + err := marketplace.ListNFT(compositeTokenID, basicTokenIDs, seller.Resolve(), 100) + if err != nil { + t.Errorf("listing NFT failed: %v", err) + } + + _, exists := marketplace.listings.Get(string(compositeTokenID)) + if !exists { + t.Errorf("NFT not listed in the marketplace") + } +} + +func TestRemoveListing(t *testing.T) { + marketplace, compositeNFT, _, _ := setupMockMarketplace() + + seller := users.AddressOrName("g1seller") + compositeTokenID := TokenID("1") + basicTokenIDs := []TokenID{TokenID("1"), TokenID("2")} + + mintMockNFTs(compositeNFT, seller.Resolve(), compositeTokenID) + marketplace.ListNFT(compositeTokenID, basicTokenIDs, seller.Resolve(), 100) + + err := marketplace.RemoveListing(compositeTokenID, seller.Resolve()) + if err != nil { + t.Errorf("removing listing failed: %v", err) + } + + _, exists := marketplace.listings.Get(string(compositeTokenID)) + if exists { + t.Errorf("NFT listing was not removed") + } +} + +func TestUnauthorizedListingRemoval(t *testing.T) { + marketplace, compositeNFT, _, _ := setupMockMarketplace() + + seller := users.AddressOrName("g1seller") + unauthorized := users.AddressOrName("g1unauth") + compositeTokenID := TokenID("1") + basicTokenIDs := []TokenID{TokenID("1"), TokenID("2")} + + mintMockNFTs(compositeNFT, seller.Resolve(), compositeTokenID) + marketplace.ListNFT(compositeTokenID, basicTokenIDs, seller.Resolve(), 100) + + err := marketplace.RemoveListing(compositeTokenID, unauthorized.Resolve()) + if err == nil { + t.Errorf("unauthorized removal did not fail as expected") + } +} + +func TestBuyNFT(t *testing.T) { + marketplace, compositeNFT, basicNFT, flipToken := setupMockMarketplace() + + seller := users.AddressOrName("g1seller") + buyer := users.AddressOrName("g1buyer") + compositeTokenID := TokenID("1") + basicTokenIDs := []TokenID{TokenID("1"), TokenID("2")} + + mintMockNFTs(compositeNFT, seller.Resolve(), compositeTokenID) + mintMockNFTs(basicNFT, seller.Resolve(), basicTokenIDs...) + flipToken.Mint(buyer.Resolve(), 1000) + marketplace.ListNFT(compositeTokenID, basicTokenIDs, seller.Resolve(), 100) + + err := marketplace.BuyNFT(buyer.Resolve(), compositeTokenID) + if err != nil { + t.Errorf("buying NFT failed: %v", err) + } + + newOwner, _ := compositeNFT.OwnerOf(compositeTokenID) + if newOwner != buyer.Resolve() { + t.Errorf("ownership not transferred to buyer") + } +} + +func TestBuyNFTWithInsufficientFLIP(t *testing.T) { + marketplace, compositeNFT, basicNFT, flipToken := setupMockMarketplace() + + seller := users.AddressOrName("g1seller") + buyer := users.AddressOrName("g1buyer") + compositeTokenID := TokenID("1") + basicTokenIDs := []TokenID{TokenID("1"), TokenID("2")} + + mintMockNFTs(compositeNFT, seller.Resolve(), compositeTokenID) + mintMockNFTs(basicNFT, seller.Resolve(), basicTokenIDs...) + flipToken.Mint(buyer.Resolve(), 50) // Insufficient balance + marketplace.ListNFT(compositeTokenID, basicTokenIDs, seller.Resolve(), 100) + + err := marketplace.BuyNFT(buyer.Resolve(), compositeTokenID) + if err == nil { + t.Errorf("expected failure due to insufficient FLIP tokens, but transaction succeeded") + } +} + + +func setupMockMarketplace() (*Marketplace, grc721.IGRC721, *grc20.AdminToken) { + // Mock setup for flipCompositeNFT and FLIP token + compositeNFT := grc721.NewBasicNFT("Flippando Composite NFT", "CFLP") + basicNFT := grc721.NewBasicNFT("Flippando Basic NFT", "BFLP") + flipToken := grc20.NewAdminToken("Flippando", "FLIP", 6) + + // Create a marketplace instance with mock contracts + marketplace := NewMarketplace(compositeNFT, basicNFT, flipToken) + return marketplace, compositeNFT, basicNFT, flipToken +} + + + +func mintMockNFTs(nftContract grc721.IGRC721, owner std.Address, tokenIDs ...grc721.TokenID) { + for _, tokenID := range tokenIDs { + nftContract.mint(owner, tokenID) + } +}*/ + diff --git a/examples/gno.land/r/demo/flippando/flippando.gno b/examples/gno.land/r/demo/flippando/flippando.gno new file mode 100644 index 00000000000..d100d42740e --- /dev/null +++ b/examples/gno.land/r/demo/flippando/flippando.gno @@ -0,0 +1,212 @@ +package flippando + +import ( + "time" + "strconv" + "std" + + "gno.land/p/demo/avl" + "gno.land/p/demo/grc/grc721" + "gno.land/p/demo/flippandoserver" +) + +// realm state +var ( + gameStore avl.Tree // string (game ID) -> *Game + gameIDCounter uint64 + + user2Games avl.Tree // std.Address -> []*Game + marketplace = NewMarketplace() +) + +const zeroes = "000000000" + +// creates game object and initializes board +func StartGame(player std.Address, tileType string, boardSize int) string { + + // Set up Game struct. Save in gameStore and user2games. + gameIDCounter++ + board, gameTiles, boardSize := flippandoserver.CreateGameBoard(tileType, boardSize, time.Now().Unix()) + + // id is zero-padded to work well with avl's alphabetic order. + id := zeroPad9(strconv.FormatUint(gameIDCounter, 10)) + g := &Game{ + ID: id, + GameBoard: make([]int64, len(board)), + SolvedGameBoard: make([]int64, len(board)), + GameTiles: gameTiles, + TileType: tileType, + GameStatus: "initialized", + } + copy(g.GameBoard, board) + copy(g.SolvedGameBoard, board) + + gameStore.Set(g.ID, g) + addToUser2Games(player, g) + + newGameJSON, err := g.MarshalJSON() + if err != nil { + return "error"; + } + return string(newGameJSON) +} + + +func FlipTiles(player std.Address, gameID string, positions string) (string) { + // get the current game of the player + games := GetUserGames(player) + var currentGame *Game // Declare a pointer to a Game + for _, game := range games { + if game.ID == gameID { + currentGame = game + break // Stop the loop once the game is found + } + } + currentGamePositions, err := ParseString(positions) + + // calls real FlipTiles on flippandoserver, which does the game mechanics + // and returns 2 []int64 boards: the GameBoard, and the SolvedGameBoard + + board, solvedBoard := flippandoserver.FlipTiles(currentGame.GameBoard, + currentGame.SolvedGameBoard, + currentGame.GameTiles, + currentGamePositions, + time.Now().Unix()) + currentGame.GameBoard = board + currentGame.SolvedGameBoard = solvedBoard + hasZeroValues := func(s []int64) bool { for _, v := range s { if v == 0 { return true } }; return false }(currentGame.SolvedGameBoard) + if(!hasZeroValues){ + currentGame.GameStatus = "finished" + } + currentGameJSON, err := currentGame.MarshalJSON() + if err != nil { + return "error"; + } + return string(currentGameJSON) +} + +func CreateBasicNFT(player std.Address, gameId string) string { + // calls CreateBasicFlipNFT from basicNFT.gno + // calls MintFlipFungibleToken from token,gno + // locks the Flip fungible token inside the basicNFT in nft2Flip avl.tree + + metadata, errString := CreateBasicFlipNFT(player, gameId) + if errString != "" { + return errString + } + return metadata +} + +func GetUserBasicNFTs(addr std.Address, readyToUse string) string { + // calls GetUserBasicFlipNFTs from basicNFT.gno + userNFTs := GetUserBasicFlipNFTs(addr, readyToUse) + return userNFTs +} + +// if excludePlayer is != "" return all nfts except those of excludePlayer +// used in displaying available nfts for art +// if excludePlayer == "" return all nfts, used for stats, etc +func GetAllBasicNFTs(excludePlayer std.Address) string { + allNFTs := GetAllBasicFlipNFTs(excludePlayer) + return allNFTs +} + +func CreateCompositeNFT(player std.Address, cWidth string, cHeight string, bTokenIDsArray string) string { + metadata, errString := CreateCompositeFlipNFT(player, cWidth, cHeight, bTokenIDsArray) + + if errString != "" { + return errString + } + return metadata +} + +func GetUserGames(user std.Address) []*Game { + val, exist := user2Games.Get(user.String()) + //var games []*Game + if !exist { + return nil + } + return val.([]*Game) +} + +func GetUserGamesByStatus(user std.Address, status string) string { + val, exist := user2Games.Get(user.String()) + if !exist { + return "{\"userGames\":[]}" + } + + allGames := val.([]*Game) + var matchingGames []Game + for _, game := range allGames { + if game.GameStatus == status { + matchingGames = append(matchingGames, *game) + } + } + + ugr := UserGamesResult{ + UserGames: matchingGames, + } + + ugrJSON, err := ugr.MarshalJSON() + if err != nil { + panic(err) + } + + return string(ugrJSON) +} + + +func addToUser2Games(addr std.Address, game *Game) { + var games []*Game + v, ok := user2Games.Get(string(addr)) + if ok { + games = v.([]*Game) + } + // game must be at top, because it is the latest ID + games = append([]*Game{game}, games...) + user2Games.Set(string(addr), games) +} + +// marketplace wrapper + +func GetArtListings() string { + return marketplace.GetCompositeNFTListings() +} + +func GetBasicListings() string { + return marketplace.GetBasicNFTListings() +} + +func ListCompositeNFT(compositeTokenID string, seller std.Address, price string) error { + return marketplace.ListCompositeNFT(grc721.TokenID(compositeTokenID), seller, price); +} + +func ListBasicNFT(basicTokenID string, seller std.Address, price string) error { + return marketplace.ListBasicNFT(grc721.TokenID(basicTokenID), seller, price); +} + +func BuyCompositeNFT(buyer std.Address, compositeTokenId string, ) (buyNFTResult string) { + return marketplace.BuyCompositeNFT(buyer, grc721.TokenID(compositeTokenId)) +} + +func BuyBasicNFT(buyer std.Address, basicTokenId string, ) (buyNFTResult string) { + return marketplace.BuyBasicNFT(buyer, grc721.TokenID(basicTokenId)) +} + +func RemoveCompositeNFTListing(compositeTokenID string, seller std.Address) error { + return marketplace.RemoveCompositeNFTListing(grc721.TokenID(compositeTokenID), seller) +} + +func RemoveBasicNFTListing(compositeTokenID string, seller std.Address) error { + return marketplace.RemoveBasicNFTListing(grc721.TokenID(compositeTokenID), seller) +} + +func IsBasicTokenIdListed(tokenId string) error { + return marketplace.IsBasicTokenIdListed(tokenId) +} + +func RenderHome() string { + return "render path" +} + + diff --git a/examples/gno.land/r/demo/flippando/flippando_test.gno b/examples/gno.land/r/demo/flippando/flippando_test.gno new file mode 100644 index 00000000000..dc1ce7016ea --- /dev/null +++ b/examples/gno.land/r/demo/flippando/flippando_test.gno @@ -0,0 +1,66 @@ +package flippando + +import ( + "math" + "strconv" + "std" + "testing" + "encoding/json" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/grc/grc721" + "gno.land/p/demo/flippandoserver" + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/avl" +) + +// todo refactor this so it actually works +func TestStartGame(t *testing.T) { + player := std.Address("someAddress") + tileType := "someType" + boardSize := 16 + + expectedGameJSON := `{"id":"000000001","gameBoard":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"solvedGameBoard":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"gameTiles":[1,3,5,8],"gameStatus":"initialized"}` + + got := StartGame(player, tileType, boardSize) + if got != expectedGameJSON { + t.Errorf("StartGame() = %v; want %v", got, expectedGameJSON) + } +} + +func TestCreateNFT(t *testing.T) { + mockPlayer := std.Address("someAddress") + mockGameId := "someGameID" + + CreateBasicNFT(mockPlayer, mockGameId) + + metadata, err := CreateBasicFlipNFT(mockPlayer, mockGameId) + if err != "" { + t.Fatalf("Expected no error, got %s", err) + } + if metadata == "" { + t.Error("Expected metadata to be non-empty") + } + +} + +func testMarshalJSON(t *testing.T) { + fbn := BasicNFTMetaData{ + name: "Flippando - the Game", + version: "1.0.0", + gameId: "game123", + gameType: "classic", + svgData: "someSVGData", + } + expectedJSON := `{"name":"Flippando - the Game","version":"1.0.0","gameId":"game123","gameType":"classic","svgData":"someSVGData"}` + jsonData, err := fbn.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + if string(jsonData) != expectedJSON { + t.Errorf("MarshalJSON() = %s; want %s", string(jsonData), expectedJSON) + } +} + + + diff --git a/examples/gno.land/r/demo/flippando/flippandosvg.gno b/examples/gno.land/r/demo/flippando/flippandosvg.gno new file mode 100644 index 00000000000..65a56fbf7e5 --- /dev/null +++ b/examples/gno.land/r/demo/flippando/flippandosvg.gno @@ -0,0 +1,327 @@ +package flippando + +import ( + "strings" + "strconv" + "errors" + "encoding/base64" + + "gno.land/p/demo/ufmt" +) + +type Dice struct { + d1, d2, d3, d4, d5, d6 string +} + +type Hexagram struct { + h1, h2, h3, h4 string +} + +func GenerateGrid(solvedBoard []int64, gridType string) (string, error) { + var size int + switch len(solvedBoard) { + case 16: + size = 4 + case 64: + size = 8 + case 256: + size = 16 + default: + return "", errors.New("invalid board size") + } + + switch gridType { + case "squareGrid", "greyGradient", "redGradient", "greenGradient", "blueGradient": + return generateColorSquareGrid(solvedBoard, gridType, size) + case "dice": + return generateDiceGrid(solvedBoard, size) + case "hexagrams": + return generateHexagramGrid(solvedBoard, size) + default: + return "", errors.New("invalid grid type") + } +} + + +func generateColorSquareGrid(solvedBoard []int64, gridType string, size int) (string, error) { + svgSquare := `` + if size == 8 { + svgSquare = `` + } + + for i := int64(0); i < int64(size); i++ { + for j := int64(0); j < int64(size); j++ { + index := i*int64(size) + j + key := solvedBoard[index] + color, _ := getColorFromKey(key, gridType) + rect := ufmt.Sprintf(``, color, intToString(j*25), intToString(i*25)) + svgSquare += rect + } + } + svgSquare += `` + base64Svg := base64.StdEncoding.EncodeToString([]byte(svgSquare)) + return base64Svg, nil +} + +func generateDiceGrid(solvedBoard []int64, size int) (string, error) { + dice := Dice{ + d1: ``, + d2: ``, + d3: ``, + d4: ``, + d5: ``, + d6: ``, + + } + + var svg strings.Builder + svgSquare := `` + if size == 8 { + svgSquare = `` + } + svg.WriteString(svgSquare) + + for i := int(0); i < size; i++ { + for j := int(0); j < size; j++ { + index := i*size + j + var diceFace string + + switch solvedBoard[index] { + case 1: + diceFace = dice.d1 + case 2: + diceFace = dice.d2 + case 3: + diceFace = dice.d3 + case 4: + diceFace = dice.d4 + case 5: + diceFace = dice.d5 + case 6: + diceFace = dice.d6 + } + + svg.WriteString(ufmt.Sprintf(`%s`, j*25, i*25, diceFace)) + } + } + + svg.WriteString(``) + svgBytes := svg.String() + base64Svg := base64.StdEncoding.EncodeToString([]byte(svgBytes)) + return base64Svg, nil +} + +func generateHexagramGrid(solvedBoard []int64, size int) (string, error) { + hexagram := Hexagram{ + h1: ``, + h2: ``, + h3: ``, + h4: ``, + } + + var svg strings.Builder + svgSquare := `` + if size == 8 { + svgSquare = `` + } + svg.WriteString(svgSquare) + + for i := int(0); i < size; i++ { + for j := int(0); j < size; j++ { + index := i*size + j + var hexagramType string + + switch solvedBoard[index] { + case 1: + hexagramType = hexagram.h1 + case 2: + hexagramType = hexagram.h2 + case 3: + hexagramType = hexagram.h3 + case 4: + hexagramType = hexagram.h4 + } + + svg.WriteString(ufmt.Sprintf(`%s`, j*25, i*25, hexagramType)) + } + } + + svg.WriteString(``) + svgBytes := svg.String() + base64Svg := base64.StdEncoding.EncodeToString([]byte(svgBytes)) + return base64Svg, nil + +} + +// util +func intToString(value int64) string { + formatted := strconv.FormatUint(uint64(value), 10) + return formatted; +} + +func getColorFromKey(key int64, gridType string) (string, error) { + switch key { + case int64(1): + switch gridType { + case "squareGrid": + return "#D9362A", nil + case "greyGradient": + return "#101010", nil + case "redGradient": + return "#800000", nil + case "greenGradient": + return "#008000", nil + case "blueGradient": + return "#000080", nil + } + case int64(2): + switch gridType { + case "squareGrid": + return "#BE185D", nil + case "greyGradient": + return "#303030", nil + case "redGradient": + return "#901010", nil + case "greenGradient": + return "#109010", nil + case "blueGradient": + return "#101090", nil + } + + case int64(3): + switch gridType { + case "squareGrid": + return "#EC1818", nil + case "greyGradient": + return "#505050", nil + case "redGradient": + return "#a02020", nil + case "greenGradient": + return "#20a020", nil + case "blueGradient": + return "#2020a0", nil + } + + case int64(4): + switch gridType { + case "squareGrid": + return "#F4AA24", nil + case "greyGradient": + return "#707070", nil + case "redGradient": + return "#b03030", nil + case "greenGradient": + return "#30b030", nil + case "blueGradient": + return "#3030b0", nil + } + + case int64(5): + switch gridType { + case "squareGrid": + return "#F4D424", nil + case "greyGradient": + return "#909090", nil + case "redGradient": + return "#c04040", nil + case "greenGradient": + return "#40c040", nil + case "blueGradient": + return "#4040c0", nil + } + + case int64(6): + switch gridType { + case "squareGrid": + return "#F1F223", nil + case "greyGradient": + return "#b0b0b0", nil + case "redGradient": + return "#d05050", nil + case "greenGradient": + return "#50d050", nil + case "blueGradient": + return "#5050d0", nil + } + + case int64(7): + switch gridType { + case "squareGrid": + return "#A5DD0C", nil + case "greyGradient": + return "#d0d0d0", nil + case "redGradient": + return "#e06060", nil + case "greenGradient": + return "#60e060", nil + case "blueGradient": + return "#6060e0", nil + } + + case int64(8): + switch gridType { + case "squareGrid": + return "#37B400", nil + case "greyGradient": + return "#f0f0f0", nil + case "redGradient": + return "#f07070", nil + case "greenGradient": + return "#70f070", nil + case "blueGradient": + return "#7070f0", nil + } + + case int64(9): + switch gridType { + case "squareGrid": + return "#98D0E9", nil + } + + case int64(10): + switch gridType { + case "squareGrid": + return "#3131FD", nil + } + + case int64(11): + switch gridType { + case "squareGrid": + return "#1D2C85", nil + } + + case int64(12): + switch gridType { + case "squareGrid": + return "#F2F2F2", nil + } + + case int64(13): + switch gridType { + case "squareGrid": + return "#1A1A1A", nil + } + + case int64(14): + switch gridType { + case "squareGrid": + return "#71842F", nil + } + + case int64(15): + switch gridType { + case "squareGrid": + return "#90572F", nil + } + + case int64(16): + switch gridType { + case "squareGrid": + return "#8316C0", nil + } + + default: + panic("Invalid color key " + intToString(key) + " " + gridType) + } + return "", nil +} diff --git a/examples/gno.land/r/demo/flippando/flippandosvg_test.gno b/examples/gno.land/r/demo/flippando/flippandosvg_test.gno new file mode 100644 index 00000000000..a0c3360872a --- /dev/null +++ b/examples/gno.land/r/demo/flippando/flippandosvg_test.gno @@ -0,0 +1,77 @@ +package flippando + +import ( + "std" + "testing" + "strings" + "encoding/base64" + + "gno.land/p/demo/testutils" +) + +func TestGenerateGrid(t *testing.T) { + solvedBoard := generateSolvedBoard() + + tests := []struct { + name string + solvedBoard []int64 + gridType string + expectError bool + }{ + {"ValidSquareGrid", solvedBoard, "squareGrid", false}, + {"ValidDiceGrid", solvedBoard, "dice", false}, + {"ValidHexagramGrid", solvedBoard, "hexagrams", false}, + {"InvalidGridType", solvedBoard, "invalidType", true}, + {"InvalidBoardSize", make([]int64, 10), "squareGrid", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := GenerateGrid(tt.solvedBoard, tt.gridType) + if (err != nil) != tt.expectError { + t.Errorf("GenerateGrid() error = %v, expectError %v", err, tt.expectError) + } + }) + } +} + +func TestGenerateColorSquareGrid(t *testing.T) { + // Example solved board + solvedBoard := generateSolvedBoard() + + // Call the function with the test board + base64Svg, err := generateColorSquareGrid(solvedBoard, "squareGrid", 4) // gridType squareGrid, size 4 for a 4x4 grid + if err != nil { + t.Fatalf("generateColorSquareGrid returned an unexpected error: %v", err) + } + + // Decode the Base64-encoded SVG string + svgBytes, err := base64.StdEncoding.DecodeString(base64Svg) + if err != nil { + t.Fatalf("Error decoding Base64 SVG string: %v", err) + } + svg := string(svgBytes) + + // Check if the SVG string starts with + if !strings.HasPrefix(svg, "") { + t.Errorf("SVG does not start with ''") + } + + // Count the number of elements + rectCount := strings.Count(svg, " elements, found %d", expectedRectCount, rectCount) + } +} + + +func generateSolvedBoard() []int64 { + board := make([]int64, 16) + for i := 0; i < 4; i++ { + for j := 1; j <= 4; j++ { + board[i*4+j-1] = int64(j) + } + } + return board +} diff --git a/examples/gno.land/r/demo/flippando/gno.mod b/examples/gno.land/r/demo/flippando/gno.mod new file mode 100644 index 00000000000..13520af5420 --- /dev/null +++ b/examples/gno.land/r/demo/flippando/gno.mod @@ -0,0 +1,5 @@ +module "gno.land/r/demo/flippando" + +require ( + "gno.land/p/demo/flippandoserver" v0.0.0-latest +) \ No newline at end of file diff --git a/examples/gno.land/r/demo/flippando/marketplace.gno b/examples/gno.land/r/demo/flippando/marketplace.gno new file mode 100644 index 00000000000..dbfbab4e1da --- /dev/null +++ b/examples/gno.land/r/demo/flippando/marketplace.gno @@ -0,0 +1,384 @@ +package flippando + +import ( + "errors" + "strconv" + "strings" + "std" + "gno.land/p/demo/ufmt" + "gno.land/p/demo/grc/grc721" +) + +type Marketplace struct { + listings map[string]Listing // CompositeTokenID -> Listing + basicListings map[string]BasicListing // BasicTokenID -> Listing +} + +type Listing struct { + CompositeTokenID grc721.TokenID // TokenID of the composite NFT + BasicTokenIDs []int64 // Slice of TokenIDs for the basic NFTs contained within the composite NFT + Seller std.Address // Address of the seller + Price uint64 // Sale price +} + +type BasicListing struct { + BasicTokenID grc721.TokenID // TokenID of the basic NFT + Seller std.Address // Address of the seller + Price uint64 // Sale price +} + +func NewMarketplace() *Marketplace { + return &Marketplace{ + listings: make(map[string]Listing), + basicListings: make(map[string]BasicListing), + } +} + +func (m *Marketplace) ListCompositeNFT(compositeTokenID grc721.TokenID, seller std.Address, price string) error { + // approve it for buying + FlipCompositeNFT.Approve(std.CurrentRealm().Addr(), compositeTokenID) + // get tokenURI of the composite NFT + compositeTokenIDstr := string(compositeTokenID) + basicTokenIDArray, err := GetChildrenOf(compositeTokenIDstr) + if err != nil { + return err + } + basicTokenIDs, _ := ParseString(basicTokenIDArray) + // approve all basic NFTs for transferring + for _, t := range basicTokenIDs { + basicTokenId := grc721.TokenID(strconv.FormatInt(t, 10)) + FlipBasicNFT.Approve(std.CurrentRealm().Addr(), basicTokenId) + } + // convert price into uflips, multiply by 1000 + intPrice, ferr := convertPriceStringToUint64(price) + if ferr != nil { + return ferr + } + // Create a new listing + newListing := Listing{ + CompositeTokenID: compositeTokenID, + BasicTokenIDs: basicTokenIDs, + Seller: seller, + Price: intPrice, + } + + // Add the new listing to the marketplace + m.listings[compositeTokenIDstr] = newListing + return nil +} + +func (m *Marketplace) ListBasicNFT(basicTokenID grc721.TokenID, seller std.Address, price string) error { + // approve it for buying + FlipBasicNFT.Approve(std.CurrentRealm().Addr(), basicTokenID) + // convert price into uflips, multiply by 1000 + intPrice, ferr := convertPriceStringToUint64(price) + if ferr != nil { + return ferr + } + // Create a new listing + newBasicListing := BasicListing{ + BasicTokenID: basicTokenID, + Seller: seller, + Price: intPrice, + } + + // Add the new listing to the marketplace + m.basicListings[string(basicTokenID)] = newBasicListing + return nil +} + +func (m *Marketplace) RemoveCompositeNFTListing(compositeTokenID grc721.TokenID, seller std.Address) error { + // Retrieve the listing + rawListing, exists := m.listings[string(compositeTokenID)] + if !exists { + return errors.New("listing does not exist") + } + + listing := rawListing + + // Verify that the caller is the seller + if listing.Seller != seller { + return errors.New("unauthorized - caller is not the seller") + } + + // Remove the listing from the marketplace + delete(m.listings, string(compositeTokenID)) + return nil +} + +func (m *Marketplace) RemoveBasicNFTListing(basicTokenID grc721.TokenID, seller std.Address) error { + // Retrieve the listing + rawListing, exists := m.basicListings[string(basicTokenID)] + if !exists { + return errors.New("basic listing does not exist") + } + + listing := rawListing + + // Verify that the caller is the seller + if listing.Seller != seller { + return errors.New("unauthorized - caller is not the seller") + } + + // Remove the listing from the marketplace + delete(m.basicListings, string(basicTokenID)) + // move approval to Basic NFT in case the basic NFT is to be used + // in the assembly of a composite NFT later on + FlipBasicNFT.Approve(GetBasicNFTRealmAddress(), basicTokenID) + return nil +} + +func (m *Marketplace) GetCompositeNFTListings() string { + var allListings []string + for _, value := range m.listings { + // Type assert the value to a Listing + listing := value + compositeTokenURI := GetCompositeTokenURI(string(listing.CompositeTokenID)) + compositeTokenURI = strings.Trim(compositeTokenURI, "\"") + + listingResult := &listingCompositeResult{ + compositeTokenID: string(listing.CompositeTokenID), + tokenURI: compositeTokenURI, + seller: string(listing.Seller), + price: strconv.FormatUint(listing.Price, 10), + } + listingResultJSON, _ := listingResult.MarshalJSON() + allListings = append(allListings, string(listingResultJSON)) + } + + marketplaceListings := &marketplaceListings{ + marketplaceListings: allListings, + } + marketplaceJSON, _ := marketplaceListings.MarshalJSON() + + return string(marketplaceJSON) +} + +func (m *Marketplace) GetBasicNFTListings() string { + var allListings []string + for _, value := range m.basicListings { + // Type assert the value to a Listing + listing := value + basicTokenURI := GetBasicTokenURI(string(listing.BasicTokenID)) + + listingBasicResult := &listingBasicResult{ + basicTokenID: string(listing.BasicTokenID), + tokenURI: basicTokenURI, + seller: string(listing.Seller), + price: strconv.FormatUint(listing.Price, 10), + } + listingResultJSON, _ := listingBasicResult.MarshalJSON() + allListings = append(allListings, string(listingResultJSON)) + } + + marketplaceListings := &marketplaceListings{ + marketplaceListings: allListings, + } + marketplaceJSON, _ := marketplaceListings.MarshalJSON() + + return string(marketplaceJSON) +} + +func (m *Marketplace) IsBasicTokenIdListed(tokenId string) error { + if _, exists := m.basicListings[tokenId]; exists { + return errors.New("tokenId is already listed") + } + return nil +} + +func (m *Marketplace) BuyCompositeNFT(buyer std.Address, compositeTokenID grc721.TokenID) (buyResult string) { + var buyError error + + flipPaid := "" + flipBurned := "" + listingRaw, exists := m.listings[string(compositeTokenID)] + if !exists { + buyError = ErrMarketplaceListingDoesNotExist + } + listing := listingRaw + + + compositeNFTOwner := GetOwnerOfCompositeTokenId(string(compositeTokenID)) + tcerr := TransferCompositeNFT(std.Address(listing.Seller), buyer, compositeTokenID) + if tcerr != nil { + buyError = errors.New(ufmt.Sprintf("TransferCompositeNFT error: seller=%s, buyer=%s, tokenID=%s, owner=%s, error: %s", listing.Seller, buyer, string(compositeTokenID), compositeNFTOwner, tcerr.Error())) + } + + transferredBasicNFTs := []grc721.TokenID{} + + if buyError == nil { + for _, t := range listing.BasicTokenIDs { + basicTokenId := grc721.TokenID(strconv.FormatInt(t, 10)) + ownerBasicNFT := GetOwnerOfBasicNFT(string(basicTokenId)) + //FlipBasicNFT.Approve(std.CurrentRealm().Addr(), basicTokenId) + berr := FlipBasicNFT.TransferFrom(std.Address(listing.Seller), buyer, basicTokenId) + if berr != nil { + buyError = errors.New(ufmt.Sprintf("FlipBasicNFT.TransferFrom error: seller=%s, buyer=%s, basicTokenId=%s, owner=%s, error: %s", listing.Seller, buyer, string(basicTokenId), string(ownerBasicNFT), berr.Error())) + break + } + transferredBasicNFTs = append(transferredBasicNFTs, basicTokenId) + } + + if buyError != nil { + reverr := TransferCompositeNFT(buyer, std.Address(listing.Seller), compositeTokenID) + if reverr != nil { + buyError = errors.New(ufmt.Sprintf("revert TransferCompositeNFT error: seller=%s, buyer=%s, tokenID=%s, owner=%s, error: %s", listing.Seller, buyer, string(compositeTokenID), compositeNFTOwner, tcerr.Error())) + } + // Revert any successfully transferred basic NFTs + for _, basicTokenId := range transferredBasicNFTs { + //FlipBasicNFT.Approve(std.CurrentRealm().Addr(), basicTokenId) + _ = FlipBasicNFT.TransferFrom(buyer, std.Address(listing.Seller), basicTokenId) + } + } + } + + if buyError == nil { + fPricePaid, fPriceBurned, terr := PayFLIPToSeller(buyer, listing.Seller, std.NewCoin("FLIP", int64(listing.Price))) + if terr != nil { + buyError = terr + //revert the sale on FLIP transfer error, most likely not enough tokens + reverr := TransferCompositeNFT(buyer, std.Address(listing.Seller), compositeTokenID) + if reverr != nil { + buyError = errors.New(ufmt.Sprintf("revert TransferCompositeNFT on FLIP error: seller=%s, buyer=%s, tokenID=%s, owner=%s, error: %s", listing.Seller, buyer, string(compositeTokenID), compositeNFTOwner, tcerr.Error())) + } + // Revert any successfully transferred basic NFTs + for _, basicTokenId := range transferredBasicNFTs { + //FlipBasicNFT.Approve(std.CurrentRealm().Addr(), basicTokenId) + _ = FlipBasicNFT.TransferFrom(buyer, std.Address(listing.Seller), basicTokenId) + } + } + flipPaid = fPricePaid + flipBurned = fPriceBurned + } + + if buyError == nil { + delete(m.listings, string(compositeTokenID)) + } + + var buyErrorString string + if buyError != nil { + buyErrorString = buyError.Error() + } else { + buyErrorString = "" + } + + buyNFTResultObject := &buyNFTResult{ + flipPaid: flipPaid, + flipBurned: flipBurned, + buyerror: buyErrorString, + } + buyResultJSON, merr := buyNFTResultObject.MarshalJSON() + + if merr != nil { + buyError = errors.New("Error in marshaling buyNFTResult") + } + return string(buyResultJSON) +} + +func (m *Marketplace) BuyBasicNFT(buyer std.Address, basicTokenID grc721.TokenID) (buyResult string) { + var buyError error + + flipPaid := "" + flipBurned := "" + listingRaw, exists := m.basicListings[string(basicTokenID)] + if !exists { + buyError = ErrMarketplaceListingDoesNotExist + } + listing := listingRaw + + basicNFTOwner := GetOwnerOfBasicNFT(string(basicTokenID)) + + // Pay the price, including random burning + if buyError == nil { + fPricePaid, fPriceBurned, terr := PayFLIPToSeller(buyer, listing.Seller, std.NewCoin("FLIP", int64(listing.Price))) + if terr != nil { + buyError = terr + } + flipPaid = fPricePaid + flipBurned = fPriceBurned + } + + // Transfer the basic NFT + if buyError == nil { + berr := FlipBasicNFT.TransferFrom(std.Address(listing.Seller), buyer, basicTokenID) + if berr != nil { + buyError = errors.New(ufmt.Sprintf("TransferFrom inside BuyBsicNFT error: seller=%s, buyer=%s, basicTokenId=%s, owner=%s, error: %s", listing.Seller, buyer, string(basicTokenID), string(basicNFTOwner), berr.Error())) + } + } + + // Transfer locked FLIP to buyer + if buyError == nil { + lerr := TransferLockedFLIP(std.Address(listing.Seller), buyer, string(basicTokenID)) + if lerr != nil { + buyError = errors.New(ufmt.Sprintf("TransferLockedFLIP error: seller=%s, buyer=%s, basicTokenId=%s, owner=%s, error: %s", listing.Seller, buyer, string(basicTokenID), string(basicNFTOwner), lerr.Error())) + } + } + + // If no errors, remove the listing + if buyError == nil { + delete(m.basicListings, string(basicTokenID)) + // move approval to Basic NFT in case the basic NFT is to be used + // in the assembly of a composite NFT later on + FlipBasicNFT.Approve(GetBasicNFTRealmAddress(), basicTokenID) + } + + + + return prepareBuyResult(flipPaid, flipBurned, buyError) +} + +// util + +func convertPriceStringToUint64(price string) (uint64, error) { + // Split the string at the decimal point + parts := strings.Split(price, ".") + + // Parse the integer part + integerPart, err := strconv.Atoi(parts[0]) + if err != nil { + return 0, err + } + + // Parse the fractional part and ensure it has at least three digits + var fractionalPart int + if len(parts) > 1 { + fractionalPartStr := parts[1] + if len(fractionalPartStr) > 3 { + fractionalPartStr = fractionalPartStr[:3] + } + fractionalPart, err = strconv.Atoi(fractionalPartStr) + if err != nil { + return 0, err + } + for len(fractionalPartStr) < 3 { + fractionalPart *= 10 + fractionalPartStr += "0" + } + } + + // Combine the integer and fractional parts + combined := uint64(integerPart * 1000 + fractionalPart) + return combined, nil +} + +func prepareBuyResult(flipPaid, flipBurned string, buyError error) string { + var buyErrorString string + if buyError != nil { + buyErrorString = buyError.Error() + } else { + buyErrorString = "" + } + + buyNFTResultObject := &buyNFTResult{ + flipPaid: flipPaid, + flipBurned: flipBurned, + buyerror: buyErrorString, + } + buyResultJSON, merr := buyNFTResultObject.MarshalJSON() + + if merr != nil { + return errors.New("Error in marshaling buyNFTResult").Error() + } + return string(buyResultJSON) +} + diff --git a/examples/gno.land/r/demo/flippando/marshals.gno b/examples/gno.land/r/demo/flippando/marshals.gno new file mode 100644 index 00000000000..e0c7998112b --- /dev/null +++ b/examples/gno.land/r/demo/flippando/marshals.gno @@ -0,0 +1,438 @@ +package flippando + +import ( + "strconv" + "bytes" +) + +type GameBoard struct { + Board []int64 `json:"board"` + GameTiles []int64 `json:"gameTiles"` + BoardSize int `json:"boardSize"` +} + +type Game struct { + ID string `json:"id"` + GameStatus string `json:"gameStatus"` + GameBoard []int64 `json:"gameBoard"` + SolvedGameBoard []int64 `json:"solvedGameBoard"` + GameTiles []int64 `json:"gameTiles"` + TileType string `json:"tileType"` +} + +type GameResult struct { + ID string `json:"id"` + GameBoard string `json:"gameBoard"` + TileType string `json:"tileTpye"` +} + +type UserGamesResult struct { + UserGames []Game `json:"userGames"` +} + +type BasicNFTMetaData struct { + tokenID string `json:"tokenID"` + name string `json:"name"` + version string `json:"version"` + gameId string`json:"gameId"` + gameType string `json:"gameType"` + gameLevel string `json:"gameLevel"` + svgData string `json:"svgData"` + airdropName string `json:"airdropName"` + airdropParentID string `json:"airdropParentID"` + airdropXPos string `json:"airdropXPos"` + airdropYPos string `json:"airdropYPos"` +} + +type compositeNFTMetaData struct { + tokenID string `json:"tokenID"` + name string `json:"name"` + version string `json:"version"` + canvasWidth string `json:canvasWidth"` + canvasHeight string `json:canvasHeight"` + bTokenIDs []int64 `json:"bTokenIDs"` +} + +type listingCompositeResult struct { + compositeTokenID string `json:"tokenID"` + tokenURI string `json:"tokenURI"` + seller string `json:"seller"` + price string `json:price"` +} + +type listingBasicResult struct { + basicTokenID string `json:"tokenID"` + tokenURI string `json:"tokenURI"` + seller string `json:"seller"` + price string `json:price"` +} + +type marketplaceListings struct { + marketplaceListings []string `json:"marketplaceListings"` +} + +type nftResult struct { + result string `json:"result"` + nftError string `json:"-"` +} + +type buyNFTResult struct { + flipPaid string `json:"flipPaid"` + flipBurned string `json:"flipBurned"` + buyerror string `json:"error"` +} + +type userNFTs struct { + tokenIDs []int64 `json:"tokenIDs"` + nftError string `json:"-"` +} + +type userNFTsResult struct { + UserNFTs []string `json:"userNFTs"` +} + +type userFLIPBalances struct { + lockedBalance string `json:"lockedBalance"` + availableBalance string `json:"availableBalance"` +} + +type inTransit struct { + tokenId int + inTransit bool +} + + +func (g Game) MarshalJSON() ([]byte, error) { + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"id":"`) + b.WriteString(g.ID) + b.WriteString(`",`) + + b.WriteString(`"gameBoard":[`) + b.WriteString(writeIntSlice(g.GameBoard)) + b.WriteString(`],`) + + b.WriteString(`"solvedGameBoard":[`) + b.WriteString(writeIntSlice(g.SolvedGameBoard)) + b.WriteString(`],`) + + b.WriteString(`"gameTiles":[`) + b.WriteString(writeIntSlice(g.GameTiles)) + b.WriteString(`],`) + + b.WriteString(`"gameStatus":"`) + b.WriteString(g.GameStatus) + b.WriteString(`",`) + + b.WriteString(`"tileType":"`) + b.WriteString(g.TileType) + b.WriteString(`"`) + + b.WriteByte('}') + + return b.Bytes(), nil +} + +func (gb GameBoard) MarshalJSON() ([]byte, error) { + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"BoardSize":`) + b.WriteString(strconv.Itoa(gb.BoardSize)) // converting int to string + b.WriteString(`,`) + + + b.WriteString(`"Board":[`) + b.WriteString(writeIntSlice(gb.Board)) + b.WriteString(`],`) + + b.WriteString(`"GameTiles":[`) + b.WriteString(writeIntSlice(gb.GameTiles)) + b.WriteString(`]`) + + b.WriteByte('}') + + return b.Bytes(), nil +} + +func (ugr UserGamesResult) MarshalJSON() ([]byte, error) { + var b bytes.Buffer + + b.WriteByte('{') + b.WriteString(`"userGames":[`) + for i, game := range ugr.UserGames { + if i > 0 { + b.WriteByte(',') + } + gameJSON, err := game.MarshalJSON() + if err != nil { + return nil, err + } + b.Write(gameJSON) + } + b.WriteString(`]`) + b.WriteByte('}') + + return b.Bytes(), nil +} + +func (fbn BasicNFTMetaData) MarshalJSON() ([]byte, error) { + + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"tokenID":"`) + b.WriteString(fbn.tokenID) + b.WriteString(`",`) + + b.WriteString(`"name":"`) + b.WriteString(fbn.name) + b.WriteString(`",`) + + b.WriteString(`"version":"`) + b.WriteString(fbn.version) + b.WriteString(`",`) + + b.WriteString(`"gameId":"`) + b.WriteString(fbn.gameId) + b.WriteString(`",`) + + b.WriteString(`"gameType":"`) + b.WriteString(fbn.gameType) + b.WriteString(`",`) + + b.WriteString(`"gameLevel":"`) + b.WriteString(fbn.gameLevel) + b.WriteString(`",`) + + b.WriteString(`"svgData":"`) + b.WriteString(fbn.svgData) + b.WriteString(`",`) + + b.WriteString(`"airdropName":"`) + b.WriteString(fbn.airdropName) + b.WriteString(`",`) + + b.WriteString(`"airdropParentID":"`) + b.WriteString(fbn.airdropParentID) + b.WriteString(`",`) + + b.WriteString(`"airdropXPos":"`) + b.WriteString(fbn.airdropXPos) + b.WriteString(`",`) + + b.WriteString(`"airdropYPos":"`) + b.WriteString(fbn.airdropYPos) + b.WriteString(`"`) + + b.WriteByte('}') + + return b.Bytes(), nil + +} + +func (cbn compositeNFTMetaData) MarshalJSON() ([]byte, error) { + + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"tokenID":"`) + b.WriteString(cbn.tokenID) + b.WriteString(`",`) + + b.WriteString(`"name":"`) + b.WriteString(cbn.name) + b.WriteString(`",`) + + b.WriteString(`"version":"`) + b.WriteString(cbn.version) + b.WriteString(`",`) + + b.WriteString(`"canvasWidth":"`) + b.WriteString(cbn.canvasWidth) + b.WriteString(`",`) + + b.WriteString(`"canvasHeight":"`) + b.WriteString(cbn.canvasHeight) + b.WriteString(`",`) + + b.WriteString(`"bTokenIDs":[`) + b.WriteString(writeIntSlice(cbn.bTokenIDs)) + b.WriteString(`]`) + + b.WriteByte('}') + + return b.Bytes(), nil + +} + +func (lrc listingCompositeResult)MarshalJSON() ([]byte, error){ + + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"tokenID":"`) + b.WriteString(lrc.compositeTokenID) + b.WriteString(`",`) + + // tokenURI is already a string + b.WriteString(`"tokenURI":`) + b.WriteString(lrc.tokenURI) + b.WriteString(`,`) + + b.WriteString(`"seller":"`) + b.WriteString(lrc.seller) + b.WriteString(`",`) + + b.WriteString(`"price":"`) + b.WriteString(lrc.price) + b.WriteString(`"`) + + b.WriteByte('}') + + return b.Bytes(), nil +} + +func (lrb listingBasicResult)MarshalJSON() ([]byte, error){ + + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"tokenID":"`) + b.WriteString(lrb.basicTokenID) + b.WriteString(`",`) + + // tokenURI is already a string + b.WriteString(`"tokenURI":`) + b.WriteString(lrb.tokenURI) + b.WriteString(`,`) + + b.WriteString(`"seller":"`) + b.WriteString(lrb.seller) + b.WriteString(`",`) + + b.WriteString(`"price":"`) + b.WriteString(lrb.price) + b.WriteString(`"`) + + b.WriteByte('}') + + return b.Bytes(), nil +} + +func (ml marketplaceListings) MarshalJSON() ([]byte, error) { + var b bytes.Buffer + + b.WriteString(`{"marketplaceListings":[`) + for i, listing := range ml.marketplaceListings { + if i > 0 { + b.WriteString(`,`) + } + b.WriteString(listing) + } + b.WriteString(`]}`) + + return b.Bytes(), nil +} + +func (n nftResult)MarshalJSON() ([]byte, error) { + + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"result":`) + b.WriteString(n.result) + //b.WriteString(`"`) + + b.WriteByte('}') + + return b.Bytes(), nil + +} + +func (bn buyNFTResult)MarshalJSON() ([]byte, error){ + + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"flipPaid":"`) + b.WriteString(bn.flipPaid) + b.WriteString(`",`) + + b.WriteString(`"flipBurned":"`) + b.WriteString(bn.flipBurned) + b.WriteString(`",`) + + b.WriteString(`"error":"`) + b.WriteString(bn.buyerror) + b.WriteString(`"`) + + b.WriteByte('}') + + return b.Bytes(), nil +} + +func (t userNFTs)MarshalJSON() ([]byte, error) { + + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"tokenIDs":[`) + b.WriteString(writeIntSlice(t.tokenIDs)) + b.WriteString(`],`) + + b.WriteString(`"error":"`) + b.WriteString(t.nftError) + b.WriteString(`"`) + + b.WriteByte('}') + + return b.Bytes(), nil + +} + +func (u userFLIPBalances)MarshalJSON() ([]byte, error) { + + var b bytes.Buffer + + b.WriteByte('{') + + b.WriteString(`"lockedBalance":"`) + b.WriteString(u.lockedBalance) + b.WriteString(`",`) + + b.WriteString(`"availableBalance":"`) + b.WriteString(u.availableBalance) + b.WriteString(`"`) + + b.WriteByte('}') + + return b.Bytes(), nil + +} + +func (r userNFTsResult) MarshalJSON() ([]byte, error) { + var b bytes.Buffer + + b.WriteString(`{"userNFTs":[`) + for i, nft := range r.UserNFTs { + if i > 0 { + b.WriteString(`,`) + } + b.WriteString(nft) + } + b.WriteString(`]}`) + + return b.Bytes(), nil +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/flippando/token.gno b/examples/gno.land/r/demo/flippando/token.gno new file mode 100644 index 00000000000..f9ab7d7fff2 --- /dev/null +++ b/examples/gno.land/r/demo/flippando/token.gno @@ -0,0 +1,282 @@ +package flippando + +import ( + "errors" + "std" + "strconv" + "time" + + "gno.land/p/demo/avl" + "gno.land/p/demo/flippandoserver" + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/ufmt" +) + +type lockedVault struct { + tokenId string + lockedFlip std.Coin +} + +var ( + flipToken = grc20.NewBanker("Flippando", "FLIP", 12) + // 1000 uFLIP = 1 FLIP + // max denom 1,000,000,000 FLIP + totalLockedSupply std.Coin = std.NewCoin("FLIP", 0) + // hardcoding the airdrop account and restricting minting to it + airdropAccount std.Address = std.Address("g1mphljw4duhzwqs72hv9grm4k6ufkvts3g7t3t4") + userFlipNFTs avl.Tree // onwer -> avl.Tree // []*lockedVault +) + +// overrides the Mint function in the interface, restricts only to airdropAccount calls +func Mint(recipient std.Address, flipAmount std.Coin) error { + if airdropAccount.String() != std.GetOrigCaller().String() { + return errors.New("invalid account calling Mint") + } + + if airdropAccount.String() != recipient.String() { + return errors.New("invalid recipient for Mint") + } + + if err := flipToken.Mint(recipient, uint64(flipAmount.Amount)); err != nil { + return errors.New(ufmt.Sprintf("Error minting FLIP to airdrop account: %s", err.Error())) + } + return nil +} + +// mint tokens and locks them, making them unavaialble for spending +func MintAndLockFLIP(recipient std.Address, tokenId string, flipAmount std.Coin) error { + if err := flipToken.Mint(recipient, uint64(flipAmount.Amount)); err != nil { + return err + } + + var userLockedBalances []*lockedVault + + v, exists := userFlipNFTs.Get(recipient.String()) + if exists { + // Assert the type of v to []*lockedVault + var ok bool + userLockedBalances, ok = v.([]*lockedVault) + if !ok { + return errors.New("invalid type for user locked balances") + } + } + + lockingBalance := &lockedVault{ + tokenId: tokenId, + lockedFlip: flipAmount, + } + + userLockedBalances = append([]*lockedVault{lockingBalance}, userLockedBalances...) + userFlipNFTs.Set(recipient.String(), userLockedBalances) + + totalLockedSupply = totalLockedSupply.Add(flipAmount) + + return nil +} + +// unlocks the balance, making it avaialble for spending for recipient +// no actual transfer is performed +func ReleaseLockedFLIP(recipient std.Address, tokenId string) error { + var userLockedBalances []*lockedVault + var flipAmount std.Coin + tokenFound := false + + v, found := userFlipNFTs.Get(recipient.String()) + if found { + // Assert the type of v to []*lockedVault + var ok bool + userLockedBalances, ok = v.([]*lockedVault) + if !ok { + return errors.New("invalid type for user locked balances") + } + + // Create a new slice for storing balances without the unlocked token + var newLockedBalances []*lockedVault + for _, lv := range userLockedBalances { + if lv.tokenId == tokenId { + // Record the amount and indicate the token was found + flipAmount = lv.lockedFlip + tokenFound = true + } else { + // Add to the new slice if it's not the token to unlock + newLockedBalances = append(newLockedBalances, lv) + } + } + + // Use the new slice if the token was found and removed + if tokenFound { + userLockedBalances = newLockedBalances + } + } + + if !tokenFound { + return ErrInvalidTokenId // Ensure this error is defined + } + + // Update the user's locked balances in userFlipNFTs + userFlipNFTs.Set(recipient.String(), userLockedBalances) + + // Update the total locked supply + totalLockedSupply = totalLockedSupply.Sub(flipAmount) + + return nil +} + +// transfers fungible tokens, taking into account the locked balances +// i.e. only avaialble tokens can be spent +func Transfer(from, recipient std.Address, fAmount std.Coin) error { + totalFLIPBalance := flipToken.BalanceOf(from) + + lockedFLIPBalance := getUserLockedBalances(from) + + if int64(totalFLIPBalance) >= fAmount.Amount && int64(totalFLIPBalance)-int64(lockedFLIPBalance.Amount) >= fAmount.Amount { + if err := flipToken.Transfer(from, recipient, uint64(fAmount.Amount)); err != nil { + return err + } + } else { + return errors.New("not enough available balance") + } + + return nil +} + +// pays the FLIP price in a marketplace transaction +// burning a percentage between 1% anf 50% +func PayFLIPToSeller(from, recipient std.Address, fPrice std.Coin) (flipPaid string, flipBurned string, err error) { + flipToken.Approve(from, std.CurrentRealm().Addr(), uint64(fPrice.Amount)) + totalFLIPBalance := flipToken.BalanceOf(from) + + lockedFLIPBalance := getUserLockedBalances(from) + + if int64(totalFLIPBalance) >= fPrice.Amount && int64(totalFLIPBalance)-lockedFLIPBalance.Amount >= fPrice.Amount { + randomPercentage := flippandoserver.GenerateRandomNumbers(2, 1, 50, time.Now().Unix()) + randomBurnAmount := fPrice.Amount * int64(randomPercentage[0]) / 100 + fPaidPrice := fPrice.Amount - randomBurnAmount + flipToBurn := fPrice.Amount - fPaidPrice + + if err := flipToken.Transfer(from, recipient, uint64(fPaidPrice)); err != nil { + return "", "", err + } + if err := flipToken.Burn(from, uint64(flipToBurn)); err != nil { + return "", "", err + } + + return strconv.FormatInt(fPaidPrice, 10), strconv.FormatInt(flipToBurn, 10), nil + } else { + return "", "", ErrFlipTokenNotEnoughBalance + } +} + +// transfers the locked tokens to a new recipient (toBuyer) +// used when a basic NFT is sold in the marketplace +func TransferLockedFLIP(fromSeller, toBuyer std.Address, tokenId string) error { + var sellerLockedBalances []*lockedVault + var flipAmount std.Coin + tokenFound := false + + // Step 1: Unlock the tokens associated with the tokenId for the seller + v, found := userFlipNFTs.Get(fromSeller.String()) + if found { + // Assert the type of v to []*lockedVault + var ok bool + sellerLockedBalances, ok = v.([]*lockedVault) + if !ok { + return errors.New("invalid type for user locked balances") + } + + // Create a new slice for storing balances without the unlocked token + var newLockedBalances []*lockedVault + for _, lv := range sellerLockedBalances { + if lv.tokenId == tokenId { + // Record the amount and indicate the token was found + flipAmount = lv.lockedFlip + tokenFound = true + } else { + // Add to the new slice if it's not the token to unlock + newLockedBalances = append(newLockedBalances, lv) + } + } + + // Use the new slice if the token was found and removed + if tokenFound { + sellerLockedBalances = newLockedBalances + } + } + + if !tokenFound { + return ErrInvalidTokenId // Ensure this error is defined + } + + // Update the seller's locked balances in userFlipNFTs + userFlipNFTs.Set(fromSeller.String(), sellerLockedBalances) + + // Update the total locked supply + totalLockedSupply = totalLockedSupply.Sub(flipAmount) + + // Step 2: Transfer the unlocked tokens to the buyer + if err := flipToken.Transfer(fromSeller, toBuyer, uint64(flipAmount.Amount)); err != nil { + return err + } + + // Step 3: Lock the received tokens in the buyer's userFlipNFTs + var buyerLockedBalances []*lockedVault + + v, exists := userFlipNFTs.Get(toBuyer.String()) + if exists { + // Assert the type of v to []*lockedVault + var ok bool + buyerLockedBalances, ok = v.([]*lockedVault) + if !ok { + return errors.New("invalid type for user locked balances") + } + } + + lockingBalance := &lockedVault{ + tokenId: tokenId, + lockedFlip: flipAmount, + } + + buyerLockedBalances = append([]*lockedVault{lockingBalance}, buyerLockedBalances...) + userFlipNFTs.Set(toBuyer.String(), buyerLockedBalances) + + totalLockedSupply = totalLockedSupply.Add(flipAmount) + + return nil +} + +func GetFLIPBalance(user std.Address) string { + totalFLIPBalance := flipToken.BalanceOf(user) + + lockedFLIPBalance := getUserLockedBalances(user) + availableFLIPBalance := totalFLIPBalance - uint64(lockedFLIPBalance.Amount) + + userBalances := &userFLIPBalances{ + lockedBalance: lockedFLIPBalance.String(), + availableBalance: strconv.FormatUint(availableFLIPBalance, 10), + } + + userBalancesJSON, err := userBalances.MarshalJSON() + if err != nil { + panic("error in marshalling user FLIP balances") + } + + return string(userBalancesJSON) +} + +func getUserLockedBalances(user std.Address) std.Coin { + lockedFLIPBalance := std.NewCoin("FLIP", 0) + + v, exists := userFlipNFTs.Get(user.String()) + if exists { + userLockedBalances, ok := v.([]*lockedVault) + if !ok { + return lockedFLIPBalance + } + + for _, lv := range userLockedBalances { + lockedFLIPBalance = lockedFLIPBalance.Add(lv.lockedFlip) + } + } + + return lockedFLIPBalance +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/flippando/utils.gno b/examples/gno.land/r/demo/flippando/utils.gno new file mode 100644 index 00000000000..48743035052 --- /dev/null +++ b/examples/gno.land/r/demo/flippando/utils.gno @@ -0,0 +1,69 @@ +package flippando + +import ( + "strconv" + "strings" +) + +// used in marshaling structs with arrays +func writeIntSlice(slice []int64) string { + var b strings.Builder + for i, v := range slice { + if i > 0 { + b.WriteString(",") + } + b.WriteString(strconv.FormatInt(v, 10)) // converting int64 to string + } + return b.String() +} + + +// used in parsing params sent as JSON.stringified arrays of ints +func ParseString(s string) ([]int64, error) { + s = strings.Trim(s, "[]") + parts := strings.Split(s, ",") + ints := make([]int64, len(parts)) + for i, part := range parts { + val, err := strconv.Atoi(strings.TrimSpace(part)) + if err != nil { + return nil, err + } + ints[i] = int64(val) + } + return ints, nil +} + +func zeroPad9(s string) string { + n := 9 - len(s) + if n < 0 { + return s + } + return zeroes[:n] + s +} + +func sqrt(x float64) float64 { + if x == 0 || x == 1 { + return x + } + + // Start with an initial guess + guess := x / 2.0 + prevGuess := 0.0 + + // Use a small threshold to determine when to stop the approximation + const threshold = 0.00001 + + for abs(guess-prevGuess) > threshold { + prevGuess = guess + guess = 0.5 * (guess + x/guess) + } + + return guess +} + +func abs(x float64) float64 { + if x < 0 { + return -x + } + return x +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/games/shifumi/gno.mod b/examples/gno.land/r/demo/games/shifumi/gno.mod deleted file mode 100644 index 7a4fc173d3d..00000000000 --- a/examples/gno.land/r/demo/games/shifumi/gno.mod +++ /dev/null @@ -1,7 +0,0 @@ -module gno.land/r/demo/games/shifumi - -require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/seqid v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest -) diff --git a/examples/gno.land/r/demo/games/shifumi/shifumi.gno b/examples/gno.land/r/demo/games/shifumi/shifumi.gno deleted file mode 100644 index 9094cb8fd69..00000000000 --- a/examples/gno.land/r/demo/games/shifumi/shifumi.gno +++ /dev/null @@ -1,120 +0,0 @@ -package shifumi - -import ( - "errors" - "std" - "strconv" - - "gno.land/p/demo/avl" - "gno.land/p/demo/seqid" - - "gno.land/r/demo/users" -) - -const ( - empty = iota - rock - paper - scissors - last -) - -type game struct { - player1, player2 std.Address // shifumi is a 2 players game - move1, move2 int // can be empty, rock, paper, or scissors -} - -var games avl.Tree -var id seqid.ID - -func (g *game) play(player std.Address, move int) error { - if !(move > empty && move < last) { - return errors.New("invalid move") - } - if player != g.player1 && player != g.player2 { - return errors.New("invalid player") - } - if player == g.player1 && g.move1 == empty { - g.move1 = move - return nil - } - if player == g.player2 && g.move2 == empty { - g.move2 = move - return nil - } - return errors.New("already played") -} - -func (g *game) winner() int { - if g.move1 == empty || g.move2 == empty { - return -1 - } - if g.move1 == g.move2 { - return 0 - } - if g.move1 == rock && g.move2 == scissors || - g.move1 == paper && g.move2 == rock || - g.move1 == scissors && g.move2 == paper { - return 1 - } - return 2 -} - -// NewGame creates a new game where player1 is the caller and player2 the argument. -// A new game index is returned. -func NewGame(player std.Address) int { - games.Set(id.Next().String(), &game{player1: std.PrevRealm().Addr(), player2: player}) - return int(id) -} - -// Play executes a move for the game at index idx, where move can be: -// 1 (rock), 2 (paper), 3 (scissors). -func Play(idx, move int) { - v, ok := games.Get(seqid.ID(idx).String()) - if !ok { - panic("game not found") - } - if err := v.(*game).play(std.PrevRealm().Addr(), move); err != nil { - panic(err) - } -} - -func Render(path string) string { - mov1 := []string{"", " 🤜 ", " 🫱 ", " 👉 "} - mov2 := []string{"", " 🤛 ", " 🫲 ", " 👈 "} - win := []string{"pending", "draw", "player1", "player2"} - - output := `# 👊 ✋ ✌️ Shifumi -Actions: -* [NewGame](shifumi?help&__func=NewGame) opponentAddress -* [Play](shifumi?help&__func=Play) gameIndex move (1=rock, 2=paper, 3=scissors) - - game | player1 | | player2 | | win - --- | --- | --- | --- | --- | --- -` - // Output the 100 most recent games. - maxGames := 100 - for n := int(id); n > 0 && int(id)-n < maxGames; n-- { - v, ok := games.Get(seqid.ID(n).String()) - if !ok { - continue - } - g := v.(*game) - output += strconv.Itoa(n) + " | " + - shortName(g.player1) + " | " + mov1[g.move1] + " | " + - shortName(g.player2) + " | " + mov2[g.move2] + " | " + - win[g.winner()+1] + "\n" - } - return output -} - -func shortName(addr std.Address) string { - user := users.GetUserByAddress(addr) - if user != nil { - return user.Name - } - if len(addr) < 10 { - return string(addr) - } - return string(addr)[:10] + "..." -} diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 1318e19eaf3..cc7d80e016d 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -1,11 +1,11 @@ package profile import ( + "errors" "std" "gno.land/p/demo/avl" "gno.land/p/demo/mux" - "gno.land/p/demo/ufmt" ) var ( @@ -13,7 +13,6 @@ var ( router = mux.NewRouter() ) -// Standard fields const ( DisplayName = "DisplayName" Homepage = "Homepage" @@ -26,28 +25,13 @@ const ( InvalidField = "InvalidField" ) -// Events -const ( - ProfileFieldCreated = "ProfileFieldCreated" - ProfileFieldUpdated = "ProfileFieldUpdated" -) - -// Field types used when emitting event -const FieldType = "FieldType" - -const ( - BoolField = "BoolField" - StringField = "StringField" - IntField = "IntField" -) - func init() { router.HandleFunc("", homeHandler) router.HandleFunc("u/{addr}", profileHandler) router.HandleFunc("f/{addr}/{field}", fieldHandler) } -// List of supported string fields +// list of supported string fields var stringFields = map[string]bool{ DisplayName: true, Homepage: true, @@ -57,61 +41,54 @@ var stringFields = map[string]bool{ GravatarEmail: true, } -// List of support int fields +// list of support int fields var intFields = map[string]bool{ Age: true, } -// List of support bool fields +// list of support bool fields var boolFields = map[string]bool{ AvailableForHiring: true, } // Setters -func SetStringField(field, value string) bool { +func SetStringField(field, value string) error { addr := std.PrevRealm().Addr() - key := addr.String() + ":" + field - updated := fields.Set(key, value) - - event := ProfileFieldCreated - if updated { - event = ProfileFieldUpdated + if _, ok := stringFields[field]; !ok { + return errors.New("invalid string field") } - std.Emit(event, FieldType, StringField, field, value) + key := addr.String() + ":" + field + fields.Set(key, value) - return updated + return nil } -func SetIntField(field string, value int) bool { +func SetIntField(field string, value int) error { addr := std.PrevRealm().Addr() - key := addr.String() + ":" + field - updated := fields.Set(key, value) - event := ProfileFieldCreated - if updated { - event = ProfileFieldUpdated + if _, ok := intFields[field]; !ok { + return errors.New("invalid int field") } - std.Emit(event, FieldType, IntField, field, string(value)) + key := addr.String() + ":" + field + fields.Set(key, value) - return updated + return nil } -func SetBoolField(field string, value bool) bool { +func SetBoolField(field string, value bool) error { addr := std.PrevRealm().Addr() - key := addr.String() + ":" + field - updated := fields.Set(key, value) - event := ProfileFieldCreated - if updated { - event = ProfileFieldUpdated + if _, ok := boolFields[field]; !ok { + return errors.New("invalid bool field") } - std.Emit(event, FieldType, BoolField, field, ufmt.Sprintf("%t", value)) + key := addr.String() + ":" + field + fields.Set(key, value) - return updated + return nil } // Getters diff --git a/examples/gno.land/r/demo/profile/profile_test.gno b/examples/gno.land/r/demo/profile/profile_test.gno index 3947897289e..987632a594d 100644 --- a/examples/gno.land/r/demo/profile/profile_test.gno +++ b/examples/gno.land/r/demo/profile/profile_test.gno @@ -27,15 +27,11 @@ func TestStringFields(t *testing.T) { name := GetStringField(alice, DisplayName, "anon") uassert.Equal(t, "anon", name) - // Set new key - updated := SetStringField(DisplayName, "Alice foo") - uassert.Equal(t, updated, false) - updated = SetStringField(Homepage, "https://example.com") - uassert.Equal(t, updated, false) - - // Update the key - updated = SetStringField(DisplayName, "Alice foo") - uassert.Equal(t, updated, true) + // Set + err := SetStringField(DisplayName, "Alice foo") + uassert.NoError(t, err) + err = SetStringField(Homepage, "https://example.com") + uassert.NoError(t, err) // Get after setting name = GetStringField(alice, DisplayName, "anon") @@ -54,13 +50,9 @@ func TestIntFields(t *testing.T) { age := GetIntField(bob, Age, 25) uassert.Equal(t, 25, age) - // Set new key - updated := SetIntField(Age, 30) - uassert.Equal(t, updated, false) - - // Update the key - updated = SetIntField(Age, 30) - uassert.Equal(t, updated, true) + // Set + err := SetIntField(Age, 30) + uassert.NoError(t, err) // Get after setting age = GetIntField(bob, Age, 25) @@ -75,28 +67,45 @@ func TestBoolFields(t *testing.T) { uassert.Equal(t, false, hiring) // Set - updated := SetBoolField(AvailableForHiring, true) - uassert.Equal(t, updated, false) - - // Update the key - updated = SetBoolField(AvailableForHiring, true) - uassert.Equal(t, updated, true) + err := SetBoolField(AvailableForHiring, true) + uassert.NoError(t, err) // Get after setting hiring = GetBoolField(charlie, AvailableForHiring, false) uassert.Equal(t, true, hiring) } +func TestInvalidStringField(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(dave)) + + err := SetStringField(InvalidField, "test") + uassert.Error(t, err) +} + +func TestInvalidIntField(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(eve)) + + err := SetIntField(InvalidField, 123) + uassert.Error(t, err) +} + +func TestInvalidBoolField(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(frank)) + + err := SetBoolField(InvalidField, true) + uassert.Error(t, err) +} + func TestMultipleProfiles(t *testing.T) { // Set profile for user1 std.TestSetRealm(std.NewUserRealm(user1)) - updated := SetStringField(DisplayName, "User One") - uassert.Equal(t, updated, false) + err := SetStringField(DisplayName, "User One") + uassert.NoError(t, err) // Set profile for user2 std.TestSetRealm(std.NewUserRealm(user2)) - updated = SetStringField(DisplayName, "User Two") - uassert.Equal(t, updated, false) + err = SetStringField(DisplayName, "User Two") + uassert.NoError(t, err) // Get profiles std.TestSetRealm(std.NewUserRealm(user1)) // Switch back to user1 @@ -107,36 +116,3 @@ func TestMultipleProfiles(t *testing.T) { uassert.Equal(t, "User One", name1) uassert.Equal(t, "User Two", name2) } - -func TestArbitraryStringField(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(user1)) - - // Set arbitrary string field - updated := SetStringField("MyEmail", "my@email.com") - uassert.Equal(t, updated, false) - - val := GetStringField(user1, "MyEmail", "") - uassert.Equal(t, val, "my@email.com") -} - -func TestArbitraryIntField(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(user1)) - - // Set arbitrary int field - updated := SetIntField("MyIncome", 100_000) - uassert.Equal(t, updated, false) - - val := GetIntField(user1, "MyIncome", 0) - uassert.Equal(t, val, 100_000) -} - -func TestArbitraryBoolField(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(user1)) - - // Set arbitrary int field - updated := SetBoolField("IsWinner", true) - uassert.Equal(t, updated, false) - - val := GetBoolField(user1, "IsWinner", false) - uassert.Equal(t, val, true) -} diff --git a/examples/gno.land/r/demo/users/gno.mod b/examples/gno.land/r/demo/users/gno.mod index 61b11c09b80..a2ee2ea86ba 100644 --- a/examples/gno.land/r/demo/users/gno.mod +++ b/examples/gno.land/r/demo/users/gno.mod @@ -2,6 +2,5 @@ module gno.land/r/demo/users require ( gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/avlhelpers v0.0.0-latest gno.land/p/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/users/users.gno b/examples/gno.land/r/demo/users/users.gno index 4a0b9c1caf7..9b8e93b579b 100644 --- a/examples/gno.land/r/demo/users/users.gno +++ b/examples/gno.land/r/demo/users/users.gno @@ -7,7 +7,6 @@ import ( "strings" "gno.land/p/demo/avl" - "gno.land/p/demo/avlhelpers" "gno.land/p/demo/users" ) @@ -256,12 +255,6 @@ func GetUserByAddressOrName(input users.AddressOrName) *users.User { return GetUserByAddress(std.Address(input)) } -// Get a list of user names starting from the given prefix. Limit the -// number of results to maxResults. (This can be used for a name search tool.) -func ListUsersByPrefix(prefix string, maxResults int) []string { - return avlhelpers.ListByteStringKeysByPrefix(name2User, prefix, maxResults) -} - func Resolve(input users.AddressOrName) std.Address { name, isName := input.GetName() if !isName { diff --git a/examples/gno.land/r/demo/users/z_12_filetest.gno b/examples/gno.land/r/demo/users/z_12_filetest.gno deleted file mode 100644 index 0fb7d27bd34..00000000000 --- a/examples/gno.land/r/demo/users/z_12_filetest.gno +++ /dev/null @@ -1,49 +0,0 @@ -package main - -// SEND: 200000000ugnot - -import ( - "strconv" - - "gno.land/r/demo/users" -) - -func main() { - users.Register("", "alicia", "my profile") - - { - // Normal usage - names := users.ListUsersByPrefix("a", 1) - println("# names: " + strconv.Itoa(len(names))) - println("name: " + names[0]) - } - - { - // Empty prefix: match all - names := users.ListUsersByPrefix("", 1) - println("# names: " + strconv.Itoa(len(names))) - println("name: " + names[0]) - } - - { - // The prefix is before "alicia" - names := users.ListUsersByPrefix("alich", 1) - println("# names: " + strconv.Itoa(len(names))) - } - - { - // The prefix is after the last name - names := users.ListUsersByPrefix("y", 10) - println("# names: " + strconv.Itoa(len(names))) - } - - // More tests are in p/demo/avlhelpers -} - -// Output: -// # names: 1 -// name: alicia -// # names: 1 -// name: alicia -// # names: 0 -// # names: 0 diff --git a/examples/gno.land/r/gnoland/events/administration.gno b/examples/gno.land/r/gnoland/events/administration.gno deleted file mode 100644 index 02914adee69..00000000000 --- a/examples/gno.land/r/gnoland/events/administration.gno +++ /dev/null @@ -1,26 +0,0 @@ -package events - -import ( - "std" - - "gno.land/p/demo/ownable/exts/authorizable" -) - -var ( - su = std.Address("g125em6arxsnj49vx35f0n0z34putv5ty3376fg5") // @leohhhn - auth = authorizable.NewAuthorizableWithAddress(su) -) - -// GetOwner gets the owner of the events realm -func GetOwner() std.Address { - return auth.Owner() -} - -// AddModerator adds a moderator to the events realm -func AddModerator(mod std.Address) { - auth.AssertCallerIsOwner() - - if err := auth.AddToAuthList(mod); err != nil { - panic(err) - } -} diff --git a/examples/gno.land/r/gnoland/events/errors.gno b/examples/gno.land/r/gnoland/events/errors.gno deleted file mode 100644 index fb44d3c9f82..00000000000 --- a/examples/gno.land/r/gnoland/events/errors.gno +++ /dev/null @@ -1,18 +0,0 @@ -package events - -import ( - "errors" - "strconv" -) - -var ( - ErrEmptyName = errors.New("event name cannot be empty") - ErrNoSuchID = errors.New("event with specified ID does not exist") - ErrMinWidgetSize = errors.New("you need to request at least 1 event to render") - ErrMaxWidgetSize = errors.New("maximum number of events in widget is" + strconv.Itoa(MaxWidgetSize)) - ErrDescriptionTooLong = errors.New("event description is too long") - ErrInvalidStartTime = errors.New("invalid start time format") - ErrInvalidEndTime = errors.New("invalid end time format") - ErrEndBeforeStart = errors.New("end time cannot be before start time") - ErrStartEndTimezonemMismatch = errors.New("start and end timezones are not the same") -) diff --git a/examples/gno.land/r/gnoland/events/events.gno b/examples/gno.land/r/gnoland/events/events.gno index 0984edf75a9..9c2708a112e 100644 --- a/examples/gno.land/r/gnoland/events/events.gno +++ b/examples/gno.land/r/gnoland/events/events.gno @@ -1,199 +1,240 @@ -// Package events allows you to upload data about specific IRL/online events -// It includes dynamic support for updating rendering events based on their -// status, ie if they are upcoming, in progress, or in the past. package events import ( - "sort" - "std" - "strings" - "time" - - "gno.land/p/demo/seqid" - "gno.land/p/demo/ufmt" + "gno.land/p/demo/ui" ) -type ( - Event struct { - id string - name string // name of event - description string // short description of event - link string // link to auth corresponding web2 page, ie eventbrite/luma or conference page - location string // location of the event - startTime time.Time // given in RFC3339 - endTime time.Time // end time of the event, given in RFC3339 +// XXX: p/demo/ui API is crappy, we need to make it more idiomatic +// XXX: use an updatable block system to update content from a DAO +// XXX: var blocks avl.Tree + +func Render(_ string) string { + dom := ui.DOM{Prefix: "r/gnoland/events:"} + dom.Title = "Gno.land Core Team Attends Industry Events & Meetups" + dom.Classes = []string{"gno-tmpl-section"} + + // body + dom.Body.Append(introSection()...) + dom.Body.Append(ui.HR{}) + dom.Body.Append(upcomingEvents()...) + dom.Body.Append(ui.HR{}) + dom.Body.Append(pastEvents()...) + + return dom.String() +} + +func introSection() ui.Element { + return ui.Element{ + ui.Paragraph("If you’re interested in building web3 with us, catch up with gno.land in person at one of our industry events. We’re looking to connect with developers and like-minded thinkers who can contribute to the growth of our platform."), } +} - eventsSlice []*Event -) +func upcomingEvents() ui.Element { + return ui.Element{ + ui.H2("Upcoming Events"), + ui.Text(`
+
-var ( - events = make(eventsSlice, 0) // sorted - idCounter seqid.ID -) +### GopherCon EU +- Come Meet Us at our Booth +- Berlin, June 17 - 20, 2024 -const ( - maxDescLength = 100 - EventAdded = "EventAdded" - EventDeleted = "EventDeleted" - EventEdited = "EventEdited" -) +[Learn More](https://gophercon.eu/) +
-// AddEvent adds auth new event -// Start time & end time need to be specified in RFC3339, ie 2024-08-08T12:00:00+02:00 -func AddEvent(name, description, link, location, startTime, endTime string) (string, error) { - auth.AssertOnAuthList() +
- if strings.TrimSpace(name) == "" { - return "", ErrEmptyName - } +### GopherCon US +- Come Meet Us at our Booth +- Chicago, July 7 - 10, 2024 - if len(description) > maxDescLength { - return "", ufmt.Errorf("%s: provided length is %d, maximum is %d", ErrDescriptionTooLong, len(description), maxDescLength) - } +[Learn More](https://www.gophercon.com/) - // Parse times - st, et, err := parseTimes(startTime, endTime) - if err != nil { - return "", err - } +
- id := idCounter.Next().String() - e := &Event{ - id: id, - name: name, - description: description, - link: link, - location: location, - startTime: st, - endTime: et, - } +
- events = append(events, e) - sort.Sort(events) +### Nebular Summit +- Join our workshop +- Brussels, July 12 - 13, 2024 - std.Emit(EventAdded, - "id", - e.id, - ) +[Learn More](https://nebular.builders/) +
- return id, nil -} +
-// DeleteEvent deletes an event with auth given ID -func DeleteEvent(id string) { - auth.AssertOnAuthList() +
+
- e, idx, err := GetEventByID(id) - if err != nil { - panic(err) +
+
`), } +} - events = append(events[:idx], events[idx+1:]...) +func pastEvents() ui.Element { + return ui.Element{ + ui.H2("Past Events"), + ui.Text(`
- std.Emit(EventDeleted, - "id", - e.id, - ) -} +
-// EditEvent edits an event with auth given ID -// It only updates values corresponding to non-empty arguments sent with the call -// Note: if you need to update the start time or end time, you need to provide both every time -func EditEvent(id string, name, description, link, location, startTime, endTime string) { - auth.AssertOnAuthList() +### Gno @ Golang Serbia - e, _, err := GetEventByID(id) - if err != nil { - panic(err) - } +- **Join the meetup** +- Belgrade, May 23, 2024 - // Set only valid values - if strings.TrimSpace(name) != "" { - e.name = name - } +[Learn more](https://gno.land/r/gnoland/blog:p/gnomes-in-serbia) - if strings.TrimSpace(description) != "" { - e.description = description - } +
- if strings.TrimSpace(link) != "" { - e.link = link - } +
- if strings.TrimSpace(location) != "" { - e.location = location - } +### Intro to Gno Tokyo - if strings.TrimSpace(startTime) != "" || strings.TrimSpace(endTime) != "" { - st, et, err := parseTimes(startTime, endTime) - if err != nil { - panic(err) // need to also revert other state changes - } +- **Join the meetup** +- Tokyo, April 11, 2024 - oldStartTime := e.startTime - e.startTime = st - e.endTime = et +[Learn more](https://gno.land/r/gnoland/blog:p/gno-tokyo) - // If sort order was disrupted, sort again - if oldStartTime != e.startTime { - sort.Sort(events) - } - } +
- std.Emit(EventEdited, - "id", - e.id, - ) -} +
-func GetEventByID(id string) (*Event, int, error) { - for i, event := range events { - if event.id == id { - return event, i, nil - } - } +### Go to Gno Seoul - return nil, -1, ErrNoSuchID -} +- **Join the workshop** +- Seoul, March 23, 2024 -// Len returns the length of the slice -func (m eventsSlice) Len() int { - return len(m) -} +[Learn more](https://medium.com/onbloc/go-to-gno-recap-intro-to-the-gno-stack-with-memeland-284a43d7f620) -// Less compares the startTime fields of two elements -// In this case, events will be sorted by largest startTime first (upcoming > past) -func (m eventsSlice) Less(i, j int) bool { - return m[i].startTime.After(m[j].startTime) -} +
-// Swap swaps two elements in the slice -func (m eventsSlice) Swap(i, j int) { - m[i], m[j] = m[j], m[i] -} +
-// parseTimes parses the start and end time for an event and checks for possible errors -func parseTimes(startTime, endTime string) (time.Time, time.Time, error) { - st, err := time.Parse(time.RFC3339, startTime) - if err != nil { - return time.Time{}, time.Time{}, ufmt.Errorf("%s: %s", ErrInvalidStartTime, err.Error()) - } +### GopherCon US - et, err := time.Parse(time.RFC3339, endTime) - if err != nil { - return time.Time{}, time.Time{}, ufmt.Errorf("%s: %s", ErrInvalidEndTime, err.Error()) - } +- **Come Meet Us at our Booth** +- San Diego, September 26 - 29, 2023 - if et.Before(st) { - return time.Time{}, time.Time{}, ErrEndBeforeStart - } +[Learn more](https://www.gophercon.com/) - _, stOffset := st.Zone() - _, etOffset := et.Zone() - if stOffset != etOffset { - return time.Time{}, time.Time{}, ErrStartEndTimezonemMismatch - } +
+ +
+ +### GopherCon EU + +- **Come Meet Us at our Booth** +- Berlin, July 26 - 29, 2023 + +[Learn more](https://gophercon.eu/) + +
+ +
+ +### Nebular Summit Gno.land for Developers - return st, et, nil +- Paris, July 24 - 25, 2023 +- Manfred Touron + +[Learn more](https://www.nebular.builders/) + +
+ +
+ +### EthCC + +- **Come Meet Us at our Booth** +- Paris, July 17 - 20, 2023 +- Manfred Touron + +[Learn more](https://www.ethcc.io/) + +
+ +
+ +### Eth Seoul + +- **The Evolution of Smart Contracts: A Journey into Gno.land** +- Seoul, June 3, 2023 +- Manfred Touron + +[Learn more](https://2023.ethseoul.org/) + +
+
+ +### BUIDL Asia + +- **Proof of Contribution in Gno.land** +- Seoul, June 6, 2023 +- Manfred Touron + +[Learn more](https://www.buidl.asia/) + +
+
+ +### Game Developer Conference + +- **Side Event: Web3 Gaming Apps Powered by Gno** +- San Francisco, Mach 23, 2023 +- Jae Kwon + +[Watch the talk](https://www.youtube.com/watch?v=IJ0xel8lr4c) + +
+
+ +### EthDenver + +- **Side Event: Discover Gno.land** +- Denver, Feb 24 - Mar 5, 2023 +- Jae Kwon + +[Watch the talk](https://www.youtube.com/watch?v=IJ0xel8lr4c) + +
+
+ +### Istanbul Blockchain Week + +- Istanbul, Nov 14 - 17, 2022 +- Manfred Touron + +[Watch the talk](https://www.youtube.com/watch?v=JX0gdWT0Cg4) + +
+
+ +### Web Summit Buckle Up and Build with Cosmos + +- Lisbon, Nov 1 - 4, 2022 +- Manfred Touron + +
+
+ +### Cosmoverse + +- Medallin, Sept 26 - 28, 2022 +- Manfred Touron + +[Watch the talk](https://www.youtube.com/watch?v=6s1zG7hgxMk) + +
+
+ +### Berlin Blockchain Week Buckle Up and Build with Cosmos + +- Berlin, Sept 11 - 18, 2022 + +[Watch the talk](https://www.youtube.com/watch?v=hCLErPgnavI) + +
+
`), + } } diff --git a/examples/gno.land/r/gnoland/events/events_filetest.gno b/examples/gno.land/r/gnoland/events/events_filetest.gno new file mode 100644 index 00000000000..46ee273414d --- /dev/null +++ b/examples/gno.land/r/gnoland/events/events_filetest.gno @@ -0,0 +1,226 @@ +package main + +import "gno.land/r/gnoland/events" + +func main() { + println(events.Render("")) +} + +// Output: +//
+// +// # Gno.land Core Team Attends Industry Events & Meetups +// +// +// If you’re interested in building web3 with us, catch up with gno.land in person at one of our industry events. We’re looking to connect with developers and like-minded thinkers who can contribute to the growth of our platform. +// +// +// --- +// +// ## Upcoming Events +// +//
+//
+// +// ### GopherCon EU +// - Come Meet Us at our Booth +// - Berlin, June 17 - 20, 2024 +// +// [Learn More](https://gophercon.eu/) +//
+// +//
+// +// ### GopherCon US +// - Come Meet Us at our Booth +// - Chicago, July 7 - 10, 2024 +// +// [Learn More](https://www.gophercon.com/) +// +//
+// +//
+// +// ### Nebular Summit +// - Join our workshop +// - Brussels, July 12 - 13, 2024 +// +// [Learn More](https://nebular.builders/) +//
+// +//
+// +//
+//
+// +//
+//
+// +// --- +// +// ## Past Events +// +//
+// +//
+// +// ### Gno @ Golang Serbia +// +// - **Join the meetup** +// - Belgrade, May 23, 2024 +// +// [Learn more](https://gno.land/r/gnoland/blog:p/gnomes-in-serbia) +// +//
+// +//
+// +// ### Intro to Gno Tokyo +// +// - **Join the meetup** +// - Tokyo, April 11, 2024 +// +// [Learn more](https://gno.land/r/gnoland/blog:p/gno-tokyo) +// +//
+// +//
+// +// ### Go to Gno Seoul +// +// - **Join the workshop** +// - Seoul, March 23, 2024 +// +// [Learn more](https://medium.com/onbloc/go-to-gno-recap-intro-to-the-gno-stack-with-memeland-284a43d7f620) +// +//
+// +//
+// +// ### GopherCon US +// +// - **Come Meet Us at our Booth** +// - San Diego, September 26 - 29, 2023 +// +// [Learn more](https://www.gophercon.com/) +// +//
+// +//
+// +// ### GopherCon EU +// +// - **Come Meet Us at our Booth** +// - Berlin, July 26 - 29, 2023 +// +// [Learn more](https://gophercon.eu/) +// +//
+// +//
+// +// ### Nebular Summit Gno.land for Developers +// +// - Paris, July 24 - 25, 2023 +// - Manfred Touron +// +// [Learn more](https://www.nebular.builders/) +// +//
+// +//
+// +// ### EthCC +// +// - **Come Meet Us at our Booth** +// - Paris, July 17 - 20, 2023 +// - Manfred Touron +// +// [Learn more](https://www.ethcc.io/) +// +//
+// +//
+// +// ### Eth Seoul +// +// - **The Evolution of Smart Contracts: A Journey into Gno.land** +// - Seoul, June 3, 2023 +// - Manfred Touron +// +// [Learn more](https://2023.ethseoul.org/) +// +//
+//
+// +// ### BUIDL Asia +// +// - **Proof of Contribution in Gno.land** +// - Seoul, June 6, 2023 +// - Manfred Touron +// +// [Learn more](https://www.buidl.asia/) +// +//
+//
+// +// ### Game Developer Conference +// +// - **Side Event: Web3 Gaming Apps Powered by Gno** +// - San Francisco, Mach 23, 2023 +// - Jae Kwon +// +// [Watch the talk](https://www.youtube.com/watch?v=IJ0xel8lr4c) +// +//
+//
+// +// ### EthDenver +// +// - **Side Event: Discover Gno.land** +// - Denver, Feb 24 - Mar 5, 2023 +// - Jae Kwon +// +// [Watch the talk](https://www.youtube.com/watch?v=IJ0xel8lr4c) +// +//
+//
+// +// ### Istanbul Blockchain Week +// +// - Istanbul, Nov 14 - 17, 2022 +// - Manfred Touron +// +// [Watch the talk](https://www.youtube.com/watch?v=JX0gdWT0Cg4) +// +//
+//
+// +// ### Web Summit Buckle Up and Build with Cosmos +// +// - Lisbon, Nov 1 - 4, 2022 +// - Manfred Touron +// +//
+//
+// +// ### Cosmoverse +// +// - Medallin, Sept 26 - 28, 2022 +// - Manfred Touron +// +// [Watch the talk](https://www.youtube.com/watch?v=6s1zG7hgxMk) +// +//
+//
+// +// ### Berlin Blockchain Week Buckle Up and Build with Cosmos +// +// - Berlin, Sept 11 - 18, 2022 +// +// [Watch the talk](https://www.youtube.com/watch?v=hCLErPgnavI) +// +//
+//
+// +//
diff --git a/examples/gno.land/r/gnoland/events/events_test.gno b/examples/gno.land/r/gnoland/events/events_test.gno deleted file mode 100644 index 357857352d8..00000000000 --- a/examples/gno.land/r/gnoland/events/events_test.gno +++ /dev/null @@ -1,200 +0,0 @@ -package events - -import ( - "std" - "strings" - "testing" - "time" - - "gno.land/p/demo/uassert" - "gno.land/p/demo/urequire" -) - -var ( - suRealm = std.NewUserRealm(su) - - now = "2009-02-13T23:31:30Z" // time.Now() is hardcoded to this value in the gno test machine currently - parsedTimeNow, _ = time.Parse(time.RFC3339, now) -) - -func TestAddEvent(t *testing.T) { - std.TestSetOrigCaller(su) - std.TestSetRealm(suRealm) - - e1Start := parsedTimeNow.Add(time.Hour * 24 * 5) - e1End := e1Start.Add(time.Hour * 4) - - AddEvent("Event 1", "this event is upcoming", "gno.land", "gnome land", e1Start.Format(time.RFC3339), e1End.Format(time.RFC3339)) - - got := renderHome(false) - - if !strings.Contains(got, "Event 1") { - t.Fatalf("Expected to find Event 1 in render") - } - - e2Start := parsedTimeNow.Add(-time.Hour * 24 * 5) - e2End := e2Start.Add(time.Hour * 4) - - AddEvent("Event 2", "this event is in the past", "gno.land", "gnome land", e2Start.Format(time.RFC3339), e2End.Format(time.RFC3339)) - - got = renderHome(false) - - upcomingPos := strings.Index(got, "## Upcoming events") - pastPos := strings.Index(got, "## Past events") - - e1Pos := strings.Index(got, "Event 1") - e2Pos := strings.Index(got, "Event 2") - - // expected index ordering: upcoming < e1 < past < e2 - if e1Pos < upcomingPos || e1Pos > pastPos { - t.Fatalf("Expected to find Event 1 in Upcoming events") - } - - if e2Pos < upcomingPos || e2Pos < pastPos || e2Pos < e1Pos { - t.Fatalf("Expected to find Event 2 on auth different pos") - } - - // larger index => smaller startTime (future => past) - if events[0].startTime.Unix() < events[1].startTime.Unix() { - t.Fatalf("expected ordering to be different") - } -} - -func TestAddEventErrors(t *testing.T) { - std.TestSetOrigCaller(su) - std.TestSetRealm(suRealm) - - _, err := AddEvent("", "sample desc", "gno.land", "gnome land", "2009-02-13T23:31:31Z", "2009-02-13T23:33:31Z") - uassert.ErrorIs(t, err, ErrEmptyName) - - _, err = AddEvent("sample name", "sample desc", "gno.land", "gnome land", "", "2009-02-13T23:33:31Z") - uassert.ErrorContains(t, err, ErrInvalidStartTime.Error()) - - _, err = AddEvent("sample name", "sample desc", "gno.land", "gnome land", "2009-02-13T23:31:31Z", "") - uassert.ErrorContains(t, err, ErrInvalidEndTime.Error()) - - _, err = AddEvent("sample name", "sample desc", "gno.land", "gnome land", "2009-02-13T23:31:31Z", "2009-02-13T23:30:31Z") - uassert.ErrorIs(t, err, ErrEndBeforeStart) - - _, err = AddEvent("sample name", "sample desc", "gno.land", "gnome land", "2009-02-13T23:31:31+06:00", "2009-02-13T23:33:31+02:00") - uassert.ErrorIs(t, err, ErrStartEndTimezonemMismatch) - - tooLongDesc := `Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean ma` - _, err = AddEvent("sample name", tooLongDesc, "gno.land", "gnome land", "2009-02-13T23:31:31Z", "2009-02-13T23:33:31Z") - uassert.ErrorContains(t, err, ErrDescriptionTooLong.Error()) -} - -func TestDeleteEvent(t *testing.T) { - events = nil // remove elements from previous tests - see issue #1982 - - e1Start := parsedTimeNow.Add(time.Hour * 24 * 5) - e1End := e1Start.Add(time.Hour * 4) - - id, _ := AddEvent("ToDelete", "description", "gno.land", "gnome land", e1Start.Format(time.RFC3339), e1End.Format(time.RFC3339)) - - got := renderHome(false) - - if !strings.Contains(got, "ToDelete") { - t.Fatalf("Expected to find ToDelete event in render") - } - - DeleteEvent(id) - got = renderHome(false) - - if strings.Contains(got, "ToDelete") { - t.Fatalf("Did not expect to find ToDelete event in render") - } -} - -func TestEditEvent(t *testing.T) { - events = nil // remove elements from previous tests - see issue #1982 - - e1Start := parsedTimeNow.Add(time.Hour * 24 * 5) - e1End := e1Start.Add(time.Hour * 4) - loc := "gnome land" - - id, _ := AddEvent("ToDelete", "description", "gno.land", loc, e1Start.Format(time.RFC3339), e1End.Format(time.RFC3339)) - - newName := "New Name" - newDesc := "Normal description" - newLink := "new Link" - newST := e1Start.Add(time.Hour) - newET := newST.Add(time.Hour) - - EditEvent(id, newName, newDesc, newLink, "", newST.Format(time.RFC3339), newET.Format(time.RFC3339)) - edited, _, _ := GetEventByID(id) - - // Check updated values - uassert.Equal(t, edited.name, newName) - uassert.Equal(t, edited.description, newDesc) - uassert.Equal(t, edited.link, newLink) - uassert.True(t, edited.startTime.Equal(newST)) - uassert.True(t, edited.endTime.Equal(newET)) - - // Check if the old values are the same - uassert.Equal(t, edited.location, loc) -} - -func TestInvalidEdit(t *testing.T) { - events = nil // remove elements from previous tests - see issue #1982 - - uassert.PanicsWithMessage(t, ErrNoSuchID.Error(), func() { - EditEvent("123123", "", "", "", "", "", "") - }) -} - -func TestParseTimes(t *testing.T) { - // times not provided - // end time before start time - // timezone Missmatch - - _, _, err := parseTimes("", "") - uassert.ErrorContains(t, err, ErrInvalidStartTime.Error()) - - _, _, err = parseTimes(now, "") - uassert.ErrorContains(t, err, ErrInvalidEndTime.Error()) - - _, _, err = parseTimes("2009-02-13T23:30:30Z", "2009-02-13T21:30:30Z") - uassert.ErrorContains(t, err, ErrEndBeforeStart.Error()) - - _, _, err = parseTimes("2009-02-10T23:30:30+02:00", "2009-02-13T21:30:33+05:00") - uassert.ErrorContains(t, err, ErrStartEndTimezonemMismatch.Error()) -} - -func TestRenderEventWidget(t *testing.T) { - events = nil // remove elements from previous tests - see issue #1982 - - // No events yet - out, err := RenderEventWidget(1) - uassert.NoError(t, err) - uassert.Equal(t, out, "No events.") - - // Too many events - out, err = RenderEventWidget(MaxWidgetSize + 1) - uassert.ErrorIs(t, err, ErrMaxWidgetSize) - - // Too little events - out, err = RenderEventWidget(0) - uassert.ErrorIs(t, err, ErrMinWidgetSize) - - // Ordering & if requested amt is larger than the num of events that exist - e1Start := parsedTimeNow.Add(time.Hour * 24 * 5) - e1End := e1Start.Add(time.Hour * 4) - - e2Start := parsedTimeNow.Add(time.Hour * 24 * 10) // event 2 is after event 1 - e2End := e2Start.Add(time.Hour * 4) - - _, err = AddEvent("Event 1", "description", "gno.land", "loc", e1Start.Format(time.RFC3339), e1End.Format(time.RFC3339)) - urequire.NoError(t, err) - - _, err = AddEvent("Event 2", "description", "gno.land", "loc", e2Start.Format(time.RFC3339), e2End.Format(time.RFC3339)) - urequire.NoError(t, err) - - out, err = RenderEventWidget(MaxWidgetSize) - urequire.NoError(t, err) - - uniqueSequence := "- [" // sequence that is displayed once per each event as per the RenderEventWidget function - uassert.Equal(t, 2, strings.Count(out, uniqueSequence)) - - uassert.True(t, strings.Index(out, "Event 1") > strings.Index(out, "Event 2")) -} diff --git a/examples/gno.land/r/gnoland/events/gno.mod b/examples/gno.land/r/gnoland/events/gno.mod index bd3e4652b04..ec781c7cf10 100644 --- a/examples/gno.land/r/gnoland/events/gno.mod +++ b/examples/gno.land/r/gnoland/events/gno.mod @@ -1,9 +1,3 @@ module gno.land/r/gnoland/events -require ( - gno.land/p/demo/ownable/exts/authorizable v0.0.0-latest - gno.land/p/demo/seqid v0.0.0-latest - gno.land/p/demo/uassert v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/p/demo/urequire v0.0.0-latest -) +require gno.land/p/demo/ui v0.0.0-latest diff --git a/examples/gno.land/r/gnoland/events/rendering.gno b/examples/gno.land/r/gnoland/events/rendering.gno deleted file mode 100644 index d98879c68f6..00000000000 --- a/examples/gno.land/r/gnoland/events/rendering.gno +++ /dev/null @@ -1,145 +0,0 @@ -package events - -import ( - "bytes" - "time" - - "gno.land/p/demo/ufmt" -) - -const ( - MaxWidgetSize = 5 -) - -// RenderEventWidget shows up to eventsToRender of the latest events to a caller -func RenderEventWidget(eventsToRender int) (string, error) { - numOfEvents := len(events) - if numOfEvents == 0 { - return "No events.", nil - } - - if eventsToRender > MaxWidgetSize { - return "", ErrMaxWidgetSize - } - - if eventsToRender < 1 { - return "", ErrMinWidgetSize - } - - if eventsToRender > numOfEvents { - eventsToRender = numOfEvents - } - - output := "" - - for _, event := range events[:eventsToRender] { - output += ufmt.Sprintf("- [%s](%s)\n", event.name, event.link) - } - - return output, nil -} - -// renderHome renders the home page of the events realm -func renderHome(admin bool) string { - output := "# gno.land events\n\n" - - if len(events) == 0 { - output += "No upcoming or past events." - return output - } - - output += "Below is a list of all gno.land events, including in progress, upcoming, and past ones.\n\n" - output += "---\n\n" - - var ( - inProgress = "" - upcoming = "" - past = "" - now = time.Now() - ) - - for _, e := range events { - if now.Before(e.startTime) { - upcoming += e.Render(admin) - } else if now.After(e.endTime) { - past += e.Render(admin) - } else { - inProgress += e.Render(admin) - } - } - - if upcoming != "" { - // Add upcoming events - output += "## Upcoming events\n\n" - output += "
" - - output += upcoming - - output += "
\n\n" - output += "---\n\n" - } - - if inProgress != "" { - output += "## Currently in progress\n\n" - output += "
" - - output += inProgress - - output += "
\n\n" - output += "---\n\n" - } - - if past != "" { - // Add past events - output += "## Past events\n\n" - output += "
" - - output += past - - output += "
\n\n" - } - - return output -} - -// Render returns the markdown representation of a single event instance -func (e Event) Render(admin bool) string { - var buf bytes.Buffer - - buf.WriteString("
\n\n") - buf.WriteString(ufmt.Sprintf("### %s\n\n", e.name)) - buf.WriteString(ufmt.Sprintf("%s\n\n", e.description)) - buf.WriteString(ufmt.Sprintf("**Location:** %s\n\n", e.location)) - - _, offset := e.startTime.Zone() // offset is in seconds - hoursOffset := offset / (60 * 60) - sign := "" - if offset >= 0 { - sign = "+" - } - - buf.WriteString(ufmt.Sprintf("**Starts:** %s UTC%s%d\n\n", e.startTime.Format("02 Jan 2006, 03:04 PM"), sign, hoursOffset)) - buf.WriteString(ufmt.Sprintf("**Ends:** %s UTC%s%d\n\n", e.endTime.Format("02 Jan 2006, 03:04 PM"), sign, hoursOffset)) - - if admin { - buf.WriteString(ufmt.Sprintf("[EDIT](/r/gnoland/events?help&__func=EditEvent&id=%s)\n\n", e.id)) - buf.WriteString(ufmt.Sprintf("[DELETE](/r/gnoland/events?help&__func=DeleteEvent&id=%s)\n\n", e.id)) - } - - if e.link != "" { - buf.WriteString(ufmt.Sprintf("[See more](%s)\n\n", e.link)) - } - - buf.WriteString("
") - - return buf.String() -} - -// Render is the main rendering entry point -func Render(path string) string { - if path == "admin" { - return renderHome(true) - } - - return renderHome(false) -} diff --git a/examples/gno.land/r/gnoland/home/gno.mod b/examples/gno.land/r/gnoland/home/gno.mod index c208ad421c9..cb2ec58b665 100644 --- a/examples/gno.land/r/gnoland/home/gno.mod +++ b/examples/gno.land/r/gnoland/home/gno.mod @@ -5,5 +5,4 @@ require ( gno.land/p/demo/ufmt v0.0.0-latest gno.land/p/demo/ui v0.0.0-latest gno.land/r/gnoland/blog v0.0.0-latest - gno.land/r/gnoland/events v0.0.0-latest ) diff --git a/examples/gno.land/r/gnoland/home/home.gno b/examples/gno.land/r/gnoland/home/home.gno index 921492d81b4..62984711d79 100644 --- a/examples/gno.land/r/gnoland/home/home.gno +++ b/examples/gno.land/r/gnoland/home/home.gno @@ -7,7 +7,6 @@ import ( "gno.land/p/demo/ufmt" "gno.land/p/demo/ui" blog "gno.land/r/gnoland/blog" - events "gno.land/r/gnoland/events" ) // XXX: p/demo/ui API is crappy, we need to make it more idiomatic @@ -36,7 +35,7 @@ func Render(_ string) string { dom.Body.Append( ui.Columns{3, []ui.Element{ lastBlogposts(4), - upcomingEvents(), + upcomingEvents(4), lastContributions(4), }}, ) @@ -69,7 +68,7 @@ func Render(_ string) string { func lastBlogposts(limit int) ui.Element { posts := blog.RenderLastPostsWidget(limit) return ui.Element{ - ui.H3("[Latest Blogposts](/r/gnoland/blog)"), + ui.H3("Latest Blogposts"), ui.Text(posts), } } @@ -82,11 +81,11 @@ func lastContributions(limit int) ui.Element { } } -func upcomingEvents() ui.Element { - out, _ := events.RenderEventWidget(events.MaxWidgetSize) +func upcomingEvents(limit int) ui.Element { return ui.Element{ - ui.H3("[Latest Events](/r/gnoland/events)"), - ui.Text(out), + ui.H3("Upcoming Events"), + // TODO: replace with r/gnoland/events + ui.Text("[View upcoming events](/events)"), } } @@ -269,7 +268,7 @@ func discoverLinks() ui.Element { - [Discover demo packages](https://github.com/gnolang/gno/tree/master/examples) - [Gnoscan](https://gnoscan.io) - [Portal Loop](https://docs.gno.land/concepts/portal-loop) -- [Testnet 4](https://test4.gno.land/) (Launched July 2024!) +- Testnet 4 (upcoming) - [Testnet 3](https://test3.gno.land/) (archive) - [Testnet 2](https://test2.gno.land/) (archive) - Testnet Faucet Hub (soon) diff --git a/examples/gno.land/r/gnoland/home/home_filetest.gno b/examples/gno.land/r/gnoland/home/home_filetest.gno index b70b22c80af..2b0a802718f 100644 --- a/examples/gno.land/r/gnoland/home/home_filetest.gno +++ b/examples/gno.land/r/gnoland/home/home_filetest.gno @@ -56,7 +56,7 @@ func main() { // - [Discover demo packages](https://github.com/gnolang/gno/tree/master/examples) // - [Gnoscan](https://gnoscan.io) // - [Portal Loop](https://docs.gno.land/concepts/portal-loop) -// - [Testnet 4](https://test4.gno.land/) (Launched July 2024!) +// - Testnet 4 (upcoming) // - [Testnet 3](https://test3.gno.land/) (archive) // - [Testnet 2](https://test2.gno.land/) (archive) // - Testnet Faucet Hub (soon) @@ -68,15 +68,15 @@ func main() { //
//
// -// ### [Latest Blogposts](/r/gnoland/blog) +// ### Latest Blogposts // // No posts. //
//
// -// ### [Latest Events](/r/gnoland/events) +// ### Upcoming Events // -// No events. +// [View upcoming events](/events) //
//
// diff --git a/examples/gno.land/r/gnoland/home/overide_filetest.gno b/examples/gno.land/r/gnoland/home/overide_filetest.gno index 4f21b90a3c2..34356b93349 100644 --- a/examples/gno.land/r/gnoland/home/overide_filetest.gno +++ b/examples/gno.land/r/gnoland/home/overide_filetest.gno @@ -21,4 +21,4 @@ func main() { // Output: // Hello World! -// r: ownable: caller is not owner +// r: unauthorized; caller is not owner diff --git a/examples/gno.land/r/gnoland/pages/page_contribute.gno b/examples/gno.land/r/gnoland/pages/page_contribute.gno deleted file mode 100644 index 3cdef10d9dc..00000000000 --- a/examples/gno.land/r/gnoland/pages/page_contribute.gno +++ /dev/null @@ -1,106 +0,0 @@ -package gnopages - -func init() { - path := "contribute" - title := "Contributor Ecosystem: Call for Contributions" - body := ` - -gno.land puts at the center of its identity the contributors that help to create and shape the project into what it is; incentivizing those who contribute the most and help advance its vision. Eventually, contributions will be incentivized directly on-chain; in the meantime, this page serves to illustrate our current off-chain initiatives. - -gno.land is still in full-steam development. For now, we're looking for the earliest of adopters; curious to explore a new way to build smart contracts and eager to make an impact. Joining gno.land's development now means you can help to shape the base of its development ecosystem, which will pave the way for the next generation of blockchain programming. - -As an open-source project, we welcome all contributions. On this page you can find some pointers on where to get started; as well as some incentives for the most valuable and important contributions. - -## Where to get started - -If you are interested in contributing to gno.land, you can jump on in on our [GitHub monorepo](https://github.com/gnolang/gno/blob/master/CONTRIBUTING.md) - where most development happens. - -A good place where to start are the issues tagged ["good first issue"](https://github.com/gnolang/gno/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). They should allow you to make some impact on the Gno repository while you're still exploring the details of how everything works. - -## Gno Bounties - -Additionally, you can look out to help on specific issues labeled as bounties. All contributions will then concur to form your profile for Game of Realms. - -The Gno bounty program is a good way to find interesting challenges in Gno, and get rewarded for helping us advance the project. We will maintain open and rewardable bounties in the gnolang/gno repository, and you can search all available bounties by using the ["bounty" label](https://github.com/gnolang/gno/labels/bounty). - -Recommendations on participating in the gno.land Bounty Program: - -- Identify the bounty you want to work on, and join in the discussion on the issue for anything that is unclear; or where you want to more clearly define the work to be done. At this stage, you can also start working on an initial implementation in your local enviornment. -- Once you have spent time on the code related to the bounty, we recommend submitting a 'draft' PR as soon as possible. - - The draft PR doesn't indicate that the bounty has been assigned to you, others are free to work on other draft PRs for the bounty. - - Make sure to reference the bounty issue on the PR description you're writing. - - After submitting the 'draft' PR, continue working until you are ready to mark the PR as "ready for review". - - The core team will review the bounty PR submission after the work on the bounty has been completed, and determine if it qualifies for the bounty reward. -- Ask for clarification early if an element on the requirements or implementation design is unclear. - - Aside from publishing the PR early, keeping regular updates with the core team on the bounty issue is key to being on the right track. - - As part of the requirements, you must adhere to the [contributing guidelines](https://github.com/gnolang/gno/blob/master/CONTRIBUTING.md); additionally, it is expected that any newly added code or functionality is properly documented, tested and covered, at least in 80% of added code. - - You're welcome to propose additional features and work on an issue should you envision a plausible expansion or change in scope. The core team may assign a bounty to the additional work, or change the bounty with respect to the changed scope. - -You may make your submission at any time; however we invite you to publish your draft PR very early in the development process. This will make your work public, so you can easily get help by the core team and other community members. Additionally, your work can be continued by other people should you get stuck or no longer be willing to work on the bounty. Likewise, you can continue the abandoned or stuck work that someone else worked on. - -Don't fear your work being "stolen": if a submission is the result of multiple people's efforts, we will look to split the bounty in a way that is fair and recognises each participant in creating the final outcome. Here are some examples of how that can happen: - -- If Alice does most of the work and abandons it; then Bob comes around and finishes the job, then Bob's PR will be merged. But the core team will propose a split like 70% for Alice and 30% for Bob (depending, of course, on the relative effort undertaken by both). -- If Alice makes a PR that does only 50% of the work outlined in the requirements for the original issue, she will get 50%. Someone can still come up and finish the job; and claim the remaining part. - - If you, for instance, cannot complete the entirety of the task or, as a non-developer, can only contribute a part of the specification/implementation, you may still be awarded a bounty for your input in the contribution. -- If Alice makes a PR that aside from implementing what's required, also undertakes creating useful tools among the way, she may qualify for an "outstanding contribution"; and may be awarded up to 25% more of the original bounty's value. Or she may also ask if the team would be willing to offer a different bounty for the implementation of the tools. - -Participants in the gno.land Bounty Program must meet the legal Terms and Conditions referenced [here](https://docs.google.com/document/d/1aXrZ6japdAykB5FLmHCCeBZTo-2tbZQHSQi79ITaTK0). - -### Bounty sizes - -Each bounty is associated with a size, to which corresponds the maximum compensation for the work involved on the bounty. A bounty size may under rare occasion be revisited to a bigger or smaller size; hence why it's important to talk about your proposed solution with the core team ahead of time. - -In some cases, the work associated with a bounty may be outstanding. When that happens, the core team can decide to award up to 25% of the bounty's value to the recipient. - -The value of the bounty, aside from the material completion of the task, considers the involved time in managing the created pull request and iterating on feedback. - - -t-shirt size | expected compensation --------------|----------------------- -[XS] | $ 500 -[S] | $ 1000 -[M] | $ 2000 -[L] | $ 4000 -[XL] | $ 8000 -_[XXL]_ \* | $ 16000 -_[3XL]_ \* | $ 32000 - -[XS]: https://github.com/gnolang/gno/labels/bounty%2FXS -[S]: https://github.com/gnolang/gno/labels/bounty%2FS -[M]: https://github.com/gnolang/gno/labels/bounty%2FM -[L]: https://github.com/gnolang/gno/labels/bounty%2FL -[XL]: https://github.com/gnolang/gno/labels/bounty%2FXL -[XXL]: https://github.com/gnolang/gno/labels/bounty%2FXXL -[3XL]: https://github.com/gnolang/gno/labels/bounty%2F3XL - -\*: XXL and 3XL bounties are exceptional. Almost no issues will have these sizes; most will be broken down into smaller bounties. - -## gno.land Grants - -The gno.land grants program is to encourage and support the growth of the gno.land contributor community, and build out the usability of the platform and smart contract library. The program provides financial resources to contributors to explore the Gno tech stack, and build dApps, tooling, infrastructure, products, and smart contract libraries in gno.land. - - - -## Join Game of Realms - -Game of Realms is the overarching contributor network of gnomes, currently running off-chain, and will eventually transition on-chain. At this stage, a Game of Realms contribution is comprised of high-impact contributions identified as ['notable contributions'](https://github.com/gnolang/game-of-realms/tree/main/contributors). - -These contributions are not linked to immediate financial rewards, but are notable in nature, in the sense they are a challenge, make a significant addition to the project, and require persistence, with minimal feedback loops from the core team. - -The selection of a notable contribution or the sum of contributions that equal 'notable' is based on the impact it has on the development of the project. For now, it is focused on code contributions, and will evolve over time. The Gno development teams will initially qualify and evaluate notable contributions, and vote off-chain on adding them to the 'notable contributions' folder on GitHub. - -You can always contribute to the project, and all contributions will be noticed. Contributing now is a way to build your personal contributor profile in gno.land early on in the ecosystem, and signal your commitment to the project, the community, and its future. - -There are a variety of ways to make your contributions count: - -- Core code contributions -- Realm and pure package development -- Validator tooling -- Developer tooling -- Tutorials and documentation - -To start, we recommend you create a PR in the Game of Realms [repository](https://github.com/gnolang/game-of-realms) to create your profile page for all your contributions.` - - _ = b.NewPost("", path, title, body, "2024-09-05T00:00:00Z", nil, nil) -} diff --git a/examples/gno.land/r/gnoland/pages/page_ecosystem.gno b/examples/gno.land/r/gnoland/pages/page_ecosystem.gno index c6e7c22ae48..e1a540c98a5 100644 --- a/examples/gno.land/r/gnoland/pages/page_ecosystem.gno +++ b/examples/gno.land/r/gnoland/pages/page_ecosystem.gno @@ -14,14 +14,6 @@ functions in your code using the repo. Visit the playground at [play.gno.land](https://play.gno.land)! -### [Gno Studio Connect](https://gno.studio/connect) - -Gno Studio Connect provides seamless access to realms, making it simple to explore, interact, and engage -with gno.land’s smart contracts through function calls. Connect focuses on function calls, enabling users to interact -with any realm’s exposed function(s) on gno.land. - -See your realm interactions in [Gno Studio Connect](https://gno.studio/connect) - ### [Gnoscan](https://gnoscan.io) Developed by the Onbloc team, Gnoscan is gno.land’s blockchain explorer. Anyone can use Gnoscan to easily find @@ -34,7 +26,7 @@ Explore the gno.land blockchain at [gnoscan.io](https://gnoscan.io)! Adena is a user-friendly non-custodial wallet for gno.land. Open-source and developed by Onbloc, Adena allows gnomes to interact easily with the chain. With an emphasis on UX, Adena is built to handle millions of realms and tokens with a -high-quality interface, support for NFTs and custom tokens, and seamless integration. Install Adena via the [official website](https://www.adena.app/) +high-quality interface, support for NFTs and custom tokens, and seamless integration. ### Gnoswap @@ -46,13 +38,7 @@ automated market maker (AMM) protocol written in Gno that allows for permissionl Flippando is a simple on-chain memory game, ported from Solidity to Gno, which starts with an empty matrix to flip tiles on to see what’s underneath. If the tiles match, they remain uncovered; if not, they are briefly shown, and the player must memorize their colors until the entire matrix is uncovered. The end result can be minted as an NFT, which can later -be assembled into bigger, more complex NFTs, creating a digital “painting” with the uncovered tiles. Play the game at [Flippando](https://gno.flippando.xyz/flip) - -### Gno Native Kit - -[Gno Native Kit](https://github.com/gnolang/gnonative) is a framework that allows developers to build and port gno.land (d)apps written in the (d)app's native language. - - +be assembled into bigger, more complex NFTs, creating a digital “painting” with the uncovered tiles. ` ) _ = b.NewPost("", path, title, body, "2022-05-20T13:17:23Z", nil, nil) diff --git a/examples/gno.land/r/gnoland/pages/page_gor.gno b/examples/gno.land/r/gnoland/pages/page_gor.gno new file mode 100644 index 00000000000..d46e9cb0ccc --- /dev/null +++ b/examples/gno.land/r/gnoland/pages/page_gor.gno @@ -0,0 +1,221 @@ +package gnopages + +func init() { + path := "gor" + title := "Game of Realms - A Contest For The Best Contributors" + // XXX: description := "Game of Realms is the first high-stakes competition held in two phases to find the best contributors to the gno.land platform with a 133,700 ATOM prize pool." + body := ` + +
+ +### Game of Realms + +The first high-stakes contest will see participants compete for tiered membership to co-own the gno.land blockchain. A series of complex technical and non-technical tasks will challenge contributors to create innovative patterns that push the chain to new limits. Start building the foundation for tomorrow through key smart contracts and other contributions that change our understanding of the world. + +
+ +The competition is currently in phase one – for advanced developers only. + +Once the necessary tools to start phase two are ready, we’ll open up the competition to newer devs and non-technical contributors. + +If you want to stack ATOM rewards and play a key role in the success of gno.land and web3, read more about Game of Realms or open a [PR](https://github.com/gnolang/gno/) today. + +
+ +
+
+
+ +## Phase I. (ongoing) + +- + +- + +- + +
+
+ +## Phase II. (Locked) + +
+
+
+ +
+ +
+ +## Evaluation DAO + +This complex challenge seeks your skills in DAO development and implementation and is one of the most important challenges of phase one. The Evaluation DAO will ensure that contributions in Game of Realms and the gno.land platform are fairly rewarded. + +
+ + + + + + + +
+ +Game of Realms participants and core contributors are still in discussions, proposing additional ideas, and seeing how the proposal for the Evaluation DAO evolves over time. + +
+ + + +
+ +See [GitHub issue 519](https://github.com/gnolang/gno/issues/519) for the most up-to-date discussion so far on how voting should work for the DAO, what the responsibilities are, how to join, etc. + +
+ + + + + + + + + + + + + + + + + +
+
+ +
+ +## Tutorials + +To progress to phase two of the competition, we need high-quality tutorials, guides, and documentation from phase one participants. Help to create materials that will onboard more contributors to gno.land. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +## Governance Module + +Can you define and implement a governance contract suite that rivals existing ones, such as the Cosmos Hub? Show us how! We’re looking for the fairest and most efficient governance solution possible. + +
+ + + + + + + +
+ +Game of Realms participants and core contributors have made significant progress teaming up to complete this challenge but discussions and additional ideas are still ongoing. + +
+ + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +## Register Now + + +
+
+ +
+
+ + +
+ +
+ + +
+ + +
+
+
+ +` + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:26Z", nil, nil) +} diff --git a/examples/gno.land/r/gnoland/pages/pages_test.gno b/examples/gno.land/r/gnoland/pages/pages_test.gno index 074e80e1892..c7972686bb3 100644 --- a/examples/gno.land/r/gnoland/pages/pages_test.gno +++ b/examples/gno.land/r/gnoland/pages/pages_test.gno @@ -11,7 +11,7 @@ func TestHome(t *testing.T) { expectedSubtrings := []string{ "/r/gnoland/pages:p/tokenomics", "/r/gnoland/pages:p/start", - "/r/gnoland/pages:p/contribute", + "/r/gnoland/pages:p/gor", "/r/gnoland/pages:p/about", "/r/gnoland/pages:p/gnolang", } diff --git a/examples/gno.land/r/leon/config/config.gno b/examples/gno.land/r/leon/config/config.gno deleted file mode 100644 index cbc1e537e3f..00000000000 --- a/examples/gno.land/r/leon/config/config.gno +++ /dev/null @@ -1,65 +0,0 @@ -package config - -import ( - "errors" - "std" -) - -var ( - main std.Address // leon's main address - backup std.Address // backup address -) - -func init() { - main = "g125em6arxsnj49vx35f0n0z34putv5ty3376fg5" -} - -func Address() std.Address { - return main -} - -func Backup() std.Address { - return backup -} - -func SetAddress(a std.Address) error { - if !a.IsValid() { - return errors.New("config: invalid address") - } - - if err := checkAuthorized(); err != nil { - return err - } - - main = a - return nil -} - -func SetBackup(a std.Address) error { - if !a.IsValid() { - return errors.New("config: invalid address") - } - - if err := checkAuthorized(); err != nil { - return err - } - - backup = a - return nil -} - -func checkAuthorized() error { - caller := std.PrevRealm().Addr() - if caller != main || caller != backup { - return errors.New("config: unauthorized") - } - - return nil -} - -func AssertAuthorized() { - caller := std.PrevRealm().Addr() - if caller != main || caller != backup { - panic("config: unauthorized") - } -} diff --git a/examples/gno.land/r/leon/config/gno.mod b/examples/gno.land/r/leon/config/gno.mod deleted file mode 100644 index e8cd5cd85b7..00000000000 --- a/examples/gno.land/r/leon/config/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/leon/config diff --git a/examples/gno.land/r/leon/home/gno.mod b/examples/gno.land/r/leon/home/gno.mod deleted file mode 100644 index 48cf64a9d0a..00000000000 --- a/examples/gno.land/r/leon/home/gno.mod +++ /dev/null @@ -1,8 +0,0 @@ -module gno.land/r/leon/home - -require ( - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/r/demo/art/gnoface v0.0.0-latest - gno.land/r/demo/art/millipede v0.0.0-latest - gno.land/r/leon/config v0.0.0-latest -) diff --git a/examples/gno.land/r/leon/home/home.gno b/examples/gno.land/r/leon/home/home.gno deleted file mode 100644 index 1f6a07e8959..00000000000 --- a/examples/gno.land/r/leon/home/home.gno +++ /dev/null @@ -1,121 +0,0 @@ -package home - -import ( - "std" - "strconv" - - "gno.land/p/demo/ufmt" - - "gno.land/r/demo/art/gnoface" - "gno.land/r/demo/art/millipede" - "gno.land/r/leon/config" -) - -var ( - pfp string // link to profile picture - pfpCaption string // profile picture caption - abtMe [2]string -) - -func init() { - pfp = "https://i.imgflip.com/91vskx.jpg" - pfpCaption = "[My favourite painting & pfp](https://en.wikipedia.org/wiki/Wanderer_above_the_Sea_of_Fog)" - abtMe = [2]string{ - `### About me -Hi, I'm Leon, a DevRel Engineer at gno.land. I am a tech enthusiast, -life-long learner, and sharer of knowledge.`, - `### Contributions -My contributions to gno.land can mainly be found -[here](https://github.com/gnolang/gno/issues?q=sort:updated-desc+author:leohhhn). - -TODO import r/gh -`, - } -} - -func UpdatePFP(url, caption string) { - config.AssertAuthorized() - pfp = url - pfpCaption = caption -} - -func UpdateAboutMe(col1, col2 string) { - config.AssertAuthorized() - abtMe[0] = col1 - abtMe[1] = col2 -} - -func Render(path string) string { - out := "# Leon's Homepage\n\n" - - out += renderAboutMe() - out += renderBlogPosts() - out += "\n\n" - out += renderArt() - - return out -} - -func renderBlogPosts() string { - out := "" - //out += "## Leon's Blog Posts" - - // todo fetch blog posts authored by @leohhhn - // and render them - return out -} - -func renderAboutMe() string { - out := "
" - - out += "
\n\n" - out += ufmt.Sprintf("![my profile pic](%s)\n\n%s\n\n", pfp, pfpCaption) - out += "
\n\n" - - out += "
\n\n" - out += abtMe[0] + "\n\n" - out += "
\n\n" - - out += "
\n\n" - out += abtMe[1] + "\n\n" - out += "
\n\n" - - out += "
\n\n" - - return out -} - -func renderArt() string { - out := `
` + "\n\n" - out += "# Gno Art\n\n" - - out += "
" - - out += renderGnoFace() - out += renderMillipede() - out += "Empty spot :/" - - out += "
\n\n" - - out += "This art is dynamic; it will change with every new block.\n\n" - out += `
` + "\n" - - return out -} - -func renderGnoFace() string { - out := "
\n\n" - out += gnoface.Render(strconv.Itoa(int(std.GetHeight()))) - out += "
\n\n" - - return out -} - -func renderMillipede() string { - out := "
\n\n" - out += "Millipede\n\n" - out += "```\n" + millipede.Draw(int(std.GetHeight())%10+1) + "```\n" - out += "
\n\n" - - return out -} diff --git a/examples/gno.land/r/morgan/guestbook/admin.gno b/examples/gno.land/r/morgan/guestbook/admin.gno deleted file mode 100644 index fb7f9e1461c..00000000000 --- a/examples/gno.land/r/morgan/guestbook/admin.gno +++ /dev/null @@ -1,25 +0,0 @@ -package guestbook - -import ( - "gno.land/p/demo/ownable" - "gno.land/p/demo/seqid" -) - -var owner = ownable.New() - -// AdminDelete removes the guestbook message with the given ID. -// The user will still be marked as having submitted a message, so they -// won't be able to re-submit a new message. -func AdminDelete(signatureID string) { - owner.AssertCallerIsOwner() - - id, err := seqid.FromString(signatureID) - if err != nil { - panic(err) - } - idb := id.Binary() - if !guestbook.Has(idb) { - panic("signature does not exist") - } - guestbook.Remove(idb) -} diff --git a/examples/gno.land/r/morgan/guestbook/gno.mod b/examples/gno.land/r/morgan/guestbook/gno.mod deleted file mode 100644 index 2591643d33d..00000000000 --- a/examples/gno.land/r/morgan/guestbook/gno.mod +++ /dev/null @@ -1,7 +0,0 @@ -module gno.land/r/morgan/guestbook - -require ( - gno.land/p/demo/avl v0.0.0-latest - gno.land/p/demo/ownable v0.0.0-latest - gno.land/p/demo/seqid v0.0.0-latest -) diff --git a/examples/gno.land/r/morgan/guestbook/guestbook.gno b/examples/gno.land/r/morgan/guestbook/guestbook.gno deleted file mode 100644 index b3a56d88397..00000000000 --- a/examples/gno.land/r/morgan/guestbook/guestbook.gno +++ /dev/null @@ -1,126 +0,0 @@ -// Realm guestbook contains an implementation of a simple guestbook. -// Come and sign yourself up! -package guestbook - -import ( - "std" - "strconv" - "strings" - "time" - "unicode" - - "gno.land/p/demo/avl" - "gno.land/p/demo/seqid" -) - -// Signature is a single entry in the guestbook. -type Signature struct { - Message string - Author std.Address - Time time.Time -} - -const ( - maxMessageLength = 140 - maxPerPage = 25 -) - -var ( - signatureID seqid.ID - guestbook avl.Tree // id -> Signature - hasSigned avl.Tree // address -> struct{} -) - -func init() { - Sign("You reached the end of the guestbook!") -} - -const ( - errNotAUser = "this guestbook can only be signed by users" - errAlreadySigned = "you already signed the guestbook!" - errInvalidCharacterInMessage = "invalid character in message" -) - -// Sign signs the guestbook, with the specified message. -func Sign(message string) { - prev := std.PrevRealm() - switch { - case !prev.IsUser(): - panic(errNotAUser) - case hasSigned.Has(prev.Addr().String()): - panic(errAlreadySigned) - } - message = validateMessage(message) - - guestbook.Set(signatureID.Next().Binary(), Signature{ - Message: message, - Author: prev.Addr(), - // NOTE: time.Now() will yield the "block time", which is deterministic. - Time: time.Now(), - }) - hasSigned.Set(prev.Addr().String(), struct{}{}) -} - -func validateMessage(msg string) string { - if len(msg) > maxMessageLength { - panic("Keep it brief! (max " + strconv.Itoa(maxMessageLength) + " bytes!)") - } - out := "" - for _, ch := range msg { - switch { - case unicode.IsLetter(ch), - unicode.IsNumber(ch), - unicode.IsSpace(ch), - unicode.IsPunct(ch): - out += string(ch) - default: - panic(errInvalidCharacterInMessage) - } - } - return out -} - -func Render(maxID string) string { - var bld strings.Builder - - bld.WriteString("# Guestbook 📝\n\n[Come sign the guestbook!](./guestbook?help&__func=Sign)\n\n---\n\n") - - var maxIDBinary string - if maxID != "" { - mid, err := seqid.FromString(maxID) - if err != nil { - panic(err) - } - - // AVL iteration is exclusive, so we need to decrease the ID value to get the "true" maximum. - mid-- - maxIDBinary = mid.Binary() - } - - var lastID seqid.ID - var printed int - guestbook.ReverseIterate("", maxIDBinary, func(key string, val interface{}) bool { - sig := val.(Signature) - message := strings.ReplaceAll(sig.Message, "\n", "\n> ") - bld.WriteString("> " + message + "\n>\n") - idValue, ok := seqid.FromBinary(key) - if !ok { - panic("invalid seqid id") - } - - bld.WriteString("> _Written by " + sig.Author.String() + " at " + sig.Time.Format(time.DateTime) + "_ (#" + idValue.String() + ")\n\n---\n\n") - lastID = idValue - - printed++ - // stop after exceeding limit - return printed >= maxPerPage - }) - - if printed == 0 { - bld.WriteString("No messages!") - } else if printed >= maxPerPage { - bld.WriteString("

Next page

") - } - - return bld.String() -} diff --git a/examples/gno.land/r/morgan/guestbook/guestbook_test.gno b/examples/gno.land/r/morgan/guestbook/guestbook_test.gno deleted file mode 100644 index b14fee45b42..00000000000 --- a/examples/gno.land/r/morgan/guestbook/guestbook_test.gno +++ /dev/null @@ -1,131 +0,0 @@ -package guestbook - -import ( - "std" - "strings" - "testing" - - "gno.land/p/demo/avl" - "gno.land/p/demo/ownable" -) - -func TestSign(t *testing.T) { - guestbook = avl.Tree{} - hasSigned = avl.Tree{} - - std.TestSetRealm(std.NewUserRealm("g1user")) - Sign("Hello!") - - std.TestSetRealm(std.NewUserRealm("g1user2")) - Sign("Hello2!") - - res := Render("") - t.Log(res) - if !strings.Contains(res, "> Hello!\n>\n> _Written by g1user ") { - t.Error("does not contain first user's message") - } - if !strings.Contains(res, "> Hello2!\n>\n> _Written by g1user2 ") { - t.Error("does not contain second user's message") - } - if guestbook.Size() != 2 { - t.Error("invalid guestbook size") - } -} - -func TestSign_FromRealm(t *testing.T) { - std.TestSetRealm(std.NewCodeRealm("gno.land/r/demo/users")) - - defer func() { - rec := recover() - if rec == nil { - t.Fatal("expected panic") - } - recString, ok := rec.(string) - if !ok { - t.Fatal("not a string", rec) - } else if recString != errNotAUser { - t.Fatal("invalid error", recString) - } - }() - Sign("Hey!") -} - -func TestSign_Double(t *testing.T) { - // Should not allow signing twice. - guestbook = avl.Tree{} - hasSigned = avl.Tree{} - - std.TestSetRealm(std.NewUserRealm("g1user")) - Sign("Hello!") - - defer func() { - rec := recover() - if rec == nil { - t.Fatal("expected panic") - } - recString, ok := rec.(string) - if !ok { - t.Error("type assertion failed", rec) - } else if recString != errAlreadySigned { - t.Error("invalid error message", recString) - } - }() - - Sign("Hello again!") -} - -func TestSign_InvalidMessage(t *testing.T) { - // Should not allow control characters in message. - guestbook = avl.Tree{} - hasSigned = avl.Tree{} - - std.TestSetRealm(std.NewUserRealm("g1user")) - - defer func() { - rec := recover() - if rec == nil { - t.Fatal("expected panic") - } - recString, ok := rec.(string) - if !ok { - t.Error("type assertion failed", rec) - } else if recString != errInvalidCharacterInMessage { - t.Error("invalid error message", recString) - } - }() - Sign("\x00Hello!") -} - -func TestAdminDelete(t *testing.T) { - const ( - userAddr std.Address = "g1user" - adminAddr std.Address = "g1admin" - ) - - guestbook = avl.Tree{} - hasSigned = avl.Tree{} - owner = ownable.NewWithAddress(adminAddr) - signatureID = 0 - - std.TestSetRealm(std.NewUserRealm(userAddr)) - - const bad = "Very Bad Message! Nyeh heh heh!" - Sign(bad) - - if rnd := Render(""); !strings.Contains(rnd, bad) { - t.Fatal("render does not contain bad message", rnd) - } - - std.TestSetRealm(std.NewUserRealm(adminAddr)) - AdminDelete(signatureID.String()) - - if rnd := Render(""); strings.Contains(rnd, bad) { - t.Error("render contains bad message", rnd) - } - if guestbook.Size() != 0 { - t.Error("invalid guestbook size") - } - if hasSigned.Size() != 1 { - t.Error("invalid hasSigned size") - } -} diff --git a/examples/gno.land/r/morgan/home/gno.mod b/examples/gno.land/r/morgan/home/gno.mod deleted file mode 100644 index 573a7e139e7..00000000000 --- a/examples/gno.land/r/morgan/home/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/morgan/home diff --git a/examples/gno.land/r/morgan/home/home.gno b/examples/gno.land/r/morgan/home/home.gno deleted file mode 100644 index 33d7e0b2df7..00000000000 --- a/examples/gno.land/r/morgan/home/home.gno +++ /dev/null @@ -1,10 +0,0 @@ -package home - -const staticHome = `# morgan's (gn)home - -- [📝 sign my guestbook](/r/morgan/guestbook) -` - -func Render(path string) string { - return staticHome -} diff --git a/gno.land/cmd/gnoland/config_get.go b/gno.land/cmd/gnoland/config_get.go index 796ae9da5e9..1fd4027ec60 100644 --- a/gno.land/cmd/gnoland/config_get.go +++ b/gno.land/cmd/gnoland/config_get.go @@ -36,19 +36,6 @@ func newConfigGetCmd(io commands.IO) *commands.Command { }, ) - // Add subcommand helpers - helperGen := metadataHelperGenerator{ - MetaUpdate: func(meta *commands.Metadata, inputType string) { - meta.ShortUsage = fmt.Sprintf("config get %s <%s>", meta.Name, inputType) - }, - TagNameSelector: "json", - TreeDisplay: true, - } - subs := generateSubCommandHelper(helperGen, config.Config{}, func(_ context.Context, args []string) error { - return execConfigGet(cfg, io, args) - }) - - cmd.AddSubCommands(subs...) return cmd } diff --git a/gno.land/cmd/gnoland/config_help.go b/gno.land/cmd/gnoland/config_help.go deleted file mode 100644 index 97d43953bba..00000000000 --- a/gno.land/cmd/gnoland/config_help.go +++ /dev/null @@ -1,127 +0,0 @@ -package main - -import ( - "context" - "fmt" - "reflect" - "strings" - "unicode" - - "github.com/gnolang/gno/tm2/pkg/commands" -) - -type metadataHelperGenerator struct { - // Optional callback to edit metadata - MetaUpdate func(meta *commands.Metadata, inputType string) - // Tag to select for name, if empty will use the field Name - TagNameSelector string - // Will display description with tree representation - TreeDisplay bool -} - -// generateSubCommandHelper generates subcommands based on `s` structure fields and their respective tag descriptions -func generateSubCommandHelper(gen metadataHelperGenerator, s any, exec commands.ExecMethod) []*commands.Command { - rv := reflect.ValueOf(s) - metas := gen.generateFields(rv, "", 0) - - cmds := make([]*commands.Command, len(metas)) - for i := 0; i < len(metas); i++ { - meta := metas[i] - exec := func(ctx context.Context, args []string) error { - args = append([]string{meta.Name}, args...) - return exec(ctx, args) - } - cmds[i] = commands.NewCommand(meta, nil, exec) - } - - return cmds -} - -func (g *metadataHelperGenerator) generateFields(rv reflect.Value, parent string, depth int) []commands.Metadata { - if parent != "" { - parent += "." - } - - // Unwrap pointer if needed - if rv.Kind() == reflect.Ptr { - if rv.IsNil() { - // Create a new non-nil instance of the original type that was nil - rv = reflect.New(rv.Type().Elem()) - } - rv = rv.Elem() // Dereference to struct value - } - - metas := []commands.Metadata{} - if rv.Kind() != reflect.Struct { - return metas - } - - rt := rv.Type() - for i := 0; i < rv.NumField(); i++ { - field := rt.Field(i) - if !field.IsExported() { - continue - } - - fieldValue := rv.Field(i) - name := field.Name - // Get JSON tag name - if g.TagNameSelector != "" { - name, _, _ = strings.Cut(field.Tag.Get(g.TagNameSelector), ",") - if name == "" || name == "-" { - continue - } - } - - // Recursive call for nested struct - var childs []commands.Metadata - if k := fieldValue.Kind(); k == reflect.Ptr || k == reflect.Struct { - childs = g.generateFields(fieldValue, name, depth+1) - } - - // Generate metadata - var meta commands.Metadata - - // Name - meta.Name = parent + name - - // Create a tree-like display to see nested field - if g.TreeDisplay && depth > 0 { - meta.ShortHelp += strings.Repeat(" ", depth*2) - if i == rv.NumField()-1 { - meta.ShortHelp += "└─" - } else { - meta.ShortHelp += "├─" - } - } - meta.ShortHelp += fmt.Sprintf("<%s>", field.Type) - - // Get Short/Long Help Message from comment tag - comment := field.Tag.Get("comment") - comment = strings.TrimFunc(comment, func(r rune) bool { - return unicode.IsSpace(r) || r == '#' - }) - - if comment != "" { - // Use the first line as short help - meta.ShortHelp += " " - meta.ShortHelp += strings.Split(comment, "\n")[0] - - // Display full comment as Long Help - meta.LongHelp = comment - } else { - // If the comment is empty, it mostly means that there is no help. - // Use a blank space to avoid falling back on short help. - meta.LongHelp = " " - } - - if g.MetaUpdate != nil { - g.MetaUpdate(&meta, field.Type.String()) - } - - metas = append(metas, meta) - metas = append(metas, childs...) - } - - return metas -} diff --git a/gno.land/cmd/gnoland/config_set.go b/gno.land/cmd/gnoland/config_set.go index de96aa35c7d..dd171970bf6 100644 --- a/gno.land/cmd/gnoland/config_set.go +++ b/gno.land/cmd/gnoland/config_set.go @@ -34,18 +34,6 @@ func newConfigSetCmd(io commands.IO) *commands.Command { }, ) - // Add subcommand helpers - helperGen := metadataHelperGenerator{ - MetaUpdate: func(meta *commands.Metadata, inputType string) { - meta.ShortUsage = fmt.Sprintf("config set %s <%s>", meta.Name, inputType) - }, - TagNameSelector: "json", - TreeDisplay: true, - } - cmd.AddSubCommands(generateSubCommandHelper(helperGen, config.Config{}, func(_ context.Context, args []string) error { - return execConfigEdit(cfg, io, args) - })...) - return cmd } diff --git a/gno.land/cmd/gnoland/genesis_balances_add.go b/gno.land/cmd/gnoland/genesis_balances_add.go index f9a898715c8..4c8603c1273 100644 --- a/gno.land/cmd/gnoland/genesis_balances_add.go +++ b/gno.land/cmd/gnoland/genesis_balances_add.go @@ -10,7 +10,6 @@ import ( "os" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" @@ -58,13 +57,13 @@ func (c *balancesAddCfg) RegisterFlags(fs *flag.FlagSet) { &c.balanceSheet, "balance-sheet", "", - "the path to the balance file containing addresses in the format
="+ugnot.Denom, + "the path to the balance file containing addresses in the format
=ugnot", ) fs.Var( &c.singleEntries, "single", - "the direct balance addition in the format
="+ugnot.Denom, + "the direct balance addition in the format
=ugnot", ) fs.StringVar( @@ -168,7 +167,7 @@ func execBalancesAdd(ctx context.Context, cfg *balancesAddCfg, io commands.IO) e io.Println() for address, balance := range finalBalances { - io.Printfln("%s:%d%s", address.String(), balance, ugnot.Denom) + io.Printfln("%s:%dugnot", address.String(), balance) } return nil @@ -209,7 +208,7 @@ func getBalancesFromTransactions( } feeAmount := std.NewCoins(tx.Fee.GasFee) - if feeAmount.AmountOf(ugnot.Denom) <= 0 { + if feeAmount.AmountOf("ugnot") <= 0 { io.ErrPrintfln( "invalid gas fee amount encountered: %q", tx.Fee.GasFee.String(), @@ -224,7 +223,7 @@ func getBalancesFromTransactions( msgSend := msg.(bank.MsgSend) sendAmount := msgSend.Amount - if sendAmount.AmountOf(ugnot.Denom) <= 0 { + if sendAmount.AmountOf("ugnot") <= 0 { io.ErrPrintfln( "invalid send amount encountered: %s", msgSend.Amount.String(), @@ -249,7 +248,7 @@ func getBalancesFromTransactions( if from.IsAllLT(sendAmount) || from.IsAllLT(feeAmount) { // Account cannot cover send amount / fee // (see message above) - from = std.NewCoins(std.NewCoin(ugnot.Denom, 0)) + from = std.NewCoins(std.NewCoin("ugnot", 0)) } if from.IsAllGT(sendAmount) { diff --git a/gno.land/cmd/gnoland/genesis_balances_add_test.go b/gno.land/cmd/gnoland/genesis_balances_add_test.go index 8f2879f9c57..9589bf919cc 100644 --- a/gno.land/cmd/gnoland/genesis_balances_add_test.go +++ b/gno.land/cmd/gnoland/genesis_balances_add_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" @@ -101,16 +100,16 @@ func TestGenesis_Balances_Add(t *testing.T) { tempGenesis.Name(), } - amount := std.NewCoins(std.NewCoin(ugnot.Denom, 10)) + amount := std.NewCoins(std.NewCoin("ugnot", 10)) for _, dummyKey := range dummyKeys { args = append(args, "--single") args = append( args, fmt.Sprintf( - "%s=%s", + "%s=%dugnot", dummyKey.Address().String(), - ugnot.ValueString(amount.AmountOf(ugnot.Denom)), + amount.AmountOf("ugnot"), ), ) } @@ -159,7 +158,7 @@ func TestGenesis_Balances_Add(t *testing.T) { require.NoError(t, genesis.SaveAs(tempGenesis.Name())) dummyKeys := getDummyKeys(t, 10) - amount := std.NewCoins(std.NewCoin(ugnot.Denom, 10)) + amount := std.NewCoins(std.NewCoin("ugnot", 10)) balances := make([]string, len(dummyKeys)) @@ -168,9 +167,9 @@ func TestGenesis_Balances_Add(t *testing.T) { for index, key := range dummyKeys { balances[index] = fmt.Sprintf( - "%s=%s", + "%s=%dugnot", key.Address().String(), - ugnot.ValueString(amount.AmountOf(ugnot.Denom)), + amount.AmountOf("ugnot"), ) } @@ -238,9 +237,9 @@ func TestGenesis_Balances_Add(t *testing.T) { var ( dummyKeys = getDummyKeys(t, 10) - amount = std.NewCoins(std.NewCoin(ugnot.Denom, 10)) - amountCoins = std.NewCoins(std.NewCoin(ugnot.Denom, 10)) - gasFee = std.NewCoin(ugnot.Denom, 1000000) + amount = std.NewCoins(std.NewCoin("ugnot", 10)) + amountCoins = std.NewCoins(std.NewCoin("ugnot", 10)) + gasFee = std.NewCoin("ugnot", 1000000) txs = make([]std.Tx, 0) ) @@ -317,7 +316,7 @@ func TestGenesis_Balances_Add(t *testing.T) { if index == 0 { // the first address should // have a balance of 0 - checkAmount = std.NewCoins(std.NewCoin(ugnot.Denom, 0)) + checkAmount = std.NewCoins(std.NewCoin("ugnot", 0)) } if dummyKey.Address().String() == balance.Address.String() { @@ -348,7 +347,7 @@ func TestGenesis_Balances_Add(t *testing.T) { Balances: []gnoland.Balance{ { Address: dummyKeys[0].Address(), - Amount: std.NewCoins(std.NewCoin(ugnot.Denom, 100)), + Amount: std.NewCoins(std.NewCoin("ugnot", 100)), }, }, } @@ -365,16 +364,16 @@ func TestGenesis_Balances_Add(t *testing.T) { tempGenesis.Name(), } - amount := std.NewCoins(std.NewCoin(ugnot.Denom, 10)) + amount := std.NewCoins(std.NewCoin("ugnot", 10)) for _, dummyKey := range dummyKeys { args = append(args, "--single") args = append( args, fmt.Sprintf( - "%s=%s", + "%s=%dugnot", dummyKey.Address().String(), - ugnot.ValueString(amount.AmountOf(ugnot.Denom)), + amount.AmountOf("ugnot"), ), ) } @@ -422,9 +421,9 @@ func TestBalances_GetBalancesFromTransactions(t *testing.T) { var ( dummyKeys = getDummyKeys(t, 10) - amount = std.NewCoins(std.NewCoin(ugnot.Denom, 10)) - amountCoins = std.NewCoins(std.NewCoin(ugnot.Denom, 10)) - gasFee = std.NewCoin(ugnot.Denom, 1000000) + amount = std.NewCoins(std.NewCoin("ugnot", 10)) + amountCoins = std.NewCoins(std.NewCoin("ugnot", 10)) + gasFee = std.NewCoin("ugnot", 1000000) txs = make([]std.Tx, 0) ) @@ -480,7 +479,7 @@ func TestBalances_GetBalancesFromTransactions(t *testing.T) { var ( dummyKeys = getDummyKeys(t, 10) - amountCoins = std.NewCoins(std.NewCoin(ugnot.Denom, 10)) + amountCoins = std.NewCoins(std.NewCoin("ugnot", 10)) gasFee = std.NewCoin("gnos", 1) // invalid fee txs = make([]std.Tx, 0) ) @@ -533,7 +532,7 @@ func TestBalances_GetBalancesFromTransactions(t *testing.T) { var ( dummyKeys = getDummyKeys(t, 10) amountCoins = std.NewCoins(std.NewCoin("gnogno", 10)) // invalid send amount - gasFee = std.NewCoin(ugnot.Denom, 1) + gasFee = std.NewCoin("ugnot", 1) txs = make([]std.Tx, 0) ) diff --git a/gno.land/cmd/gnoland/genesis_balances_export_test.go b/gno.land/cmd/gnoland/genesis_balances_export_test.go index bd1f6152246..ee88af4c56b 100644 --- a/gno.land/cmd/gnoland/genesis_balances_export_test.go +++ b/gno.land/cmd/gnoland/genesis_balances_export_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/testutils" @@ -19,7 +18,7 @@ func getDummyBalances(t *testing.T, count int) []gnoland.Balance { t.Helper() dummyKeys := getDummyKeys(t, count) - amount := std.NewCoins(std.NewCoin(ugnot.Denom, 10)) + amount := std.NewCoins(std.NewCoin("ugnot", 10)) balances := make([]gnoland.Balance, len(dummyKeys)) diff --git a/gno.land/cmd/gnoland/genesis_balances_remove_test.go b/gno.land/cmd/gnoland/genesis_balances_remove_test.go index ed11836ba4d..a8ec6ddac10 100644 --- a/gno.land/cmd/gnoland/genesis_balances_remove_test.go +++ b/gno.land/cmd/gnoland/genesis_balances_remove_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/std" @@ -76,7 +75,7 @@ func TestGenesis_Balances_Remove(t *testing.T) { Balances: []gnoland.Balance{ { Address: dummyKey.Address(), - Amount: std.NewCoins(std.NewCoin(ugnot.Denom, 100)), + Amount: std.NewCoins(std.NewCoin("ugnot", 100)), }, }, } diff --git a/gno.land/cmd/gnoland/genesis_txs_add_packages.go b/gno.land/cmd/gnoland/genesis_txs_add_packages.go index 56d165c070b..93246eadff5 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add_packages.go +++ b/gno.land/cmd/gnoland/genesis_txs_add_packages.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/crypto" @@ -17,7 +16,7 @@ var errInvalidPackageDir = errors.New("invalid package directory") var ( genesisDeployAddress = crypto.MustAddressFromString("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // test1 - genesisDeployFee = std.NewFee(50000, std.MustParseCoin(ugnot.ValueString(1000000))) + genesisDeployFee = std.NewFee(50000, std.MustParseCoin("1000000ugnot")) ) // newTxsAddPackagesCmd creates the genesis txs add packages subcommand diff --git a/gno.land/cmd/gnoland/genesis_txs_add_sheet_test.go b/gno.land/cmd/gnoland/genesis_txs_add_sheet_test.go index a70446cfe6c..1d49422afd1 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add_sheet_test.go +++ b/gno.land/cmd/gnoland/genesis_txs_add_sheet_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" @@ -31,12 +30,12 @@ func generateDummyTxs(t *testing.T, count int) []std.Tx { bank.MsgSend{ FromAddress: crypto.Address{byte(i)}, ToAddress: crypto.Address{byte((i + 1) % count)}, - Amount: std.NewCoins(std.NewCoin(ugnot.Denom, 1)), + Amount: std.NewCoins(std.NewCoin("ugnot", 1)), }, }, Fee: std.Fee{ GasWanted: 1, - GasFee: std.NewCoin(ugnot.Denom, 1000000), + GasFee: std.NewCoin("ugnot", 1000000), }, Memo: fmt.Sprintf("tx %d", i), } diff --git a/gno.land/cmd/gnoland/secrets_get.go b/gno.land/cmd/gnoland/secrets_get.go index 8d111516816..47de7a46283 100644 --- a/gno.land/cmd/gnoland/secrets_get.go +++ b/gno.land/cmd/gnoland/secrets_get.go @@ -41,18 +41,6 @@ func newSecretsGetCmd(io commands.IO) *commands.Command { }, ) - // Add subcommand helpers - helperGen := metadataHelperGenerator{ - MetaUpdate: func(meta *commands.Metadata, inputType string) { - meta.ShortUsage = fmt.Sprintf("secrets get %s <%s>", meta.Name, inputType) - }, - TagNameSelector: "json", - TreeDisplay: false, - } - cmd.AddSubCommands(generateSubCommandHelper(helperGen, secrets{}, func(_ context.Context, args []string) error { - return execSecretsGet(cfg, args, io) - })...) - return cmd } diff --git a/gno.land/cmd/gnoland/testdata/addpkg.txtar b/gno.land/cmd/gnoland/testdata/addpkg.txtar index 8594e6596ce..6249d2ff7a0 100644 --- a/gno.land/cmd/gnoland/testdata/addpkg.txtar +++ b/gno.land/cmd/gnoland/testdata/addpkg.txtar @@ -1,23 +1,15 @@ # test for add package +# load hello.gno package located in $WORK directory as gno.land/r/hello +loadpkg gno.land/r/hello $WORK + ## start a new node gnoland start -## deploy realm -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/$USER_ADDR_test1/hello -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1 - -## check output -stdout OK! -stdout 'GAS WANTED: 100000000' -stdout 'GAS USED: \d+' -stdout 'HEIGHT: \d+' -stdout 'EVENTS: \[\]' -stdout 'TX HASH: ' - -## call added realm -gnokey maketx call -pkgpath gno.land/r/$USER_ADDR_test1/hello -chainid=tendermint_test -func SayHello -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast test1 +## execute SayHello +gnokey maketx call -pkgpath gno.land/r/hello -func SayHello -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -## check output +## compare SayHello stdout '\("hello world!" string\)' stdout OK! stdout 'GAS WANTED: 2000000' diff --git a/gno.land/cmd/gnoland/testdata/alloc_array.txtar b/gno.land/cmd/gnoland/testdata/alloc_array.txtar deleted file mode 100644 index df9e6539297..00000000000 --- a/gno.land/cmd/gnoland/testdata/alloc_array.txtar +++ /dev/null @@ -1,16 +0,0 @@ -loadpkg gno.land/r/alloc $WORK - -gnoland start - -! gnokey maketx call -pkgpath gno.land/r/alloc -func DoAlloc -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -stderr 'Data: allocation limit exceeded' - --- alloc.gno -- -package alloc - -var buffer interface{} - -func DoAlloc() { - var arr [1_000_000_000_000_000]byte - buffer = arr -} diff --git a/gno.land/cmd/gnoland/testdata/alloc_byte_slice.txtar b/gno.land/cmd/gnoland/testdata/alloc_byte_slice.txtar deleted file mode 100644 index 99b0b85e97d..00000000000 --- a/gno.land/cmd/gnoland/testdata/alloc_byte_slice.txtar +++ /dev/null @@ -1,16 +0,0 @@ -loadpkg gno.land/r/alloc $WORK - -gnoland start - -! gnokey maketx call -pkgpath gno.land/r/alloc -func DoAlloc -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -stderr 'Data: allocation limit exceeded' - --- alloc.gno -- -package alloc - -var buffer []byte - -func DoAlloc() { - buffer := make([]byte, 1_000_000_000_000) - buffer[1] = 'a' -} diff --git a/gno.land/cmd/gnoland/testdata/alloc_slice.txtar b/gno.land/cmd/gnoland/testdata/alloc_slice.txtar deleted file mode 100644 index 21a4d28d90d..00000000000 --- a/gno.land/cmd/gnoland/testdata/alloc_slice.txtar +++ /dev/null @@ -1,16 +0,0 @@ -loadpkg gno.land/r/alloc $WORK - -gnoland start - -! gnokey maketx call -pkgpath gno.land/r/alloc -func DoAlloc -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -stderr 'Data: allocation limit exceeded' - --- alloc.gno -- -package alloc - -var buffer []int - -func DoAlloc() { - buffer := make([]int, 1_000_000_000_000) - buffer[1] = 1 -} diff --git a/gno.land/cmd/gnoland/testdata/issue_2283_cacheTypes.txtar b/gno.land/cmd/gnoland/testdata/issue_2283_cacheTypes.txtar index 95bd48c0144..38b0c8fe865 100644 --- a/gno.land/cmd/gnoland/testdata/issue_2283_cacheTypes.txtar +++ b/gno.land/cmd/gnoland/testdata/issue_2283_cacheTypes.txtar @@ -101,3 +101,4 @@ import ( func Call(s string) { base64.StdEncoding.DecodeString("hey") } + diff --git a/gno.land/cmd/gnoland/testdata/panic.txtar b/gno.land/cmd/gnoland/testdata/panic.txtar deleted file mode 100644 index 2b964d80751..00000000000 --- a/gno.land/cmd/gnoland/testdata/panic.txtar +++ /dev/null @@ -1,27 +0,0 @@ -# test panic - -loadpkg gno.land/r/demo/panic $WORK - -# start a new node -gnoland start - - -! gnokey maketx call -pkgpath gno.land/r/demo/panic --func Trigger --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 - -stderr 'p\\(\)' -stderr 'gno.land/r/demo/panic/panic.gno:5' -stderr 'pkg\\.Trigger\(\)' -stderr 'gno.land/r/demo/panic/panic.gno:9' - --- panic.gno -- -package main - -func p() { - i := "here" - panic(i) -} - -func Trigger() { - p() -} - diff --git a/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar b/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar deleted file mode 100644 index 7592693eeff..00000000000 --- a/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar +++ /dev/null @@ -1,202 +0,0 @@ -# This txtar is a regression test for a bug, whereby a type is committed to -# the defaultStore.cacheTypes map, but not to the underlying store (due to a -# failing transaction). -# For more information: https://github.com/gnolang/gno/pull/2605 -loadpkg gno.land/p/demo/avl -gnoland start - -gnokey sign -tx-path $WORK/tx1.tx -chainid tendermint_test -account-sequence 0 test1 -! gnokey broadcast $WORK/tx1.tx -stderr 'out of gas' - -gnokey sign -tx-path $WORK/tx2.tx -chainid tendermint_test -account-sequence 1 test1 -gnokey broadcast $WORK/tx2.tx -stdout 'OK!' - -gnokey sign -tx-path $WORK/tx3.tx -chainid tendermint_test -account-sequence 2 test1 -gnokey broadcast $WORK/tx3.tx -stdout 'OK!' - -gnoland restart - --- tx1.tx -- -{ - "msg": [ - { - "@type": "/vm.m_addpkg", - "creator": "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5", - "package": { - "name": "zentasktic", - "path": "gno.land/p/g17ernafy6ctpcz6uepfsq2js8x2vz0wladh5yc3/zentasktic", - "files": [ - { - "name": "README.md", - "body": "# ZenTasktic Core\n\nA basic, minimalisitc Asess-Decide-Do implementations as `p/zentasktic`. The diagram below shows a simplified ADD workflow.\n\n![ZenTasktic](ZenTasktic-framework.png)\n\nThis implementation will expose all the basic features of the framework: tasks & projects with complete workflows. Ideally, this should offer all the necessary building blocks for any other custom implementation.\n\n## Object Definitions and Default Values\n\nAs an unopinionated ADD workflow, `zentastic_core` defines the following objects:\n\n- Realm\n\nRealms act like containers for tasks & projects during their journey from Assess to Do, via Decide. Each realm has a certain restrictions, e.g. a task's Body can only be edited in Assess, a Context, Due date and Alert can only be added in Decide, etc.\n\nIf someone observes different realms, there is support for adding and removing arbitrary Realms.\n\n_note: the Ids between 1 and 4 are reserved for: 1-Assess, 2-Decide, 3-Do, 4-Collection. Trying to add or remove such a Realm will raise an error._\n\n\nRealm data definition:\n\n```\ntype Realm struct {\n\tId \t\t\tstring `json:\"realmId\"`\n\tName \t\tstring `json:\"realmName\"`\n}\n```\n\n- Task\n\nA task is the minimal data structure in ZenTasktic, with the following definition:\n\n```\ntype Task struct {\n\tId \t\t\tstring `json:\"taskId\"`\n\tProjectId \tstring `json:\"taskProjectId\"`\n\tContextId\tstring `json:\"taskContextId\"`\n\tRealmId \tstring `json:\"taskRealmId\"`\n\tBody \t\tstring `json:\"taskBody\"`\n\tDue\t\t\tstring `json:\"taskDue\"`\n\tAlert\t\tstring `json:\"taskAlert\"`\n}\n```\n\n- Project\n\nProjects are unopinionated collections of Tasks. A Task in a Project can be in any Realm, but the restrictions are propagated upwards to the Project: e.g. if a Task is marked as 'done' in the Do realm (namely changing its RealmId property to \"1\", Assess, or \"4\" Collection), and the rest of the tasks are not, the Project cannot be moved back to Decide or Asses, all Tasks must have consisted RealmId properties.\n\nA Task can be arbitrarily added to, removed from and moved to another Project.\n\nProject data definition:\n\n\n```\ntype Project struct {\n\tId \t\t\tstring `json:\"projectId\"`\n\tContextId\tstring `json:\"projectContextId\"`\n\tRealmId \tstring `json:\"projectRealmId\"`\n\tTasks\t\t[]Task `json:\"projectTasks\"`\n\tBody \t\tstring `json:\"projectBody\"`\n\tDue\t\t\tstring `json:\"ProjectDue\"`\n}\n```\n\n\n- Context\n\nContexts act as tags, grouping together Tasks and Project, e.g. \"Backend\", \"Frontend\", \"Marketing\". Contexts have no defaults and can be added or removed arbitrarily.\n\nContext data definition:\n\n```\ntype Context struct {\n\tId \t\t\tstring `json:\"contextId\"`\n\tName \t\tstring `json:\"contextName\"`\n}\n```\n\n- Collection\n\nCollections are intended as an agnostic storage for Tasks & Projects which are either not ready to be Assessed, or they have been already marked as done, and, for whatever reason, they need to be kept in the system. There is a special Realm Id for Collections, \"4\", although technically they are not part of the Assess-Decide-Do workflow.\n\nCollection data definition:\n\n```\ntype Collection struct {\n\tId \t\t\tstring `json:\"collectionId\"`\n\tRealmId \tstring `json:\"collectionRealmId\"`\n\tName \t\tstring `json:\"collectionName\"`\n\tTasks\t\t[]Task `json:\"collectionTasks\"`\n\tProjects\t[]Project `json:\"collectionProjects\"`\n}\n```\n\n- ObjectPath\n\nObjectPaths are minimalistic representations of the journey taken by a Task or a Project in the Assess-Decide-Do workflow. By recording their movement between various Realms, one can extract their `ZenStatus`, e.g., if a Task has been moved many times between Assess and Decide, never making it to Do, we can infer the following:\n-- either the Assess part was incomplete\n-- the resources needed for that Task are not yet ready\n\nObjectPath data definition:\n\n```\ntype ObjectPath struct {\n\tObjectType\tstring `json:\"objectType\"` // Task, Project\n\tId \t\t\tstring `json:\"id\"` // this is the Id of the object moved, Task, Project\n\tRealmId \tstring `json:\"realmId\"`\n}\n```\n\n_note: the core implementation offers the basic adding and retrieving functionality, but it's up to the client realm using the `zentasktic` package to call them when an object is moved from one Realm to another._\n\n## Example Workflow\n\n```\npackage example_zentasktic\n\nimport \"gno.land/p/demo/zentasktic\"\n\nvar ztm *zentasktic.ZTaskManager\nvar zpm *zentasktic.ZProjectManager\nvar zrm *zentasktic.ZRealmManager\nvar zcm *zentasktic.ZContextManager\nvar zcl *zentasktic.ZCollectionManager\nvar zom *zentasktic.ZObjectPathManager\n\nfunc init() {\n ztm = zentasktic.NewZTaskManager()\n zpm = zentasktic.NewZProjectManager()\n\tzrm = zentasktic.NewZRealmManager()\n\tzcm = zentasktic.NewZContextManager()\n\tzcl = zentasktic.NewZCollectionManager()\n\tzom = zentasktic.NewZObjectPathManager()\n}\n\n// initializing a task, assuming we get the value POSTed by some call to the current realm\n\nnewTask := zentasktic.Task{Id: \"20\", Body: \"Buy milk\"}\nztm.AddTask(newTask)\n\n// if we want to keep track of the object zen status, we update the object path\ntaskPath := zentasktic.ObjectPath{ObjectType: \"task\", Id: \"20\", RealmId: \"1\"}\nzom.AddPath(taskPath)\n...\n\neditedTask := zentasktic.Task{Id: \"20\", Body: \"Buy fresh milk\"}\nztm.EditTask(editedTask)\n\n...\n\n// moving it to Decide\n\nztm.MoveTaskToRealm(\"20\", \"2\")\n\n// adding context, due date and alert, assuming they're received from other calls\n\nshoppingContext := zcm.GetContextById(\"2\")\n\ncerr := zcm.AddContextToTask(ztm, shoppingContext, editedTask)\n\nderr := ztm.SetTaskDueDate(editedTask.Id, \"2024-04-10\")\nnow := time.Now() // replace with the actual time of the alert\nalertTime := now.Format(\"2006-01-02 15:04:05\")\naerr := ztm.SetTaskAlert(editedTask.Id, alertTime)\n\n...\n\n// move the Task to Do\n\nztm.MoveTaskToRealm(editedTask.Id, \"2\")\n\n// if we want to keep track of the object zen status, we update the object path\ntaskPath := zentasktic.ObjectPath{ObjectType: \"task\", Id: \"20\", RealmId: \"2\"}\nzom.AddPath(taskPath)\n\n// after the task is done, we sent it back to Assess\n\nztm.MoveTaskToRealm(editedTask.Id,\"1\")\n\n// if we want to keep track of the object zen status, we update the object path\ntaskPath := zentasktic.ObjectPath{ObjectType: \"task\", Id: \"20\", RealmId: \"1\"}\nzom.AddPath(taskPath)\n\n// from here, we can add it to a collection\n\nmyCollection := zcm.GetCollectionById(\"1\")\n\nzcm.AddTaskToCollection(ztm, myCollection, editedTask)\n\n// if we want to keep track of the object zen status, we update the object path\ntaskPath := zentasktic.ObjectPath{ObjectType: \"task\", Id: \"20\", RealmId: \"4\"}\nzom.AddPath(taskPath)\n\n```\n\nAll tests are in the `*_test.gno` files, e.g. `tasks_test.gno`, `projects_test.gno`, etc." - }, - { - "name": "collections.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"gno.land/p/demo/avl\"\n)\n\n\ntype Collection struct {\n\tId \t\t\tstring `json:\"collectionId\"`\n\tRealmId \tstring `json:\"collectionRealmId\"`\n\tName \t\tstring `json:\"collectionName\"`\n\tTasks\t\t[]Task `json:\"collectionTasks\"`\n\tProjects\t[]Project `json:\"collectionProjects\"`\n}\n\ntype ZCollectionManager struct {\n\tCollections *avl.Tree \n\tCollectionTasks *avl.Tree\n\tCollectionProjects *avl.Tree \n}\n\nfunc NewZCollectionManager() *ZCollectionManager {\n return &ZCollectionManager{\n Collections: avl.NewTree(),\n CollectionTasks: avl.NewTree(),\n CollectionProjects: avl.NewTree(),\n }\n}\n\n\n// actions\n\nfunc (zcolm *ZCollectionManager) AddCollection(c Collection) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif exist {\n\t\t\treturn ErrCollectionIdAlreadyExists\n\t\t}\n\t}\n\tzcolm.Collections.Set(c.Id, c)\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) EditCollection(c Collection) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\t\n\tzcolm.Collections.Set(c.Id, c)\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) RemoveCollection(c Collection) (err error) {\n // implementation\n if zcolm.Collections.Size() != 0 {\n collectionInterface, exist := zcolm.Collections.Get(c.Id)\n if !exist {\n return ErrCollectionIdNotFound\n }\n collection := collectionInterface.(Collection)\n\n _, removed := zcolm.Collections.Remove(collection.Id)\n if !removed {\n return ErrCollectionNotRemoved\n }\n\n if zcolm.CollectionTasks.Size() != 0 {\n _, removedTasks := zcolm.CollectionTasks.Remove(collection.Id)\n if !removedTasks {\n return ErrCollectionNotRemoved\n }\t\n }\n\n if zcolm.CollectionProjects.Size() != 0 {\n _, removedProjects := zcolm.CollectionProjects.Remove(collection.Id)\n if !removedProjects {\n return ErrCollectionNotRemoved\n }\t\n }\n }\n return nil\n}\n\n\nfunc (zcolm *ZCollectionManager) AddProjectToCollection(zpm *ZProjectManager, c Collection, p Project) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\n\texistingCollectionProjects, texist := zcolm.CollectionProjects.Get(c.Id)\n\tif !texist {\n\t\t// If the collections has no projects yet, initialize the slice.\n\t\texistingCollectionProjects = []Project{}\n\t} else {\n\t\tprojects, ok := existingCollectionProjects.([]Project)\n\t\tif !ok {\n\t\t\treturn ErrCollectionsProjectsNotFound\n\t\t}\n\t\texistingCollectionProjects = projects\n\t}\n\tp.RealmId = \"4\"\n\tif err := zpm.EditProject(p); err != nil {\n\t\treturn err\n\t}\n\tupdatedProjects := append(existingCollectionProjects.([]Project), p)\n\tzcolm.CollectionProjects.Set(c.Id, updatedProjects)\n\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) AddTaskToCollection(ztm *ZTaskManager, c Collection, t Task) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\n\texistingCollectionTasks, texist := zcolm.CollectionTasks.Get(c.Id)\n\tif !texist {\n\t\t// If the collections has no tasks yet, initialize the slice.\n\t\texistingCollectionTasks = []Task{}\n\t} else {\n\t\ttasks, ok := existingCollectionTasks.([]Task)\n\t\tif !ok {\n\t\t\treturn ErrCollectionsTasksNotFound\n\t\t}\n\t\texistingCollectionTasks = tasks\n\t}\n\tt.RealmId = \"4\"\n\tif err := ztm.EditTask(t); err != nil {\n\t\treturn err\n\t}\n\tupdatedTasks := append(existingCollectionTasks.([]Task), t)\n\tzcolm.CollectionTasks.Set(c.Id, updatedTasks)\n\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) RemoveProjectFromCollection(zpm *ZProjectManager, c Collection, p Project) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\n\texistingCollectionProjects, texist := zcolm.CollectionProjects.Get(c.Id)\n\tif !texist {\n\t\t// If the collection has no projects yet, return appropriate error\n\t\treturn ErrCollectionsProjectsNotFound\n\t}\n\n\t// Find the index of the project to be removed.\n\tvar index int = -1\n\tfor i, project := range existingCollectionProjects.([]Project) {\n\t\tif project.Id == p.Id {\n\t\t\tindex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// If the project was found, we remove it from the slice.\n\tif index != -1 {\n\t\t// by default we send it back to Assess\n\t\tp.RealmId = \"1\"\n\t\tzpm.EditProject(p)\n\t\texistingCollectionProjects = append(existingCollectionProjects.([]Project)[:index], existingCollectionProjects.([]Project)[index+1:]...)\n\t} else {\n\t\t// Project not found in the collection\n\t\treturn ErrProjectByIdNotFound \n\t}\n\tzcolm.CollectionProjects.Set(c.Id, existingCollectionProjects)\n\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) RemoveTaskFromCollection(ztm *ZTaskManager, c Collection, t Task) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\n\texistingCollectionTasks, texist := zcolm.CollectionTasks.Get(c.Id)\n\tif !texist {\n\t\t// If the collection has no tasks yet, return appropriate error\n\t\treturn ErrCollectionsTasksNotFound\n\t}\n\n\t// Find the index of the task to be removed.\n\tvar index int = -1\n\tfor i, task := range existingCollectionTasks.([]Task) {\n\t\tif task.Id == t.Id {\n\t\t\tindex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// If the task was found, we remove it from the slice.\n\tif index != -1 {\n\t\t// by default, we send the task to Assess\n\t\tt.RealmId = \"1\"\n\t\tztm.EditTask(t)\n\t\texistingCollectionTasks = append(existingCollectionTasks.([]Task)[:index], existingCollectionTasks.([]Task)[index+1:]...)\n\t} else {\n\t\t// Task not found in the collection\n\t\treturn ErrTaskByIdNotFound \n\t}\n\tzcolm.CollectionTasks.Set(c.Id, existingCollectionTasks)\n\n\treturn nil\n}\n\n// getters\n\nfunc (zcolm *ZCollectionManager) GetCollectionById(collectionId string) (Collection, error) {\n if zcolm.Collections.Size() != 0 {\n cInterface, exist := zcolm.Collections.Get(collectionId)\n if exist {\n collection := cInterface.(Collection)\n // look for collection Tasks, Projects\n existingCollectionTasks, texist := zcolm.CollectionTasks.Get(collectionId)\n if texist {\n collection.Tasks = existingCollectionTasks.([]Task)\n }\n existingCollectionProjects, pexist := zcolm.CollectionProjects.Get(collectionId)\n if pexist {\n collection.Projects = existingCollectionProjects.([]Project)\n }\n return collection, nil\n }\n return Collection{}, ErrCollectionByIdNotFound\n }\n return Collection{}, ErrCollectionByIdNotFound\n}\n\nfunc (zcolm *ZCollectionManager) GetCollectionTasks(c Collection) (tasks []Task, err error) {\n\t\n\tif zcolm.CollectionTasks.Size() != 0 {\n\t\ttask, exist := zcolm.CollectionTasks.Get(c.Id)\n\t\tif !exist {\n\t\t\t// if there's no record in CollectionTasks, we don't have to return anything\n\t\t\treturn nil, ErrCollectionsTasksNotFound\n\t\t} else {\n\t\t\t// type assertion to convert interface{} to []Task\n\t\t\texistingCollectionTasks, ok := task.([]Task)\n\t\t\tif !ok {\n\t\t\t\treturn nil, ErrTaskFailedToAssert\n\t\t\t}\n\t\t\treturn existingCollectionTasks, nil\n\t\t}\n\t}\n\treturn nil, nil\n}\n\nfunc (zcolm *ZCollectionManager) GetCollectionProjects(c Collection) (projects []Project, err error) {\n\t\n\tif zcolm.CollectionProjects.Size() != 0 {\n\t\tproject, exist := zcolm.CollectionProjects.Get(c.Id)\n\t\tif !exist {\n\t\t\t// if there's no record in CollectionProjets, we don't have to return anything\n\t\t\treturn nil, ErrCollectionsProjectsNotFound\n\t\t} else {\n\t\t\t// type assertion to convert interface{} to []Projet\n\t\t\texistingCollectionProjects, ok := project.([]Project)\n\t\t\tif !ok {\n\t\t\t\treturn nil, ErrProjectFailedToAssert\n\t\t\t}\n\t\t\treturn existingCollectionProjects, nil\n\t\t}\n\t}\n\treturn nil, nil\n}\n\nfunc (zcolm *ZCollectionManager) GetAllCollections() (collections string, err error) {\n\t// implementation\n\tvar allCollections []Collection\n\t\n\t// Iterate over the Collections AVL tree to collect all Project objects.\n\t\n\tzcolm.Collections.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif collection, ok := value.(Collection); ok {\n\t\t\t// get collection tasks, if any\n\t\t\tcollectionTasks, _ := zcolm.GetCollectionTasks(collection)\n\t\t\tif collectionTasks != nil {\n\t\t\t\tcollection.Tasks = collectionTasks\n\t\t\t}\n\t\t\t// get collection prokects, if any\n\t\t\tcollectionProjects, _ := zcolm.GetCollectionProjects(collection)\n\t\t\tif collectionProjects != nil {\n\t\t\t\tcollection.Projects = collectionProjects\n\t\t\t}\n\t\t\tallCollections = append(allCollections, collection)\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a CollectionsObject with all collected tasks.\n\tcollectionsObject := CollectionsObject{\n\t\tCollections: allCollections,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the collections into JSON.\n\tmarshalledCollections, merr := collectionsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\", merr\n\t} \n\treturn string(marshalledCollections), nil\n} " - }, - { - "name": "collections_test.gno", - "body": "package zentasktic\n\nimport (\n\t\"testing\"\n\n \"gno.land/p/demo/avl\"\n)\n/*\n\nfunc Test_AddCollection(t *testing.T) {\n \n collection := Collection{Id: \"1\", RealmId: \"4\", Name: \"First collection\",}\n\n // Test adding a collection successfully.\n err := collection.AddCollection()\n if err != nil {\n t.Errorf(\"Failed to add collection: %v\", err)\n }\n\n // Test adding a duplicate task.\n cerr := collection.AddCollection()\n if cerr != ErrCollectionIdAlreadyExists {\n t.Errorf(\"Expected ErrCollectionIdAlreadyExists, got %v\", cerr)\n }\n}\n\nfunc Test_RemoveCollection(t *testing.T) {\n \n collection := Collection{Id: \"20\", RealmId: \"4\", Name: \"Removable collection\",}\n\n // Test adding a collection successfully.\n err := collection.AddCollection()\n if err != nil {\n t.Errorf(\"Failed to add collection: %v\", err)\n }\n\n retrievedCollection, rerr := GetCollectionById(collection.Id)\n if rerr != nil {\n t.Errorf(\"Could not retrieve the added collection\")\n }\n\n // Test removing a collection\n terr := retrievedCollection.RemoveCollection()\n if terr != ErrCollectionNotRemoved {\n t.Errorf(\"Expected ErrCollectionNotRemoved, got %v\", terr)\n }\n}\n\nfunc Test_EditCollection(t *testing.T) {\n \n collection := Collection{Id: \"2\", RealmId: \"4\", Name: \"Second collection\",}\n\n // Test adding a collection successfully.\n err := collection.AddCollection()\n if err != nil {\n t.Errorf(\"Failed to add collection: %v\", err)\n }\n\n // Test editing the collection\n editedCollection := Collection{Id: collection.Id, RealmId: collection.RealmId, Name: \"Edited collection\",}\n cerr := editedCollection.EditCollection()\n if cerr != nil {\n t.Errorf(\"Failed to edit the collection\")\n }\n\n retrievedCollection, _ := GetCollectionById(editedCollection.Id)\n if retrievedCollection.Name != \"Edited collection\" {\n t.Errorf(\"Collection was not edited\")\n }\n}\n\nfunc Test_AddProjectToCollection(t *testing.T){\n // Example Collection and Projects\n col := Collection{Id: \"1\", Name: \"First collection\", RealmId: \"4\",}\n prj := Project{Id: \"10\", Body: \"Project 10\", RealmId: \"1\",}\n\n Collections.Set(col.Id, col) // Mock existing collections\n\n tests := []struct {\n name string\n collection Collection\n project Project\n wantErr bool\n errMsg error\n }{\n {\n name: \"Attach to existing collection\",\n collection: col,\n project: prj,\n wantErr: false,\n },\n {\n name: \"Attach to non-existing collection\",\n collection: Collection{Id: \"200\", Name: \"Collection 200\", RealmId: \"4\",},\n project: prj,\n wantErr: true,\n errMsg: ErrCollectionIdNotFound,\n },\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n err := tt.collection.AddProjectToCollection(tt.project)\n if (err != nil) != tt.wantErr {\n t.Errorf(\"AddProjectToCollection() error = %v, wantErr %v\", err, tt.wantErr)\n }\n if tt.wantErr && err != tt.errMsg {\n t.Errorf(\"AddProjectToCollection() error = %v, expected %v\", err, tt.errMsg)\n }\n\n // For successful attach, verify the project is added to the collection's tasks.\n if !tt.wantErr {\n projects, exist := CollectionProjects.Get(tt.collection.Id)\n if !exist || len(projects.([]Project)) == 0 {\n t.Errorf(\"Project was not added to the collection\")\n } else {\n found := false\n for _, project := range projects.([]Project) {\n if project.Id == tt.project.Id {\n found = true\n break\n }\n }\n if !found {\n t.Errorf(\"Project was not attached to the collection\")\n }\n }\n }\n })\n }\n}\n\nfunc Test_AddTaskToCollection(t *testing.T){\n // Example Collection and Tasks\n col := Collection{Id: \"2\", Name: \"Second Collection\", RealmId: \"4\",}\n tsk := Task{Id: \"30\", Body: \"Task 30\", RealmId: \"1\",}\n\n Collections.Set(col.Id, col) // Mock existing collections\n\n tests := []struct {\n name string\n collection Collection\n task Task\n wantErr bool\n errMsg error\n }{\n {\n name: \"Attach to existing collection\",\n collection: col,\n task: tsk,\n wantErr: false,\n },\n {\n name: \"Attach to non-existing collection\",\n collection: Collection{Id: \"210\", Name: \"Collection 210\", RealmId: \"4\",},\n task: tsk,\n wantErr: true,\n errMsg: ErrCollectionIdNotFound,\n },\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n err := tt.collection.AddTaskToCollection(tt.task)\n if (err != nil) != tt.wantErr {\n t.Errorf(\"AddTaskToCollection() error = %v, wantErr %v\", err, tt.wantErr)\n }\n if tt.wantErr && err != tt.errMsg {\n t.Errorf(\"AddTaskToCollection() error = %v, expected %v\", err, tt.errMsg)\n }\n\n // For successful attach, verify the task is added to the collection's tasks.\n if !tt.wantErr {\n tasks, exist := CollectionTasks.Get(tt.collection.Id)\n if !exist || len(tasks.([]Task)) == 0 {\n t.Errorf(\"Task was not added to the collection\")\n } else {\n found := false\n for _, task := range tasks.([]Task) {\n if task.Id == tt.task.Id {\n found = true\n break\n }\n }\n if !found {\n t.Errorf(\"Task was not attached to the collection\")\n }\n }\n }\n })\n }\n}\n\nfunc Test_RemoveProjectFromCollection(t *testing.T){\n // Setup:\n\tcollection := Collection{Id: \"300\", Name: \"Collection 300\",}\n\tproject1 := Project{Id: \"21\", Body: \"Project 21\", RealmId: \"1\",}\n\tproject2 := Project{Id: \"22\", Body: \"Project 22\", RealmId: \"1\",}\n\n collection.AddCollection()\n project1.AddProject()\n project2.AddProject()\n collection.AddProjectToCollection(project1)\n collection.AddProjectToCollection(project2)\n\n\ttests := []struct {\n\t\tname string\n\t\tproject Project\n\t\tcollection Collection\n\t\twantErr bool\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname: \"Remove existing project from collection\",\n\t\t\tproject: project1,\n\t\t\tcollection: collection,\n\t\t\twantErr: false,\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to remove project from non-existing collection\",\n\t\t\tproject: project1,\n\t\t\tcollection: Collection{Id: \"nonexistent\"},\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrCollectionIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to remove non-existing project from collection\",\n\t\t\tproject: Project{Id: \"nonexistent\"},\n\t\t\tcollection: collection,\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrProjectByIdNotFound,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.collection.RemoveProjectFromCollection(tt.project)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tif err == nil || err != tt.expectedErr {\n\t\t\t\t\tt.Errorf(\"%s: expected error %v, got %v\", tt.name, tt.expectedErr, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"%s: unexpected error: %v\", tt.name, err)\n\t\t\t\t}\n\n\t\t\t\t// For successful removal, verify the project is no longer part of the collection's projects\n\t\t\t\tif !tt.wantErr {\n\t\t\t\t\tprojects, _ := CollectionProjects.Get(tt.collection.Id)\n\t\t\t\t\tfor _, project := range projects.([]Project) {\n\t\t\t\t\t\tif project.Id == tt.project.Id {\n\t\t\t\t\t\t\tt.Errorf(\"%s: project was not detached from the collection\", tt.name)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_RemoveTaskFromCollection(t *testing.T){\n // setup, re-using parts from Test_AddTaskToCollection\n\tcollection := Collection{Id: \"40\", Name: \"Collection 40\",}\n task1 := Task{Id: \"40\", Body: \"Task 40\", RealmId: \"1\",}\n\n collection.AddCollection()\n task1.AddTask()\n collection.AddTaskToCollection(task1)\n\n\ttests := []struct {\n\t\tname string\n\t\ttask Task\n\t\tcollection Collection\n\t\twantErr bool\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname: \"Remove existing task from collection\",\n\t\t\ttask: task1,\n\t\t\tcollection: collection,\n\t\t\twantErr: false,\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to remove task from non-existing collection\",\n\t\t\ttask: task1,\n\t\t\tcollection: Collection{Id: \"nonexistent\"},\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrCollectionIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to remove non-existing task from collection\",\n\t\t\ttask: Task{Id: \"nonexistent\"},\n\t\t\tcollection: collection,\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrTaskByIdNotFound,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.collection.RemoveTaskFromCollection(tt.task)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tif err == nil || err != tt.expectedErr {\n\t\t\t\t\tt.Errorf(\"%s: expected error %v, got %v\", tt.name, tt.expectedErr, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"%s: unexpected error: %v\", tt.name, err)\n\t\t\t\t}\n\n\t\t\t\t// For successful removal, verify the task is no longer part of the collection's tasks\n\t\t\t\tif !tt.wantErr {\n\t\t\t\t\ttasks, _ := CollectionTasks.Get(tt.collection.Id)\n\t\t\t\t\tfor _, task := range tasks.([]Task) {\n\t\t\t\t\t\tif task.Id == tt.task.Id {\n\t\t\t\t\t\t\tt.Errorf(\"%s: task was not detached from the collection\", tt.name)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_GetCollectionById(t *testing.T){\n // test getting a non-existing collection\n nonCollection, err := GetCollectionById(\"0\")\n if err != ErrCollectionByIdNotFound {\n t.Fatalf(\"Expected ErrCollectionByIdNotFound, got: %v\", err)\n }\n\n // test getting the correct collection by id\n correctCollection, err := GetCollectionById(\"1\")\n if err != nil {\n t.Fatalf(\"Failed to get collection by id, error: %v\", err)\n }\n\n if correctCollection.Name != \"First collection\" {\n t.Fatalf(\"Got the wrong collection, with name: %v\", correctCollection.Name)\n }\n}\n\nfunc Test_GetCollectionTasks(t *testing.T) {\n // retrieving objects based on these mocks\n //col := Collection{Id: \"2\", Name: \"Second Collection\", RealmId: \"4\",}\n tsk := Task{Id: \"30\", Body: \"Task 30\", RealmId: \"1\",}\n\n collection, cerr := GetCollectionById(\"2\")\n if cerr != nil {\n t.Errorf(\"GetCollectionById() failed, %v\", cerr)\n }\n\n collectionTasks, pterr := collection.GetCollectionTasks()\n if len(collectionTasks) == 0 {\n t.Errorf(\"GetCollectionTasks() failed, %v\", pterr)\n }\n\n // test detaching from an existing collection\n dtterr := collection.RemoveTaskFromCollection(tsk)\n if dtterr != nil {\n t.Errorf(\"RemoveTaskFromCollection() failed, %v\", dtterr)\n }\n\n collectionWithNoTasks, pterr := collection.GetCollectionTasks()\n if len(collectionWithNoTasks) != 0 {\n t.Errorf(\"GetCollectionTasks() after detach failed, %v\", pterr)\n }\n\n // add task back to collection, for tests mockup integrity\n collection.AddTaskToCollection(tsk)\n}\n\nfunc Test_GetCollectionProjects(t *testing.T) {\n // retrieving objects based on these mocks\n //col := Collection{Id: \"1\", Name: \"First Collection\", RealmId: \"4\",}\n prj := Project{Id: \"10\", Body: \"Project 10\", RealmId: \"2\", ContextId: \"2\", Due: \"2024-01-01\"}\n\n collection, cerr := GetCollectionById(\"1\")\n if cerr != nil {\n t.Errorf(\"GetCollectionById() failed, %v\", cerr)\n }\n\n collectionProjects, pterr := collection.GetCollectionProjects()\n if len(collectionProjects) == 0 {\n t.Errorf(\"GetCollectionProjects() failed, %v\", pterr)\n }\n\n // test detaching from an existing collection\n dtterr := collection.RemoveProjectFromCollection(prj)\n if dtterr != nil {\n t.Errorf(\"RemoveProjectFromCollection() failed, %v\", dtterr)\n }\n\n collectionWithNoProjects, pterr := collection.GetCollectionProjects()\n if len(collectionWithNoProjects) != 0 {\n t.Errorf(\"GetCollectionProjects() after detach failed, %v\", pterr)\n }\n\n // add project back to collection, for tests mockup integrity\n collection.AddProjectToCollection(prj)\n}\n\nfunc Test_GetAllCollections(t *testing.T){\n // mocking the collections based on previous tests\n // TODO: add isolation?\n knownCollections := []Collection{\n {\n Id: \"1\",\n RealmId: \"4\",\n Name: \"First collection\",\n Tasks: nil, \n Projects: []Project{\n {\n Id: \"10\",\n ContextId: \"2\",\n RealmId: \"4\",\n Tasks: nil, \n Body: \"Project 10\",\n Due: \"2024-01-01\",\n },\n },\n },\n {\n Id: \"2\",\n RealmId: \"4\",\n Name: \"Second Collection\",\n Tasks: []Task{\n {\n Id:\"30\",\n ProjectId:\"\",\n ContextId:\"\",\n RealmId:\"4\",\n Body:\"Task 30\",\n Due:\"\",\n Alert:\"\",\n },\n },\n Projects: nil, \n },\n {\n Id:\"20\",\n RealmId:\"4\",\n Name:\"Removable collection\",\n Tasks: nil,\n Projects: nil,\n },\n {\n Id: \"300\",\n Name: \"Collection 300\",\n Tasks: nil, \n Projects: []Project {\n {\n Id:\"22\",\n ContextId:\"\",\n RealmId:\"4\",\n Tasks: nil,\n Body:\"Project 22\",\n Due:\"\",\n },\n }, \n },\n {\n Id: \"40\",\n Name: \"Collection 40\",\n Tasks: nil, \n Projects: nil, \n },\n }\n \n\n // Manually marshal the known collections to create the expected outcome.\n collectionsObject := CollectionsObject{Collections: knownCollections}\n expected, err := collectionsObject.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal known collections: %v\", err)\n }\n\n // Execute GetAllCollections() to get the actual outcome.\n actual, err := GetAllCollections()\n if err != nil {\n t.Fatalf(\"GetAllCollections() failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual collections JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n*/\n\n\n\n\n" - }, - { - "name": "contexts.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"gno.land/p/demo/avl\"\n)\n\ntype Context struct {\n\tId string `json:\"contextId\"`\n\tName string `json:\"contextName\"`\n}\n\ntype ZContextManager struct {\n\tContexts *avl.Tree\n}\n\nfunc NewZContextManager() *ZContextManager {\n\treturn &ZContextManager{\n\t\tContexts: avl.NewTree(),\n\t}\n}\n\n// Actions\n\nfunc (zcm *ZContextManager) AddContext(c Context) error {\n\tif zcm.Contexts.Size() != 0 {\n\t\t_, exist := zcm.Contexts.Get(c.Id)\n\t\tif exist {\n\t\t\treturn ErrContextIdAlreadyExists\n\t\t}\n\t}\n\tzcm.Contexts.Set(c.Id, c)\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) EditContext(c Context) error {\n\tif zcm.Contexts.Size() != 0 {\n\t\t_, exist := zcm.Contexts.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrContextIdNotFound\n\t\t}\n\t}\n\tzcm.Contexts.Set(c.Id, c)\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) RemoveContext(c Context) error {\n\tif zcm.Contexts.Size() != 0 {\n\t\tcontext, exist := zcm.Contexts.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrContextIdNotFound\n\t\t}\n\t\t_, removed := zcm.Contexts.Remove(context.(Context).Id)\n\t\tif !removed {\n\t\t\treturn ErrContextNotRemoved\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) AddContextToTask(ztm *ZTaskManager, c Context, t Task) error {\n\ttaskInterface, exist := ztm.Tasks.Get(t.Id)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\t_, cexist := zcm.Contexts.Get(c.Id)\n\tif !cexist {\n\t\treturn ErrContextIdNotFound\n\t}\n\n\tif t.RealmId == \"2\" {\n\t\ttask := taskInterface.(Task)\n\t\ttask.ContextId = c.Id\n\t\tztm.Tasks.Set(t.Id, task)\n\t} else {\n\t\treturn ErrTaskNotEditable\n\t}\n\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) AddContextToProject(zpm *ZProjectManager, c Context, p Project) error {\n\tprojectInterface, exist := zpm.Projects.Get(p.Id)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\t_, cexist := zcm.Contexts.Get(c.Id)\n\tif !cexist {\n\t\treturn ErrContextIdNotFound\n\t}\n\n\tif p.RealmId == \"2\" {\n\t\tproject := projectInterface.(Project)\n\t\tproject.ContextId = c.Id\n\t\tzpm.Projects.Set(p.Id, project)\n\t} else {\n\t\treturn ErrProjectNotEditable\n\t}\n\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) AddContextToProjectTask(zpm *ZProjectManager, c Context, p Project, projectTaskId string) error {\n\t\n\t_, cexist := zcm.Contexts.Get(c.Id)\n\tif !cexist {\n\t\treturn ErrContextIdNotFound\n\t}\n\n\texistingProjectInterface, exist := zpm.Projects.Get(p.Id)\n if !exist {\n return ErrProjectIdNotFound\n }\n existingProject := existingProjectInterface.(Project)\n\n\tif existingProject.RealmId != \"2\" {\n\t\treturn ErrProjectNotEditable\n\t}\n\n existingProjectTasksInterface, texist := zpm.ProjectTasks.Get(p.Id)\n if !texist {\n return ErrProjectTasksNotFound\n }\n tasks, ok := existingProjectTasksInterface.([]Task)\n if !ok {\n return ErrProjectTasksNotFound\n }\n existingProject.Tasks = tasks\n\n var index int = -1\n for i, task := range existingProject.Tasks {\n if task.Id == projectTaskId {\n index = i\n break\n }\n }\n\n if index != -1 {\n existingProject.Tasks[index].ContextId = c.Id\n } else {\n return ErrTaskByIdNotFound\n }\n\n zpm.ProjectTasks.Set(p.Id, existingProject.Tasks)\n return nil\n}\n\n// getters\n\nfunc (zcm *ZContextManager) GetContextById(contextId string) (Context, error) {\n\tif zcm.Contexts.Size() != 0 {\n\t\tcInterface, exist := zcm.Contexts.Get(contextId)\n\t\tif exist {\n\t\t\treturn cInterface.(Context), nil\n\t\t}\n\t\treturn Context{}, ErrContextIdNotFound\n\t}\n\treturn Context{}, ErrContextIdNotFound\n}\n\nfunc (zcm *ZContextManager) GetAllContexts() (string) {\n\tvar allContexts []Context\n\n\t// Iterate over the Contexts AVL tree to collect all Context objects.\n\tzcm.Contexts.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif context, ok := value.(Context); ok {\n\t\t\tallContexts = append(allContexts, context)\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a ContextsObject with all collected contexts.\n\tcontextsObject := &ContextsObject{\n\t\tContexts: allContexts,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the contexts into JSON.\n\tmarshalledContexts, merr := contextsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t}\n\treturn string(marshalledContexts)\n}\n\n" - }, - { - "name": "contexts_test.gno", - "body": "package zentasktic\n\nimport (\n\t\"testing\"\n\n \"gno.land/p/demo/avl\"\n)\n/*\nfunc Test_AddContext(t *testing.T) {\n \n context := Context{Id: \"1\", Name: \"Work\"}\n\n // Test adding a context successfully.\n err := context.AddContext()\n if err != nil {\n t.Errorf(\"Failed to add context: %v\", err)\n }\n\n // Test adding a duplicate task.\n cerr := context.AddContext()\n if cerr != ErrContextIdAlreadyExists {\n t.Errorf(\"Expected ErrContextIdAlreadyExists, got %v\", cerr)\n }\n}\n\nfunc Test_EditContext(t *testing.T) {\n \n context := Context{Id: \"2\", Name: \"Home\"}\n\n // Test adding a context successfully.\n err := context.AddContext()\n if err != nil {\n t.Errorf(\"Failed to add context: %v\", err)\n }\n\n // Test editing the context\n editedContext := Context{Id: \"2\", Name: \"Shopping\"}\n cerr := editedContext.EditContext()\n if cerr != nil {\n t.Errorf(\"Failed to edit the context\")\n }\n\n retrievedContext, _ := GetContextById(editedContext.Id)\n if retrievedContext.Name != \"Shopping\" {\n t.Errorf(\"Context was not edited\")\n }\n}\n\nfunc Test_RemoveContext(t *testing.T) {\n \n context := Context{Id: \"4\", Name: \"Gym\",}\n\n // Test adding a context successfully.\n err := context.AddContext()\n if err != nil {\n t.Errorf(\"Failed to add context: %v\", err)\n }\n\n retrievedContext, rerr := GetContextById(context.Id)\n if rerr != nil {\n t.Errorf(\"Could not retrieve the added context\")\n }\n // Test removing a context\n cerr := retrievedContext.RemoveContext()\n if cerr != ErrContextNotRemoved {\n t.Errorf(\"Expected ErrContextNotRemoved, got %v\", cerr)\n }\n}\n\nfunc Test_AddContextToTask(t *testing.T) {\n\n task := Task{Id: \"10\", Body: \"First content\", RealmId: \"2\", ContextId: \"1\",}\n\n // Test adding a task successfully.\n err := task.AddTask()\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n taskInDecide, exist := Tasks.Get(\"10\")\n\tif !exist {\n\t\tt.Errorf(\"Task with id 10 not found\")\n\t}\n\t// check if context exists\n\tcontextToAdd, cexist := Contexts.Get(\"2\")\n\tif !cexist {\n\t\tt.Errorf(\"Context with id 2 not found\")\n\t}\n\n derr := contextToAdd.(Context).AddContextToTask(taskInDecide.(Task))\n if derr != nil {\n t.Errorf(\"Could not add context to a task in Decide, err %v\", derr)\n }\n}\n\nfunc Test_AddContextToProject(t *testing.T) {\n\n project := Project{Id: \"10\", Body: \"Project 10\", RealmId: \"2\", ContextId: \"1\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n projectInDecide, exist := Projects.Get(\"10\")\n\tif !exist {\n\t\tt.Errorf(\"Project with id 10 not found\")\n\t}\n\t// check if context exists\n\tcontextToAdd, cexist := Contexts.Get(\"2\")\n\tif !cexist {\n\t\tt.Errorf(\"Context with id 2 not found\")\n\t}\n\n derr := contextToAdd.(Context).AddContextToProject(projectInDecide.(Project))\n if derr != nil {\n t.Errorf(\"Could not add context to a project in Decide, err %v\", derr)\n }\n}\n\nfunc Test_GetAllContexts(t *testing.T) {\n \n // mocking the contexts based on previous tests\n // TODO: add isolation?\n knownContexts := []Context{\n {Id: \"1\", Name: \"Work\",},\n {Id: \"2\", Name: \"Shopping\",},\n {Id: \"4\", Name: \"Gym\",},\n }\n\n // Manually marshal the known contexts to create the expected outcome.\n contextsObject := ContextsObject{Contexts: knownContexts}\n expected, err := contextsObject.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal known contexts: %v\", err)\n }\n\n // Execute GetAllContexts() to get the actual outcome.\n actual, err := GetAllContexts()\n if err != nil {\n t.Fatalf(\"GetAllContexts() failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual contexts JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n*/\n\n" - }, - { - "name": "core.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"strconv\"\n\n\t\"gno.land/p/demo/avl\"\n)\n\n// holding the path of an object since creation\n// each time we move an object from one realm to another, we add to its path\ntype ObjectPath struct {\n\tObjectType string `json:\"objectType\"` // Task, Project\n\tId string `json:\"id\"` // this is the Id of the object moved, Task, Project\n\tRealmId string `json:\"realmId\"`\n}\n\ntype ZObjectPathManager struct {\n\tPaths avl.Tree\n\tPathId int\n}\n\nfunc NewZObjectPathManager() *ZObjectPathManager {\n\treturn &ZObjectPathManager{\n\t\tPaths: *avl.NewTree(),\n\t\tPathId: 1,\n\t}\n}\n\nfunc (zopm *ZObjectPathManager) AddPath(o ObjectPath) error {\n\tzopm.PathId++\n\tupdated := zopm.Paths.Set(strconv.Itoa(zopm.PathId), o)\n\tif !updated {\n\t\treturn ErrObjectPathNotUpdated\n\t}\n\treturn nil\n}\n\nfunc (zopm *ZObjectPathManager) GetObjectJourney(objectType string, objectId string) (string, error) {\n\tvar objectPaths []ObjectPath\n\n\t// Iterate over the Paths AVL tree to collect all ObjectPath objects.\n\tzopm.Paths.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif objectPath, ok := value.(ObjectPath); ok {\n\t\t\tif objectPath.ObjectType == objectType && objectPath.Id == objectId {\n\t\t\t\tobjectPaths = append(objectPaths, objectPath)\n\t\t\t}\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create an ObjectJourney with all collected paths.\n\tobjectJourney := &ObjectJourney{\n\t\tObjectPaths: objectPaths,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the journey into JSON.\n\tmarshalledJourney, merr := objectJourney.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\", merr\n\t}\n\treturn string(marshalledJourney), nil\n}\n\n\n// GetZenStatus\n/* todo: leave it to the client\nfunc () GetZenStatus() (zenStatus string, err error) {\n\t// implementation\n}\n*/\n" - }, - { - "name": "errors.gno", - "body": "package zentasktic\n\nimport \"errors\"\n\nvar (\n\tErrTaskNotEditable \t= errors.New(\"Task is not editable\")\n\tErrProjectNotEditable = errors.New(\"Project is not editable\")\n\tErrProjectIdNotFound\t\t\t= errors.New(\"Project id not found\")\n\tErrTaskIdNotFound\t\t\t\t= errors.New(\"Task id not found\")\n\tErrTaskFailedToAssert\t\t\t= errors.New(\"Failed to assert Task type\")\n\tErrProjectFailedToAssert\t\t= errors.New(\"Failed to assert Project type\")\n\tErrProjectTasksNotFound\t\t\t= errors.New(\"Could not get tasks for project\")\n\tErrCollectionsProjectsNotFound\t= errors.New(\"Could not get projects for this collection\")\n\tErrCollectionsTasksNotFound\t\t= errors.New(\"Could not get tasks for this collection\")\n\tErrTaskIdAlreadyExists\t\t\t= errors.New(\"A task with the provided id already exists\")\n\tErrCollectionIdAlreadyExists\t= errors.New(\"A collection with the provided id already exists\")\n\tErrProjectIdAlreadyExists\t\t= errors.New(\"A project with the provided id already exists\")\n\tErrTaskByIdNotFound\t\t\t\t= errors.New(\"Can't get task by id\")\n\tErrProjectByIdNotFound\t\t\t= errors.New(\"Can't get project by id\")\n\tErrCollectionByIdNotFound\t\t= errors.New(\"Can't get collection by id\")\n\tErrTaskNotRemovable\t\t\t\t= errors.New(\"Cannot remove a task directly from this realm\")\n\tErrProjectNotRemovable\t\t\t= errors.New(\"Cannot remove a project directly from this realm\")\n\tErrProjectTasksNotRemoved\t\t= errors.New(\"Project tasks were not removed\")\n\tErrTaskNotRemoved\t\t\t\t= errors.New(\"Task was not removed\")\n\tErrTaskNotInAssessRealm\t\t\t= errors.New(\"Task is not in Assess, cannot edit Body\")\n\tErrProjectNotInAssessRealm\t\t= errors.New(\"Project is not in Assess, cannot edit Body\")\n\tErrContextIdAlreadyExists\t\t= errors.New(\"A context with the provided id already exists\")\n\tErrContextIdNotFound\t\t\t= errors.New(\"Context id not found\")\n\tErrCollectionIdNotFound\t\t\t= errors.New(\"Collection id not found\")\n\tErrContextNotRemoved\t\t\t= errors.New(\"Context was not removed\")\n\tErrProjectNotRemoved\t\t\t= errors.New(\"Project was not removed\")\n\tErrCollectionNotRemoved\t\t\t= errors.New(\"Collection was not removed\")\n\tErrObjectPathNotUpdated\t\t\t= errors.New(\"Object path wasn't updated\")\n\tErrInvalidateDateFormat\t\t\t= errors.New(\"Invalida date format\")\n\tErrInvalidDateFilterType\t\t= errors.New(\"Invalid date filter type\")\n\tErrRealmIdAlreadyExists\t\t\t= errors.New(\"A realm with the same id already exists\")\n\tErrRealmIdNotAllowed\t\t\t= errors.New(\"This is a reserved realm id\")\n\tErrRealmIdNotFound\t\t\t\t= errors.New(\"Realm id not found\")\n\tErrRealmNotRemoved\t\t\t\t= errors.New(\"Realm was not removed\")\n)" - }, - { - "name": "marshals.gno", - "body": "package zentasktic\n\nimport (\n\t\"bytes\"\n)\n\n\ntype ContextsObject struct {\n\tContexts\t[]Context\n}\n\ntype TasksObject struct {\n\tTasks\t[]Task\n}\n\ntype ProjectsObject struct {\n\tProjects\t[]Project\n}\n\ntype CollectionsObject struct {\n\tCollections\t[]Collection\n}\n\ntype RealmsObject struct {\n\tRealms\t[]Realm\n}\n\ntype ObjectJourney struct {\n\tObjectPaths []ObjectPath\n}\n\nfunc (c Context) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"contextId\":\"`)\n\tb.WriteString(c.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"contextName\":\"`)\n\tb.WriteString(c.Name)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (cs ContextsObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"contexts\":[`)\n\t\n\tfor i, context := range cs.Contexts {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tcontextJSON, cerr := context.MarshalJSON()\n\t\tif cerr == nil {\n\t\t\tb.WriteString(string(contextJSON))\n\t\t}\n\t}\n\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (t Task) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"taskId\":\"`)\n\tb.WriteString(t.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskProjectId\":\"`)\n\tb.WriteString(t.ProjectId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskContextId\":\"`)\n\tb.WriteString(t.ContextId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskRealmId\":\"`)\n\tb.WriteString(t.RealmId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskBody\":\"`)\n\tb.WriteString(t.Body)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskDue\":\"`)\n\tb.WriteString(t.Due)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskAlert\":\"`)\n\tb.WriteString(t.Alert)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (ts TasksObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"tasks\":[`)\n\tfor i, task := range ts.Tasks {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\ttaskJSON, cerr := task.MarshalJSON()\n\t\tif cerr == nil {\n\t\t\tb.WriteString(string(taskJSON))\n\t\t}\n\t}\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (p Project) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"projectId\":\"`)\n\tb.WriteString(p.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"projectContextId\":\"`)\n\tb.WriteString(p.ContextId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"projectRealmId\":\"`)\n\tb.WriteString(p.RealmId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"projectTasks\":[`)\n\n\tif len(p.Tasks) != 0 {\n\t\tfor i, projectTask := range p.Tasks {\n\t\t\tif i > 0 {\n\t\t\t\tb.WriteString(`,`)\n\t\t\t}\n\t\t\tprojectTaskJSON, perr := projectTask.MarshalJSON()\n\t\t\tif perr == nil {\n\t\t\t\tb.WriteString(string(projectTaskJSON))\n\t\t\t}\n\t\t}\n\t}\n\n\tb.WriteString(`],`)\n\n\tb.WriteString(`\"projectBody\":\"`)\n\tb.WriteString(p.Body)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"projectDue\":\"`)\n\tb.WriteString(p.Due)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (ps ProjectsObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"projects\":[`)\n\tfor i, project := range ps.Projects {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tprojectJSON, perr := project.MarshalJSON()\n\t\tif perr == nil {\n\t\t\tb.WriteString(string(projectJSON))\n\t\t}\n\t}\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (c Collection) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"collectionId\":\"`)\n\tb.WriteString(c.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"collectionRealmId\":\"`)\n\tb.WriteString(c.RealmId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"collectionName\":\"`)\n\tb.WriteString(c.Name)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"collectionTasks\":[`)\n\tfor i, collectionTask := range c.Tasks {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tcollectionTaskJSON, perr := collectionTask.MarshalJSON()\n\t\tif perr == nil {\n\t\t\tb.WriteString(string(collectionTaskJSON))\n\t\t}\n\t}\n\tb.WriteString(`],`)\n\n\tb.WriteString(`\"collectionProjects\":[`)\n\tfor i, collectionProject := range c.Projects {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tcollectionProjectJSON, perr := collectionProject.MarshalJSON()\n\t\tif perr == nil {\n\t\t\tb.WriteString(string(collectionProjectJSON))\n\t\t}\n\t}\n\tb.WriteString(`],`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (co CollectionsObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"collections\":[`)\n\tfor i, collection := range co.Collections {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tcollectionJSON, perr := collection.MarshalJSON()\n\t\tif perr == nil {\n\t\t\tb.WriteString(string(collectionJSON))\n\t\t}\n\t}\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (r Realm) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"realmId\":\"`)\n\tb.WriteString(r.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"realmName\":\"`)\n\tb.WriteString(r.Name)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (rs RealmsObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"realms\":[`)\n\t\n\tfor i, realm := range rs.Realms {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\trealmJSON, rerr := realm.MarshalJSON()\n\t\tif rerr == nil {\n\t\t\tb.WriteString(string(realmJSON))\n\t\t}\n\t}\n\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (op ObjectPath) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"objectType\":\"`)\n\tb.WriteString(op.ObjectType)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"id\":\"`)\n\tb.WriteString(op.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"realmId\":\"`)\n\tb.WriteString(op.RealmId)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (oj ObjectJourney) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"objectJourney\":[`)\n\t\n\tfor i, objectPath := range oj.ObjectPaths {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tobjectPathJSON, oerr := objectPath.MarshalJSON()\n\t\tif oerr == nil {\n\t\t\tb.WriteString(string(objectPathJSON))\n\t\t}\n\t}\n\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n" - }, - { - "name": "projects.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"time\"\n\n\t\"gno.land/p/demo/avl\"\n)\n\n\ntype Project struct {\n\tId \t\t\tstring `json:\"projectId\"`\n\tContextId\tstring `json:\"projectContextId\"`\n\tRealmId \tstring `json:\"projectRealmId\"`\n\tTasks\t\t[]Task `json:\"projectTasks\"`\n\tBody \t\tstring `json:\"projectBody\"`\n\tDue\t\t\tstring `json:\"projectDue\"`\n}\n\ntype ZProjectManager struct {\n\tProjects *avl.Tree // projectId -> Project\n\tProjectTasks *avl.Tree // projectId -> []Task\n}\n\n\nfunc NewZProjectManager() *ZProjectManager {\n\treturn &ZProjectManager{\n\t\tProjects: avl.NewTree(),\n\t\tProjectTasks: avl.NewTree(),\n\t}\n}\n\n// actions\n\nfunc (zpm *ZProjectManager) AddProject(p Project) (err error) {\n\t// implementation\n\n\tif zpm.Projects.Size() != 0 {\n\t\t_, exist := zpm.Projects.Get(p.Id)\n\t\tif exist {\n\t\t\treturn ErrProjectIdAlreadyExists\n\t\t}\n\t}\n\tzpm.Projects.Set(p.Id, p)\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) RemoveProject(p Project) (err error) {\n\t// implementation, remove from ProjectTasks too\n\texistingProjectInterface, exist := zpm.Projects.Get(p.Id)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\t // project is removable only in Asses (RealmId 1) or via a Collection (RealmId 4)\n\tif existingProject.RealmId != \"1\" && existingProject.RealmId != \"4\" {\n\t\treturn ErrProjectNotRemovable\n\t}\n\n\t_, removed := zpm.Projects.Remove(existingProject.Id)\n\tif !removed {\n\t\treturn ErrProjectNotRemoved\n\t}\n\n\t// manage project tasks, if any\n\n\tif zpm.ProjectTasks.Size() != 0 {\n\t\t_, exist := zpm.ProjectTasks.Get(existingProject.Id)\n\t\tif !exist {\n\t\t\t// if there's no record in ProjectTasks, we don't have to remove anything\n\t\t\treturn nil\n\t\t} else {\n\t\t\t_, removed := zpm.ProjectTasks.Remove(existingProject.Id)\n\t\t\tif !removed {\n\t\t\t\treturn ErrProjectTasksNotRemoved\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) EditProject(p Project) (err error) {\n\t// implementation, get project by Id and replace the object\n\t// this is for the project body and realm, project tasks are managed in the Tasks object\n\texistingProject := Project{}\n\tif zpm.Projects.Size() != 0 {\n\t\t_, exist := zpm.Projects.Get(p.Id)\n\t\tif !exist {\n\t\t\treturn ErrProjectIdNotFound\n\t\t}\n\t}\n\t\n\t// project Body is editable only when project is in Assess, RealmId = \"1\"\n\tif p.RealmId != \"1\" {\n\t\tif p.Body != existingProject.Body {\n\t\t\treturn ErrProjectNotInAssessRealm\n\t\t}\n\t}\n\n\tzpm.Projects.Set(p.Id, p)\n\treturn nil\n}\n\n// helper function, we can achieve the same with EditProject() above\n/*func (zpm *ZProjectManager) MoveProjectToRealm(projectId string, realmId string) (err error) {\n\t// implementation\n\texistingProjectInterface, exist := zpm.Projects.Get(projectId)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\texistingProject.RealmId = realmId\n\tzpm.Projects.Set(projectId, existingProject)\n\treturn nil\n}*/\n\nfunc (zpm *ZProjectManager) MoveProjectToRealm(projectId string, realmId string) error {\n\t// Get the existing project from the Projects map\n\texistingProjectInterface, exist := zpm.Projects.Get(projectId)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\t// Set the project's RealmId to the new RealmId\n\texistingProject.RealmId = realmId\n\n\t// Get the existing project tasks from the ProjectTasks map\n\texistingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n\tif !texist {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\ttasks, ok := existingProjectTasksInterface.([]Task)\n\tif !ok {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\n\t// Iterate through the project's tasks and set their RealmId to the new RealmId\n\tfor i := range tasks {\n\t\ttasks[i].RealmId = realmId\n\t}\n\n\t// Set the updated tasks back into the ProjectTasks map\n\tzpm.ProjectTasks.Set(projectId, tasks)\n\n\t// Set the updated project back into the Projects map\n\tzpm.Projects.Set(projectId, existingProject)\n\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) MarkProjectTaskAsDone(projectId string, projectTaskId string) error {\n // Get the existing project from the Projects map\n existingProjectInterface, exist := zpm.Projects.Get(projectId)\n if !exist {\n return ErrProjectIdNotFound\n }\n existingProject := existingProjectInterface.(Project)\n\n // Get the existing project tasks from the ProjectTasks map\n existingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n if !texist {\n return ErrProjectTasksNotFound\n }\n tasks, ok := existingProjectTasksInterface.([]Task)\n if !ok {\n return ErrProjectTasksNotFound\n }\n\n // Iterate through the project's tasks to find the task to be updated\n var taskFound bool\n for i, task := range tasks {\n if task.Id == projectTaskId {\n tasks[i].RealmId = \"4\" // Change the RealmId to \"4\"\n taskFound = true\n break\n }\n }\n\n if !taskFound {\n return ErrTaskByIdNotFound\n }\n\n // Set the updated tasks back into the ProjectTasks map\n zpm.ProjectTasks.Set(existingProject.Id, tasks)\n\n return nil\n}\n\n\nfunc (zpm *ZProjectManager) GetProjectTasks(p Project) (tasks []Task, err error) {\n\t// implementation, query ProjectTasks and return the []Tasks object\n\tvar existingProjectTasks []Task\n\n\tif zpm.ProjectTasks.Size() != 0 {\n\t\tprojectTasksInterface, exist := zpm.ProjectTasks.Get(p.Id)\n\t\tif !exist {\n\t\t\treturn nil, ErrProjectTasksNotFound\n\t\t}\n\t\texistingProjectTasks = projectTasksInterface.([]Task)\n\t\treturn existingProjectTasks, nil\n\t}\n\treturn nil, nil\n}\n\nfunc (zpm *ZProjectManager) SetProjectDueDate(projectId string, dueDate string) (err error) {\n\tprojectInterface, exist := zpm.Projects.Get(projectId)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\tproject := projectInterface.(Project)\n\n\t// check to see if project is in RealmId = 2 (Decide)\n\tif project.RealmId == \"2\" {\n\t\tproject.Due = dueDate\n\t\tzpm.Projects.Set(project.Id, project)\n\t} else {\n\t\treturn ErrProjectNotEditable\n\t}\n\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) SetProjectTaskDueDate(projectId string, projectTaskId string, dueDate string) (err error){\n\texistingProjectInterface, exist := zpm.Projects.Get(projectId)\n if !exist {\n return ErrProjectIdNotFound\n }\n existingProject := existingProjectInterface.(Project)\n\n\tif existingProject.RealmId != \"2\" {\n\t\treturn ErrProjectNotEditable\n\t}\n\n existingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n if !texist {\n return ErrProjectTasksNotFound\n }\n tasks, ok := existingProjectTasksInterface.([]Task)\n if !ok {\n return ErrProjectTasksNotFound\n }\n existingProject.Tasks = tasks\n\n var index int = -1\n for i, task := range existingProject.Tasks {\n if task.Id == projectTaskId {\n index = i\n break\n }\n }\n\n if index != -1 {\n existingProject.Tasks[index].Due = dueDate\n } else {\n return ErrTaskByIdNotFound\n }\n\n zpm.ProjectTasks.Set(projectId, existingProject.Tasks)\n return nil\n}\n\n// getters\n\nfunc (zpm *ZProjectManager) GetProjectById(projectId string) (Project, error) {\n\tif zpm.Projects.Size() != 0 {\n\t\tpInterface, exist := zpm.Projects.Get(projectId)\n\t\tif exist {\n\t\t\treturn pInterface.(Project), nil\n\t\t}\n\t}\n\treturn Project{}, ErrProjectIdNotFound\n}\n\nfunc (zpm *ZProjectManager) GetAllProjects() (projects string) {\n\t// implementation\n\tvar allProjects []Project\n\t\n\t// Iterate over the Projects AVL tree to collect all Project objects.\n\t\n\tzpm.Projects.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif project, ok := value.(Project); ok {\n\t\t\t// get project tasks, if any\n\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\tif projectTasks != nil {\n\t\t\t\tproject.Tasks = projectTasks\n\t\t\t}\n\t\t\tallProjects = append(allProjects, project)\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a ProjectsObject with all collected tasks.\n\tprojectsObject := ProjectsObject{\n\t\tProjects: allProjects,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledProjects, merr := projectsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledProjects)\n}\n\nfunc (zpm *ZProjectManager) GetProjectsByRealm(realmId string) (projects string) {\n\t// implementation\n\tvar realmProjects []Project\n\t\n\t// Iterate over the Projects AVL tree to collect all Project objects.\n\t\n\tzpm.Projects.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif project, ok := value.(Project); ok {\n\t\t\tif project.RealmId == realmId {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\trealmProjects = append(realmProjects, project)\n\t\t\t}\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a ProjectsObject with all collected tasks.\n\tprojectsObject := ProjectsObject{\n\t\tProjects: realmProjects,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledProjects, merr := projectsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledProjects)\n}\n\nfunc (zpm *ZProjectManager) GetProjectsByContextAndRealm(contextId string, realmId string) (projects string) {\n\t// implementation\n\tvar contextProjects []Project\n\t\n\t// Iterate over the Projects AVL tree to collect all Project objects.\n\t\n\tzpm.Projects.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif project, ok := value.(Project); ok {\n\t\t\tif project.ContextId == contextId && project.RealmId == realmId {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\tcontextProjects = append(contextProjects, project)\n\t\t\t}\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a ProjectsObject with all collected tasks.\n\tprojectsObject := ProjectsObject{\n\t\tProjects: contextProjects,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledProjects, merr := projectsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledProjects)\n}\n\nfunc (zpm *ZProjectManager) GetProjectsByDate(projectDate string, filterType string) (projects string) {\n\t// implementation\n\tparsedDate, err:= time.Parse(\"2006-01-02\", projectDate)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\tvar filteredProjects []Project\n\t\n\tzpm.Projects.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tproject, ok := value.(Project)\n\t\tif !ok {\n\t\t\treturn false // Skip this iteration and continue.\n\t\t}\n\n\t\tstoredDate, serr := time.Parse(\"2006-01-02\", project.Due)\n\t\tif serr != nil {\n\t\t\t// Skip projects with invalid dates.\n\t\t\treturn false\n\t\t}\n\n\t\tswitch filterType {\n\t\tcase \"specific\":\n\t\t\tif storedDate.Format(\"2006-01-02\") == parsedDate.Format(\"2006-01-02\") {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\tfilteredProjects = append(filteredProjects, project)\n\t\t\t}\n\t\tcase \"before\":\n\t\t\tif storedDate.Before(parsedDate) {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\tfilteredProjects = append(filteredProjects, project)\n\t\t\t}\n\t\tcase \"after\":\n\t\t\tif storedDate.After(parsedDate) {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\tfilteredProjects = append(filteredProjects, project)\n\t\t\t}\n\t\t}\n\n\t\treturn false // Continue iteration.\n\t})\n\n\tif len(filteredProjects) == 0 {\n\t\treturn \"\"\n\t}\n\n\t// Create a ProjectsObject with all collected tasks.\n\tprojectsObject := ProjectsObject{\n\t\tProjects: filteredProjects,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledProjects, merr := projectsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledProjects)\n\n}\n" - }, - { - "name": "projects_test.gno", - "body": "package zentasktic\n\nimport (\n\t\"testing\"\n\n \"gno.land/p/demo/avl\"\n)\n/*\nfunc Test_AddProject(t *testing.T) {\n \n project := Project{Id: \"1\", RealmId: \"1\", Body: \"First project\", ContextId: \"1\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n\n // Test adding a duplicate project.\n cerr := project.AddProject()\n if cerr != ErrProjectIdAlreadyExists {\n t.Errorf(\"Expected ErrProjectIdAlreadyExists, got %v\", cerr)\n }\n}\n\n\nfunc Test_RemoveProject(t *testing.T) {\n \n project := Project{Id: \"20\", Body: \"Removable project\", RealmId: \"1\", ContextId: \"2\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n\n retrievedProject, rerr := GetProjectById(project.Id)\n if rerr != nil {\n t.Errorf(\"Could not retrieve the added project\")\n }\n\n // Test removing a project\n terr := retrievedProject.RemoveProject()\n if terr != ErrProjectNotRemoved {\n t.Errorf(\"Expected ErrProjectNotRemoved, got %v\", terr)\n }\n}\n\n\nfunc Test_EditProject(t *testing.T) {\n \n project := Project{Id: \"2\", Body: \"Second project content\", RealmId: \"1\", ContextId: \"2\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n\n // Test editing the project\n editedProject := Project{Id: project.Id, Body: \"Edited project content\", RealmId: project.RealmId, ContextId: \"2\",}\n cerr := editedProject.EditProject()\n if cerr != nil {\n t.Errorf(\"Failed to edit the project\")\n }\n\n retrievedProject, _ := GetProjectById(editedProject.Id)\n if retrievedProject.Body != \"Edited project content\" {\n t.Errorf(\"Project was not edited\")\n }\n}\n\n\nfunc Test_MoveProjectToRealm(t *testing.T) {\n \n project := Project{Id: \"3\", Body: \"Project id 3 content\", RealmId: \"1\", ContextId: \"1\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n\n // Test moving the project to another realm\n \n cerr := project.MoveProjectToRealm(\"2\")\n if cerr != nil {\n t.Errorf(\"Failed to move project to another realm\")\n }\n\n retrievedProject, _ := GetProjectById(project.Id)\n if retrievedProject.RealmId != \"2\" {\n t.Errorf(\"Project was moved to the wrong realm\")\n }\n}\n\nfunc Test_SetProjectDueDate(t *testing.T) {\n\tprojectRealmIdOne, _ := GetProjectById(\"1\")\n projectRealmIdTwo, _ := GetProjectById(\"10\") \n\t// Define test cases\n\ttests := []struct {\n\t\tname string\n\t\tproject Project\n\t\tdueDate string\n\t\twantErr error\n\t}{\n\t\t{\n\t\t\tname: \"Project does not exist\",\n\t\t\tproject: Project{Id: \"nonexistent\", RealmId: \"2\"},\n\t\t\twantErr: ErrProjectIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Project not editable due to wrong realm\",\n\t\t\tproject: projectRealmIdOne,\n\t\t\twantErr: ErrProjectNotEditable,\n\t\t},\n\t\t{\n\t\t\tname: \"Successfully set alert\",\n\t\t\tproject: projectRealmIdTwo,\n\t\t\tdueDate: \"2024-01-01\",\n\t\t\twantErr: nil,\n\t\t},\n\t}\n\n\t// Execute test cases\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.project.SetProjectDueDate(tc.dueDate)\n\n\t\t\t// Validate\n\t\t\tif err != tc.wantErr {\n\t\t\t\tt.Errorf(\"Expected error %v, got %v\", tc.wantErr, err)\n\t\t\t}\n\n\t\t\t// Additional check for the success case to ensure the due date was actually set\n\t\t\tif err == nil {\n\t\t\t\t// Fetch the task again to check if the due date was set correctly\n\t\t\t\tupdatedProject, exist := Projects.Get(tc.project.Id)\n\t\t\t\tif !exist {\n\t\t\t\t\tt.Fatalf(\"Project %v was not found after setting the due date\", tc.project.Id)\n\t\t\t\t}\n\t\t\t\tif updatedProject.(Project).Due != tc.dueDate {\n\t\t\t\t\tt.Errorf(\"Expected due date to be %v, got %v\", tc.dueDate, updatedProject.(Project).Due)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\n// getters\n\nfunc Test_GetAllProjects(t *testing.T) {\n \n // mocking the tasks based on previous tests\n // TODO: add isolation?\n knownProjects := []Project{\n {Id: \"1\", Body: \"First project\", RealmId: \"1\", ContextId: \"1\",},\n {Id: \"10\", Body: \"Project 10\", RealmId: \"2\", ContextId: \"2\", Due: \"2024-01-01\"},\n\t\t{Id: \"2\", Body: \"Edited project content\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"20\", Body: \"Removable project\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"21\", Body: \"Project 21\", RealmId: \"1\",},\n {Id: \"22\", Body: \"Project 22\", RealmId: \"1\",},\n\t\t{Id: \"3\", Body: \"Project id 3 content\", RealmId: \"2\", ContextId: \"1\",},\n }\n\n // Manually marshal the known projects to create the expected outcome.\n projectsObject := ProjectsObject{Projects: knownProjects}\n expected, err := projectsObject.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal known projects: %v\", err)\n }\n\n // Execute GetAllProjects() to get the actual outcome.\n actual, err := GetAllProjects()\n if err != nil {\n t.Fatalf(\"GetAllProjects() failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual project JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n\nfunc Test_GetProjectsByDate(t *testing.T) {\n\t\n\ttests := []struct {\n\t\tname string\n\t\tprojectDate string\n\t\tfilterType string\n\t\twant string\n\t\twantErr bool\n\t}{\n\t\t{\"SpecificDate\", \"2024-01-01\", \"specific\", `{\"projects\":[{\"projectId\":\"10\",\"projectContextId\":\"2\",\"projectRealmId\":\"2\",\"projectTasks\":[],\"projectBody\":\"Project 10\",\"projectDue\":\"2024-01-01\"}]}`, false},\n\t\t{\"BeforeDate\", \"2022-04-05\", \"before\", \"\", false},\n\t\t{\"AfterDate\", \"2025-04-05\", \"after\", \"\", false},\n\t\t{\"NoMatch\", \"2002-04-07\", \"specific\", \"\", false},\n\t\t{\"InvalidDateFormat\", \"April 5, 2023\", \"specific\", \"\", true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := GetProjectsByDate(tt.projectDate, tt.filterType)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"GetProjectsByDate() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err == nil && got != tt.want {\n\t\t\t\tt.Errorf(\"GetProjectsByDate() got = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_GetProjectTasks(t *testing.T){\n \n task := Task{Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",}\n\n project, perr := GetProjectById(\"1\")\n if perr != nil {\n t.Errorf(\"GetProjectById() failed, %v\", perr)\n }\n\n // test attaching to an existing project\n atterr := task.AttachTaskToProject(project)\n if atterr != nil {\n t.Errorf(\"AttachTaskToProject() failed, %v\", atterr)\n }\n\n projectTasks, pterr := project.GetProjectTasks()\n if len(projectTasks) == 0 {\n t.Errorf(\"GetProjectTasks() failed, %v\", pterr)\n }\n\n // test detaching from an existing project\n dtterr := task.DetachTaskFromProject(project)\n if dtterr != nil {\n t.Errorf(\"DetachTaskFromProject() failed, %v\", dtterr)\n }\n\n projectWithNoTasks, pterr := project.GetProjectTasks()\n if len(projectWithNoTasks) != 0 {\n t.Errorf(\"GetProjectTasks() after detach failed, %v\", pterr)\n }\n}\n\nfunc Test_GetProjectById(t *testing.T){\n // test getting a non-existing project\n nonProject, err := GetProjectById(\"0\")\n if err != ErrProjectByIdNotFound {\n t.Fatalf(\"Expected ErrProjectByIdNotFound, got: %v\", err)\n }\n\n // test getting the correct task by id\n correctProject, err := GetProjectById(\"1\")\n if err != nil {\n t.Fatalf(\"Failed to get project by id, error: %v\", err)\n }\n\n if correctProject.Body != \"First project\" {\n t.Fatalf(\"Got the wrong project, with body: %v\", correctProject.Body)\n }\n}\n\nfunc Test_GetProjectsByRealm(t *testing.T) {\n \n // mocking the projects based on previous tests\n // TODO: add isolation?\n projectsInAssessRealm := []Project{\n {Id: \"1\", Body: \"First project\", RealmId: \"1\", ContextId: \"1\",},\n\t\t{Id: \"2\", Body: \"Edited project content\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"20\", Body: \"Removable project\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"21\", Body: \"Project 21\", RealmId: \"1\",},\n {Id: \"22\", Body: \"Project 22\", RealmId: \"1\",},\n }\n\n // Manually marshal the known projects to create the expected outcome.\n projectsObjectAssess := ProjectsObject{Projects: projectsInAssessRealm}\n expected, err := projectsObjectAssess.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal projects in Assess: %v\", err)\n }\n\n actual, err := GetProjectsByRealm(\"1\")\n if err != nil {\n t.Fatalf(\"GetProjectByRealm('1') failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual projects JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n\nfunc Test_GetProjectsByContext(t *testing.T) {\n \n // mocking the projects based on previous tests\n // TODO: add isolation?\n projectsInContextOne := []Project{\n {Id: \"1\", Body: \"First project\", RealmId: \"1\", ContextId: \"1\",},\n\t\t{Id: \"3\", Body: \"Project id 3 content\", RealmId: \"2\", ContextId: \"1\",},\n }\n\n // Manually marshal the known tasks to create the expected outcome.\n projectsObjectForContexts := ProjectsObject{Projects: projectsInContextOne}\n expected, err := projectsObjectForContexts.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal projects for ContextId 1: %v\", err)\n }\n\n actual, err := GetProjectsByContext(\"1\")\n if err != nil {\n t.Fatalf(\"GetProjectsByContext('1') failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual project JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n*/\n\n" - }, - { - "name": "realms.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"gno.land/p/demo/avl\"\n)\n\n// structs\n\ntype Realm struct {\n\tId \t\t\tstring `json:\"realmId\"`\n\tName \t\tstring `json:\"realmName\"`\n}\n\ntype ZRealmManager struct {\n\tRealms *avl.Tree\n}\n\nfunc NewZRealmManager() *ZRealmManager {\n\tzrm := &ZRealmManager{\n\t\tRealms: avl.NewTree(),\n\t}\n\tzrm.initializeHardcodedRealms()\n\treturn zrm\n}\n\n\nfunc (zrm *ZRealmManager) initializeHardcodedRealms() {\n\thardcodedRealms := []Realm{\n\t\t{Id: \"1\", Name: \"Assess\"},\n\t\t{Id: \"2\", Name: \"Decide\"},\n\t\t{Id: \"3\", Name: \"Do\"},\n\t\t{Id: \"4\", Name: \"Collections\"},\n\t}\n\n\tfor _, realm := range hardcodedRealms {\n\t\tzrm.Realms.Set(realm.Id, realm)\n\t}\n}\n\n\nfunc (zrm *ZRealmManager) AddRealm(r Realm) (err error){\n\t// implementation\n\tif zrm.Realms.Size() != 0 {\n\t\t_, exist := zrm.Realms.Get(r.Id)\n\t\tif exist {\n\t\t\treturn ErrRealmIdAlreadyExists\n\t\t}\n\t}\n\t// check for hardcoded values\n\tif r.Id == \"1\" || r.Id == \"2\" || r.Id == \"3\" || r.Id == \"4\" {\n\t\treturn ErrRealmIdNotAllowed\n\t}\n\tzrm.Realms.Set(r.Id, r)\n\treturn nil\n\t\n}\n\nfunc (zrm *ZRealmManager) RemoveRealm(r Realm) (err error){\n\t// implementation\n\tif zrm.Realms.Size() != 0 {\n\t\t_, exist := zrm.Realms.Get(r.Id)\n\t\tif !exist {\n\t\t\treturn ErrRealmIdNotFound\n\t\t} else {\n\t\t\t// check for hardcoded values, not removable\n\t\t\tif r.Id == \"1\" || r.Id == \"2\" || r.Id == \"3\" || r.Id == \"4\" {\n\t\t\t\treturn ErrRealmIdNotAllowed\n\t\t\t}\n\t\t}\n\t}\n\t\n\t_, removed := zrm.Realms.Remove(r.Id)\n\tif !removed {\n\t\treturn ErrRealmNotRemoved\n\t}\n\treturn nil\n\t\n}\n\n// getters\nfunc (zrm *ZRealmManager) GetRealmById(realmId string) (r Realm, err error) {\n\t// implementation\n\tif zrm.Realms.Size() != 0 {\n\t\trInterface, exist := zrm.Realms.Get(realmId)\n\t\tif exist {\n\t\t\treturn rInterface.(Realm), nil\n\t\t} else {\n\t\t\treturn Realm{}, ErrRealmIdNotFound\n\t\t}\n\t}\n\treturn Realm{}, ErrRealmIdNotFound\n}\n\nfunc (zrm *ZRealmManager) GetRealms() (realms string, err error) {\n\t// implementation\n\tvar allRealms []Realm\n\n\t// Iterate over the Realms AVL tree to collect all Context objects.\n\tzrm.Realms.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif realm, ok := value.(Realm); ok {\n\t\t\tallRealms = append(allRealms, realm)\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\n\t// Create a RealmsObject with all collected contexts.\n\trealmsObject := &RealmsObject{\n\t\tRealms: allRealms,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the realms into JSON.\n\tmarshalledRealms, rerr := realmsObject.MarshalJSON()\n\tif rerr != nil {\n\t\treturn \"\", rerr\n\t} \n\treturn string(marshalledRealms), nil\n}\n" - }, - { - "name": "tasks.gno", - "body": "package zentasktic\n\nimport (\n\t\"time\"\n\n\t\"gno.land/p/demo/avl\"\n)\n\ntype Task struct {\n\tId \t\t\tstring `json:\"taskId\"`\n\tProjectId \tstring `json:\"taskProjectId\"`\n\tContextId\tstring `json:\"taskContextId\"`\n\tRealmId \tstring `json:\"taskRealmId\"`\n\tBody \t\tstring `json:\"taskBody\"`\n\tDue\t\t\tstring `json:\"taskDue\"`\n\tAlert\t\tstring `json:\"taskAlert\"`\n}\n\ntype ZTaskManager struct {\n\tTasks *avl.Tree\n}\n\nfunc NewZTaskManager() *ZTaskManager {\n\treturn &ZTaskManager{\n\t\tTasks: avl.NewTree(),\n\t}\n}\n\n// actions\n\nfunc (ztm *ZTaskManager) AddTask(t Task) error {\n\tif ztm.Tasks.Size() != 0 {\n\t\t_, exist := ztm.Tasks.Get(t.Id)\n\t\tif exist {\n\t\t\treturn ErrTaskIdAlreadyExists\n\t\t}\n\t}\n\tztm.Tasks.Set(t.Id, t)\n\treturn nil\n}\n\nfunc (ztm *ZTaskManager) RemoveTask(t Task) error {\n\texistingTaskInterface, exist := ztm.Tasks.Get(t.Id)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\texistingTask := existingTaskInterface.(Task)\n\n\t // task is removable only in Asses (RealmId 1) or via a Collection (RealmId 4)\n\tif existingTask.RealmId != \"1\" && existingTask.RealmId != \"4\" {\n\t\treturn ErrTaskNotRemovable\n\t}\n\n\t_, removed := ztm.Tasks.Remove(existingTask.Id)\n\tif !removed {\n\t\treturn ErrTaskNotRemoved\n\t}\n\treturn nil\n}\n\nfunc (ztm *ZTaskManager) EditTask(t Task) error {\n\texistingTaskInterface, exist := ztm.Tasks.Get(t.Id)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\texistingTask := existingTaskInterface.(Task)\n\n\t// task Body is editable only when task is in Assess, RealmId = \"1\"\n\tif t.RealmId != \"1\" {\n\t\tif t.Body != existingTask.Body {\n\t\t\treturn ErrTaskNotInAssessRealm\n\t\t}\n\t}\n\n\tztm.Tasks.Set(t.Id, t)\n\treturn nil\n}\n\n// Helper function to move a task to a different realm\nfunc (ztm *ZTaskManager) MoveTaskToRealm(taskId, realmId string) error {\n\texistingTaskInterface, exist := ztm.Tasks.Get(taskId)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\texistingTask := existingTaskInterface.(Task)\n\texistingTask.RealmId = realmId\n\tztm.Tasks.Set(taskId, existingTask)\n\treturn nil\n}\n\nfunc (ztm *ZTaskManager) SetTaskDueDate(taskId, dueDate string) error {\n\ttaskInterface, exist := ztm.Tasks.Get(taskId)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\ttask := taskInterface.(Task)\n\n\tif task.RealmId == \"2\" {\n\t\ttask.Due = dueDate\n\t\tztm.Tasks.Set(task.Id, task)\n\t} else {\n\t\treturn ErrTaskNotEditable\n\t}\n\n\treturn nil\n}\n\nfunc (ztm *ZTaskManager) SetTaskAlert(taskId, alertDate string) error {\n\ttaskInterface, exist := ztm.Tasks.Get(taskId)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\ttask := taskInterface.(Task)\n\n\tif task.RealmId == \"2\" {\n\t\ttask.Alert = alertDate\n\t\tztm.Tasks.Set(task.Id, task)\n\t} else {\n\t\treturn ErrTaskNotEditable\n\t}\n\n\treturn nil\n}\n\n// tasks & projects association\n\nfunc (zpm *ZProjectManager) AttachTaskToProject(ztm *ZTaskManager, t Task, p Project) error {\n\texistingProjectInterface, exist := zpm.Projects.Get(p.Id)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\texistingProjectTasksInterface, texist := zpm.ProjectTasks.Get(p.Id)\n\tif !texist {\n\t\texistingProject.Tasks = []Task{}\n\t} else {\n\t\ttasks, ok := existingProjectTasksInterface.([]Task)\n\t\tif !ok {\n\t\t\treturn ErrProjectTasksNotFound\n\t\t}\n\t\texistingProject.Tasks = tasks\n\t}\n\n\tt.ProjectId = p.Id\n\t// @todo we need to remove it from Tasks if it was previously added there, then detached\n\texistingTask, err := ztm.GetTaskById(t.Id)\n\tif err == nil {\n\t\tztm.RemoveTask(existingTask)\n\t}\n\tupdatedTasks := append(existingProject.Tasks, t)\n\tzpm.ProjectTasks.Set(p.Id, updatedTasks)\n\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) EditProjectTask(projectTaskId string, projectTaskBody string, projectId string) error {\n existingProjectInterface, exist := zpm.Projects.Get(projectId)\n if !exist {\n return ErrProjectIdNotFound\n }\n existingProject := existingProjectInterface.(Project)\n\n\tif existingProject.RealmId != \"1\" {\n\t\treturn ErrProjectNotEditable\n\t}\n\n existingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n if !texist {\n return ErrProjectTasksNotFound\n }\n tasks, ok := existingProjectTasksInterface.([]Task)\n if !ok {\n return ErrProjectTasksNotFound\n }\n existingProject.Tasks = tasks\n\n var index int = -1\n for i, task := range existingProject.Tasks {\n if task.Id == projectTaskId {\n index = i\n break\n }\n }\n\n if index != -1 {\n existingProject.Tasks[index].Body = projectTaskBody\n } else {\n return ErrTaskByIdNotFound\n }\n\n zpm.ProjectTasks.Set(projectId, existingProject.Tasks)\n return nil\n}\n\nfunc (zpm *ZProjectManager) DetachTaskFromProject(ztm *ZTaskManager, projectTaskId string, detachedTaskId string, p Project) error {\n\texistingProjectInterface, exist := zpm.Projects.Get(p.Id)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\texistingProjectTasksInterface, texist := zpm.ProjectTasks.Get(p.Id)\n\tif !texist {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\ttasks, ok := existingProjectTasksInterface.([]Task)\n\tif !ok {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\texistingProject.Tasks = tasks\n\n\tvar foundTask Task\n\tvar index int = -1\n\tfor i, task := range existingProject.Tasks {\n\t\tif task.Id == projectTaskId {\n\t\t\tindex = i\n\t\t\tfoundTask = task\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif index != -1 {\n\t\texistingProject.Tasks = append(existingProject.Tasks[:index], existingProject.Tasks[index+1:]...)\n\t} else {\n\t\treturn ErrTaskByIdNotFound\n\t}\n\n\tfoundTask.ProjectId = \"\"\n\tfoundTask.Id = detachedTaskId\n\t// Tasks and ProjectTasks have different storage, if a task is detached from a Project\n\t// we add it to the Tasks storage\n\tif err := ztm.AddTask(foundTask); err != nil {\n\t\treturn err\n\t}\n\n\tzpm.ProjectTasks.Set(p.Id, existingProject.Tasks)\n\treturn nil\n}\n\n\nfunc (zpm *ZProjectManager) RemoveTaskFromProject(projectTaskId string, projectId string) error {\n\texistingProjectInterface, exist := zpm.Projects.Get(projectId)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\texistingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n\tif !texist {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\ttasks, ok := existingProjectTasksInterface.([]Task)\n\tif !ok {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\texistingProject.Tasks = tasks\n\n\tvar index int = -1\n\tfor i, task := range existingProject.Tasks {\n\t\tif task.Id == projectTaskId {\n\t\t\tindex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif index != -1 {\n\t\texistingProject.Tasks = append(existingProject.Tasks[:index], existingProject.Tasks[index+1:]...)\n\t} else {\n\t\treturn ErrTaskByIdNotFound\n\t}\n\n\tzpm.ProjectTasks.Set(projectId, existingProject.Tasks)\n\treturn nil\n}\n\n// getters\n\nfunc (ztm *ZTaskManager) GetTaskById(taskId string) (Task, error) {\n\tif ztm.Tasks.Size() != 0 {\n\t\ttInterface, exist := ztm.Tasks.Get(taskId)\n\t\tif exist {\n\t\t\treturn tInterface.(Task), nil\n\t\t}\n\t}\n\treturn Task{}, ErrTaskIdNotFound\n}\n\nfunc (ztm *ZTaskManager) GetAllTasks() (task string) {\n\tvar allTasks []Task\n\n\tztm.Tasks.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif task, ok := value.(Task); ok {\n\t\t\tallTasks = append(allTasks, task)\n\t\t}\n\t\treturn false\n\t})\n\t// Create a TasksObject with all collected tasks.\n\ttasksObject := &TasksObject{\n\t\tTasks: allTasks,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledTasks, merr := tasksObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledTasks)\t\n}\n\nfunc (ztm *ZTaskManager) GetTasksByRealm(realmId string) (tasks string) {\n\tvar realmTasks []Task\n\n\tztm.Tasks.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif task, ok := value.(Task); ok {\n\t\t\tif task.RealmId == realmId {\n\t\t\t\trealmTasks = append(realmTasks, task)\n\t\t\t}\n\t\t}\n\t\treturn false\n\t})\n\n\t// Create a TasksObject with all collected tasks.\n\ttasksObject := &TasksObject{\n\t\tTasks: realmTasks,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledTasks, merr := tasksObject.MarshalJSON()\n\tif merr != nil {\n\t\t\treturn \"\"\n\t} \n\treturn string(marshalledTasks)\n}\n\nfunc (ztm *ZTaskManager) GetTasksByContextAndRealm(contextId string, realmId string) (tasks string) {\n\tvar contextTasks []Task\n\n\tztm.Tasks.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif task, ok := value.(Task); ok {\n\t\t\tif task.ContextId == contextId && task.ContextId == realmId {\n\t\t\t\tcontextTasks = append(contextTasks, task)\n\t\t\t}\n\t\t}\n\t\treturn false\n\t})\n\n\t// Create a TasksObject with all collected tasks.\n\ttasksObject := &TasksObject{\n\t\tTasks: contextTasks,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledTasks, merr := tasksObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledTasks)\n}\n\nfunc (ztm *ZTaskManager) GetTasksByDate(taskDate string, filterType string) (tasks string) {\n\tparsedDate, err := time.Parse(\"2006-01-02\", taskDate)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\tvar filteredTasks []Task\n\n\tztm.Tasks.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\ttask, ok := value.(Task)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\n\t\tstoredDate, serr := time.Parse(\"2006-01-02\", task.Due)\n\t\tif serr != nil {\n\t\t\treturn false\n\t\t}\n\n\t\tswitch filterType {\n\t\tcase \"specific\":\n\t\t\tif storedDate.Format(\"2006-01-02\") == parsedDate.Format(\"2006-01-02\") {\n\t\t\t\tfilteredTasks = append(filteredTasks, task)\n\t\t\t}\n\t\tcase \"before\":\n\t\t\tif storedDate.Before(parsedDate) {\n\t\t\t\tfilteredTasks = append(filteredTasks, task)\n\t\t\t}\n\t\tcase \"after\":\n\t\t\tif storedDate.After(parsedDate) {\n\t\t\t\tfilteredTasks = append(filteredTasks, task)\n\t\t\t}\n\t\t}\n\n\t\treturn false\n\t})\n\n\t// Create a TasksObject with all collected tasks.\n\ttasksObject := &TasksObject{\n\t\tTasks: filteredTasks,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledTasks, merr := tasksObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledTasks)\n}\n" - }, - { - "name": "tasks_test.gno", - "body": "package zentasktic\n\nimport (\n\t\"testing\"\n\n \"gno.land/p/demo/avl\"\n)\n\n// Shared instance of ZTaskManager\nvar ztm *ZTaskManager\n\nfunc init() {\n ztm = NewZTaskManager()\n}\n\nfunc Test_AddTask(t *testing.T) {\n task := Task{Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",}\n\n // Test adding a task successfully.\n err := ztm.AddTask(task)\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n\n // Test adding a duplicate task.\n cerr := ztm.AddTask(task)\n if cerr != ErrTaskIdAlreadyExists {\n t.Errorf(\"Expected ErrTaskIdAlreadyExists, got %v\", cerr)\n }\n}\n\nfunc Test_RemoveTask(t *testing.T) {\n \n task := Task{Id: \"20\", Body: \"Removable task\", RealmId: \"1\"}\n\n // Test adding a task successfully.\n err := ztm.AddTask(task)\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n\n retrievedTask, rerr := ztm.GetTaskById(task.Id)\n if rerr != nil {\n t.Errorf(\"Could not retrieve the added task\")\n }\n\n // Test removing a task\n terr := ztm.RemoveTask(retrievedTask)\n if terr != nil {\n t.Errorf(\"Expected nil, got %v\", terr)\n }\n}\n\nfunc Test_EditTask(t *testing.T) {\n \n task := Task{Id: \"2\", Body: \"First content\", RealmId: \"1\", ContextId: \"2\"}\n\n // Test adding a task successfully.\n err := ztm.AddTask(task)\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n\n // Test editing the task\n editedTask := Task{Id: task.Id, Body: \"Edited content\", RealmId: task.RealmId, ContextId: \"2\"}\n cerr := ztm.EditTask(editedTask)\n if cerr != nil {\n t.Errorf(\"Failed to edit the task\")\n }\n\n retrievedTask, _ := ztm.GetTaskById(editedTask.Id)\n if retrievedTask.Body != \"Edited content\" {\n t.Errorf(\"Task was not edited\")\n }\n}\n/*\nfunc Test_MoveTaskToRealm(t *testing.T) {\n \n task := Task{Id: \"3\", Body: \"First content\", RealmId: \"1\", ContextId: \"1\"}\n\n // Test adding a task successfully.\n err := task.AddTask()\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n\n // Test moving the task to another realm\n \n cerr := task.MoveTaskToRealm(\"2\")\n if cerr != nil {\n t.Errorf(\"Failed to move task to another realm\")\n }\n\n retrievedTask, _ := GetTaskById(task.Id)\n if retrievedTask.RealmId != \"2\" {\n t.Errorf(\"Task was moved to the wrong realm\")\n }\n}\n\nfunc Test_AttachTaskToProject(t *testing.T) {\n \n // Example Projects and Tasks\n prj := Project{Id: \"1\", Body: \"Project 1\", RealmId: \"1\",}\n tsk := Task{Id: \"4\", Body: \"Task 4\", RealmId: \"1\",}\n\n Projects.Set(prj.Id, prj) // Mock existing project\n\n tests := []struct {\n name string\n project Project\n task Task\n wantErr bool\n errMsg error\n }{\n {\n name: \"Attach to existing project\",\n project: prj,\n task: tsk,\n wantErr: false,\n },\n {\n name: \"Attach to non-existing project\",\n project: Project{Id: \"200\", Body: \"Project 200\", RealmId: \"1\",},\n task: tsk,\n wantErr: true,\n errMsg: ErrProjectIdNotFound,\n },\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n err := tt.task.AttachTaskToProject(tt.project)\n if (err != nil) != tt.wantErr {\n t.Errorf(\"AttachTaskToProject() error = %v, wantErr %v\", err, tt.wantErr)\n }\n if tt.wantErr && err != tt.errMsg {\n t.Errorf(\"AttachTaskToProject() error = %v, expected %v\", err, tt.errMsg)\n }\n\n // For successful attach, verify the task is added to the project's tasks.\n if !tt.wantErr {\n tasks, exist := ProjectTasks.Get(tt.project.Id)\n if !exist || len(tasks.([]Task)) == 0 {\n t.Errorf(\"Task was not attached to the project\")\n } else {\n found := false\n for _, task := range tasks.([]Task) {\n if task.Id == tt.task.Id {\n found = true\n break\n }\n }\n if !found {\n t.Errorf(\"Task was not attached to the project\")\n }\n }\n }\n })\n }\n}\n\nfunc TestDetachTaskFromProject(t *testing.T) {\n\t\n\t// Setup:\n\tproject := Project{Id: \"p1\", Body: \"Test Project\"}\n\ttask1 := Task{Id: \"5\", Body: \"Task One\"}\n\ttask2 := Task{Id: \"6\", Body: \"Task Two\"}\n\n\tProjects.Set(project.Id, project)\n\tProjectTasks.Set(project.Id, []Task{task1, task2})\n\n\ttests := []struct {\n\t\tname string\n\t\ttask Task\n\t\tproject Project\n\t\twantErr bool\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname: \"Detach existing task from project\",\n\t\t\ttask: task1,\n\t\t\tproject: project,\n\t\t\twantErr: false,\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to detach task from non-existing project\",\n\t\t\ttask: task1,\n\t\t\tproject: Project{Id: \"nonexistent\"},\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrProjectIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to detach non-existing task from project\",\n\t\t\ttask: Task{Id: \"nonexistent\"},\n\t\t\tproject: project,\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrTaskByIdNotFound,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.task.DetachTaskFromProject(tt.project)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tif err == nil || err != tt.expectedErr {\n\t\t\t\t\tt.Errorf(\"%s: expected error %v, got %v\", tt.name, tt.expectedErr, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"%s: unexpected error: %v\", tt.name, err)\n\t\t\t\t}\n\n\t\t\t\t// For successful detachment, verify the task is no longer part of the project's tasks\n\t\t\t\tif !tt.wantErr {\n\t\t\t\t\ttasks, _ := ProjectTasks.Get(tt.project.Id)\n\t\t\t\t\tfor _, task := range tasks.([]Task) {\n\t\t\t\t\t\tif task.Id == tt.task.Id {\n\t\t\t\t\t\t\tt.Errorf(\"%s: task was not detached from the project\", tt.name)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_SetTaskDueDate(t *testing.T) {\n\ttaskRealmIdOne, _ := GetTaskById(\"1\")\n taskRealmIdTwo, _ := GetTaskById(\"10\") \n\t// Define test cases\n\ttests := []struct {\n\t\tname string\n\t\ttask Task\n\t\tdueDate string\n\t\twantErr error\n\t}{\n\t\t{\n\t\t\tname: \"Task does not exist\",\n\t\t\ttask: Task{Id: \"nonexistent\", RealmId: \"2\"},\n\t\t\twantErr: ErrTaskIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Task not editable due to wrong realm\",\n\t\t\ttask: taskRealmIdOne,\n\t\t\twantErr: ErrTaskNotEditable,\n\t\t},\n\t\t{\n\t\t\tname: \"Successfully set due date\",\n\t\t\ttask: taskRealmIdTwo,\n\t\t\tdueDate: \"2023-01-01\",\n\t\t\twantErr: nil,\n\t\t},\n\t}\n\n\t// Execute test cases\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.task.SetTaskDueDate(tc.dueDate)\n\n\t\t\t// Validate\n\t\t\tif err != tc.wantErr {\n\t\t\t\tt.Errorf(\"Expected error %v, got %v\", tc.wantErr, err)\n\t\t\t}\n\n\t\t\t// Additional check for the success case to ensure the due date was actually set\n\t\t\tif err == nil {\n\t\t\t\t// Fetch the task again to check if the due date was set correctly\n\t\t\t\tupdatedTask, exist := Tasks.Get(tc.task.Id)\n\t\t\t\tif !exist {\n\t\t\t\t\tt.Fatalf(\"Task %v was not found after setting the due date\", tc.task.Id)\n\t\t\t\t}\n\t\t\t\tif updatedTask.(Task).Due != tc.dueDate {\n\t\t\t\t\tt.Errorf(\"Expected due date to be %v, got %v\", tc.dueDate, updatedTask.(Task).Due)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_SetTaskAlert(t *testing.T) {\n\ttaskRealmIdOne, _ := GetTaskById(\"1\")\n taskRealmIdTwo, _ := GetTaskById(\"10\") \n\t// Define test cases\n\ttests := []struct {\n\t\tname string\n\t\ttask Task\n\t\talertDate string\n\t\twantErr error\n\t}{\n\t\t{\n\t\t\tname: \"Task does not exist\",\n\t\t\ttask: Task{Id: \"nonexistent\", RealmId: \"2\"},\n\t\t\twantErr: ErrTaskIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Task not editable due to wrong realm\",\n\t\t\ttask: taskRealmIdOne,\n\t\t\twantErr: ErrTaskNotEditable,\n\t\t},\n\t\t{\n\t\t\tname: \"Successfully set alert\",\n\t\t\ttask: taskRealmIdTwo,\n\t\t\talertDate: \"2024-01-01\",\n\t\t\twantErr: nil,\n\t\t},\n\t}\n\n\t// Execute test cases\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.task.SetTaskAlert(tc.alertDate)\n\n\t\t\t// Validate\n\t\t\tif err != tc.wantErr {\n\t\t\t\tt.Errorf(\"Expected error %v, got %v\", tc.wantErr, err)\n\t\t\t}\n\n\t\t\t// Additional check for the success case to ensure the due date was actually set\n\t\t\tif err == nil {\n\t\t\t\t// Fetch the task again to check if the due date was set correctly\n\t\t\t\tupdatedTask, exist := Tasks.Get(tc.task.Id)\n\t\t\t\tif !exist {\n\t\t\t\t\tt.Fatalf(\"Task %v was not found after setting the due date\", tc.task.Id)\n\t\t\t\t}\n\t\t\t\tif updatedTask.(Task).Alert != tc.alertDate {\n\t\t\t\t\tt.Errorf(\"Expected due date to be %v, got %v\", tc.alertDate, updatedTask.(Task).Due)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\n// getters\n\nfunc Test_GetAllTasks(t *testing.T) {\n \n // mocking the tasks based on previous tests\n // TODO: add isolation?\n knownTasks := []Task{\n {Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",},\n {Id: \"10\", Body: \"First content\", RealmId: \"2\", ContextId: \"2\", Due: \"2023-01-01\", Alert: \"2024-01-01\"},\n {Id: \"2\", Body: \"Edited content\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"20\", Body: \"Removable task\", RealmId: \"1\",},\n {Id: \"3\", Body: \"First content\", RealmId: \"2\", ContextId: \"1\",},\n {Id: \"40\", Body: \"Task 40\", RealmId: \"1\",},\n }\n\n // Manually marshal the known tasks to create the expected outcome.\n tasksObject := TasksObject{Tasks: knownTasks}\n expected, err := tasksObject.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal known tasks: %v\", err)\n }\n\n // Execute GetAllTasks() to get the actual outcome.\n actual, err := GetAllTasks()\n if err != nil {\n t.Fatalf(\"GetAllTasks() failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual task JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n\nfunc Test_GetTasksByDate(t *testing.T) {\n\t\n\ttests := []struct {\n\t\tname string\n\t\ttaskDate string\n\t\tfilterType string\n\t\twant string\n\t\twantErr bool\n\t}{\n\t\t{\"SpecificDate\", \"2023-01-01\", \"specific\", `{\"tasks\":[{\"taskId\":\"10\",\"taskProjectId\":\"\",\"taskContextId\":\"2\",\"taskRealmId\":\"2\",\"taskBody\":\"First content\",\"taskDue\":\"2023-01-01\",\"taskAlert\":\"2024-01-01\"}]}`, false},\n\t\t{\"BeforeDate\", \"2022-04-05\", \"before\", \"\", false},\n\t\t{\"AfterDate\", \"2023-04-05\", \"after\", \"\", false},\n\t\t{\"NoMatch\", \"2002-04-07\", \"specific\", \"\", false},\n\t\t{\"InvalidDateFormat\", \"April 5, 2023\", \"specific\", \"\", true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := GetTasksByDate(tt.taskDate, tt.filterType)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"GetTasksByDate() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err == nil && got != tt.want {\n\t\t\t\tt.Errorf(\"GetTasksByDate() got = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_GetTaskById(t *testing.T){\n // test getting a non-existing task\n nonTask, err := GetTaskById(\"0\")\n if err != ErrTaskByIdNotFound {\n t.Fatalf(\"Expected ErrTaskByIdNotFound, got: %v\", err)\n }\n\n // test getting the correct task by id\n correctTask, err := GetTaskById(\"1\")\n if err != nil {\n t.Fatalf(\"Failed to get task by id, error: %v\", err)\n }\n\n if correctTask.Body != \"First task\" {\n t.Fatalf(\"Got the wrong task, with body: %v\", correctTask.Body)\n }\n}\n\nfunc Test_GetTasksByRealm(t *testing.T) {\n \n // mocking the tasks based on previous tests\n // TODO: add isolation?\n tasksInAssessRealm := []Task{\n {Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",},\n {Id: \"2\", RealmId: \"1\", Body: \"Edited content\", ContextId: \"2\",},\n {Id: \"20\", Body: \"Removable task\", RealmId: \"1\",},\n {Id: \"40\", Body: \"Task 40\", RealmId: \"1\",},\n }\n\n // Manually marshal the known tasks to create the expected outcome.\n tasksObjectAssess := TasksObject{Tasks: tasksInAssessRealm}\n expected, err := tasksObjectAssess.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal tasks in Assess: %v\", err)\n }\n\n actual, err := GetTasksByRealm(\"1\")\n if err != nil {\n t.Fatalf(\"GetTasksByRealm('1') failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual task JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n\nfunc Test_GetTasksByContext(t *testing.T) {\n \n // mocking the tasks based on previous tests\n // TODO: add isolation?\n tasksInContextOne := []Task{\n {Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",},\n {Id: \"3\", RealmId: \"2\", Body: \"First content\", ContextId: \"1\",},\n }\n\n // Manually marshal the known tasks to create the expected outcome.\n tasksObjectForContexts := TasksObject{Tasks: tasksInContextOne}\n expected, err := tasksObjectForContexts.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal tasks for ContextId 1: %v\", err)\n }\n\n actual, err := GetTasksByContext(\"1\")\n if err != nil {\n t.Fatalf(\"GetTasksByContext('1') failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual task JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n*/\n" - } - ] - }, - "deposit": "" - } - ], - "fee": { - "gas_wanted": "1000000", - "gas_fee": "1000000ugnot" - }, - "signatures": [], - "memo": "" -} - --- tx2.tx -- -{ - "msg": [ - { - "@type": "/vm.m_addpkg", - "creator": "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5", - "package": { - "name": "zentasktic", - "path": "gno.land/p/g17ernafy6ctpcz6uepfsq2js8x2vz0wladh5yc3/zentasktic", - "files": [ - { - "name": "README.md", - "body": "# ZenTasktic Core\n\nA basic, minimalisitc Asess-Decide-Do implementations as `p/zentasktic`. The diagram below shows a simplified ADD workflow.\n\n![ZenTasktic](ZenTasktic-framework.png)\n\nThis implementation will expose all the basic features of the framework: tasks & projects with complete workflows. Ideally, this should offer all the necessary building blocks for any other custom implementation.\n\n## Object Definitions and Default Values\n\nAs an unopinionated ADD workflow, `zentastic_core` defines the following objects:\n\n- Realm\n\nRealms act like containers for tasks & projects during their journey from Assess to Do, via Decide. Each realm has a certain restrictions, e.g. a task's Body can only be edited in Assess, a Context, Due date and Alert can only be added in Decide, etc.\n\nIf someone observes different realms, there is support for adding and removing arbitrary Realms.\n\n_note: the Ids between 1 and 4 are reserved for: 1-Assess, 2-Decide, 3-Do, 4-Collection. Trying to add or remove such a Realm will raise an error._\n\n\nRealm data definition:\n\n```\ntype Realm struct {\n\tId \t\t\tstring `json:\"realmId\"`\n\tName \t\tstring `json:\"realmName\"`\n}\n```\n\n- Task\n\nA task is the minimal data structure in ZenTasktic, with the following definition:\n\n```\ntype Task struct {\n\tId \t\t\tstring `json:\"taskId\"`\n\tProjectId \tstring `json:\"taskProjectId\"`\n\tContextId\tstring `json:\"taskContextId\"`\n\tRealmId \tstring `json:\"taskRealmId\"`\n\tBody \t\tstring `json:\"taskBody\"`\n\tDue\t\t\tstring `json:\"taskDue\"`\n\tAlert\t\tstring `json:\"taskAlert\"`\n}\n```\n\n- Project\n\nProjects are unopinionated collections of Tasks. A Task in a Project can be in any Realm, but the restrictions are propagated upwards to the Project: e.g. if a Task is marked as 'done' in the Do realm (namely changing its RealmId property to \"1\", Assess, or \"4\" Collection), and the rest of the tasks are not, the Project cannot be moved back to Decide or Asses, all Tasks must have consisted RealmId properties.\n\nA Task can be arbitrarily added to, removed from and moved to another Project.\n\nProject data definition:\n\n\n```\ntype Project struct {\n\tId \t\t\tstring `json:\"projectId\"`\n\tContextId\tstring `json:\"projectContextId\"`\n\tRealmId \tstring `json:\"projectRealmId\"`\n\tTasks\t\t[]Task `json:\"projectTasks\"`\n\tBody \t\tstring `json:\"projectBody\"`\n\tDue\t\t\tstring `json:\"ProjectDue\"`\n}\n```\n\n\n- Context\n\nContexts act as tags, grouping together Tasks and Project, e.g. \"Backend\", \"Frontend\", \"Marketing\". Contexts have no defaults and can be added or removed arbitrarily.\n\nContext data definition:\n\n```\ntype Context struct {\n\tId \t\t\tstring `json:\"contextId\"`\n\tName \t\tstring `json:\"contextName\"`\n}\n```\n\n- Collection\n\nCollections are intended as an agnostic storage for Tasks & Projects which are either not ready to be Assessed, or they have been already marked as done, and, for whatever reason, they need to be kept in the system. There is a special Realm Id for Collections, \"4\", although technically they are not part of the Assess-Decide-Do workflow.\n\nCollection data definition:\n\n```\ntype Collection struct {\n\tId \t\t\tstring `json:\"collectionId\"`\n\tRealmId \tstring `json:\"collectionRealmId\"`\n\tName \t\tstring `json:\"collectionName\"`\n\tTasks\t\t[]Task `json:\"collectionTasks\"`\n\tProjects\t[]Project `json:\"collectionProjects\"`\n}\n```\n\n- ObjectPath\n\nObjectPaths are minimalistic representations of the journey taken by a Task or a Project in the Assess-Decide-Do workflow. By recording their movement between various Realms, one can extract their `ZenStatus`, e.g., if a Task has been moved many times between Assess and Decide, never making it to Do, we can infer the following:\n-- either the Assess part was incomplete\n-- the resources needed for that Task are not yet ready\n\nObjectPath data definition:\n\n```\ntype ObjectPath struct {\n\tObjectType\tstring `json:\"objectType\"` // Task, Project\n\tId \t\t\tstring `json:\"id\"` // this is the Id of the object moved, Task, Project\n\tRealmId \tstring `json:\"realmId\"`\n}\n```\n\n_note: the core implementation offers the basic adding and retrieving functionality, but it's up to the client realm using the `zentasktic` package to call them when an object is moved from one Realm to another._\n\n## Example Workflow\n\n```\npackage example_zentasktic\n\nimport \"gno.land/p/demo/zentasktic\"\n\nvar ztm *zentasktic.ZTaskManager\nvar zpm *zentasktic.ZProjectManager\nvar zrm *zentasktic.ZRealmManager\nvar zcm *zentasktic.ZContextManager\nvar zcl *zentasktic.ZCollectionManager\nvar zom *zentasktic.ZObjectPathManager\n\nfunc init() {\n ztm = zentasktic.NewZTaskManager()\n zpm = zentasktic.NewZProjectManager()\n\tzrm = zentasktic.NewZRealmManager()\n\tzcm = zentasktic.NewZContextManager()\n\tzcl = zentasktic.NewZCollectionManager()\n\tzom = zentasktic.NewZObjectPathManager()\n}\n\n// initializing a task, assuming we get the value POSTed by some call to the current realm\n\nnewTask := zentasktic.Task{Id: \"20\", Body: \"Buy milk\"}\nztm.AddTask(newTask)\n\n// if we want to keep track of the object zen status, we update the object path\ntaskPath := zentasktic.ObjectPath{ObjectType: \"task\", Id: \"20\", RealmId: \"1\"}\nzom.AddPath(taskPath)\n...\n\neditedTask := zentasktic.Task{Id: \"20\", Body: \"Buy fresh milk\"}\nztm.EditTask(editedTask)\n\n...\n\n// moving it to Decide\n\nztm.MoveTaskToRealm(\"20\", \"2\")\n\n// adding context, due date and alert, assuming they're received from other calls\n\nshoppingContext := zcm.GetContextById(\"2\")\n\ncerr := zcm.AddContextToTask(ztm, shoppingContext, editedTask)\n\nderr := ztm.SetTaskDueDate(editedTask.Id, \"2024-04-10\")\nnow := time.Now() // replace with the actual time of the alert\nalertTime := now.Format(\"2006-01-02 15:04:05\")\naerr := ztm.SetTaskAlert(editedTask.Id, alertTime)\n\n...\n\n// move the Task to Do\n\nztm.MoveTaskToRealm(editedTask.Id, \"2\")\n\n// if we want to keep track of the object zen status, we update the object path\ntaskPath := zentasktic.ObjectPath{ObjectType: \"task\", Id: \"20\", RealmId: \"2\"}\nzom.AddPath(taskPath)\n\n// after the task is done, we sent it back to Assess\n\nztm.MoveTaskToRealm(editedTask.Id,\"1\")\n\n// if we want to keep track of the object zen status, we update the object path\ntaskPath := zentasktic.ObjectPath{ObjectType: \"task\", Id: \"20\", RealmId: \"1\"}\nzom.AddPath(taskPath)\n\n// from here, we can add it to a collection\n\nmyCollection := zcm.GetCollectionById(\"1\")\n\nzcm.AddTaskToCollection(ztm, myCollection, editedTask)\n\n// if we want to keep track of the object zen status, we update the object path\ntaskPath := zentasktic.ObjectPath{ObjectType: \"task\", Id: \"20\", RealmId: \"4\"}\nzom.AddPath(taskPath)\n\n```\n\nAll tests are in the `*_test.gno` files, e.g. `tasks_test.gno`, `projects_test.gno`, etc." - }, - { - "name": "collections.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"gno.land/p/demo/avl\"\n)\n\n\ntype Collection struct {\n\tId \t\t\tstring `json:\"collectionId\"`\n\tRealmId \tstring `json:\"collectionRealmId\"`\n\tName \t\tstring `json:\"collectionName\"`\n\tTasks\t\t[]Task `json:\"collectionTasks\"`\n\tProjects\t[]Project `json:\"collectionProjects\"`\n}\n\ntype ZCollectionManager struct {\n\tCollections *avl.Tree \n\tCollectionTasks *avl.Tree\n\tCollectionProjects *avl.Tree \n}\n\nfunc NewZCollectionManager() *ZCollectionManager {\n return &ZCollectionManager{\n Collections: avl.NewTree(),\n CollectionTasks: avl.NewTree(),\n CollectionProjects: avl.NewTree(),\n }\n}\n\n\n// actions\n\nfunc (zcolm *ZCollectionManager) AddCollection(c Collection) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif exist {\n\t\t\treturn ErrCollectionIdAlreadyExists\n\t\t}\n\t}\n\tzcolm.Collections.Set(c.Id, c)\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) EditCollection(c Collection) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\t\n\tzcolm.Collections.Set(c.Id, c)\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) RemoveCollection(c Collection) (err error) {\n // implementation\n if zcolm.Collections.Size() != 0 {\n collectionInterface, exist := zcolm.Collections.Get(c.Id)\n if !exist {\n return ErrCollectionIdNotFound\n }\n collection := collectionInterface.(Collection)\n\n _, removed := zcolm.Collections.Remove(collection.Id)\n if !removed {\n return ErrCollectionNotRemoved\n }\n\n if zcolm.CollectionTasks.Size() != 0 {\n _, removedTasks := zcolm.CollectionTasks.Remove(collection.Id)\n if !removedTasks {\n return ErrCollectionNotRemoved\n }\t\n }\n\n if zcolm.CollectionProjects.Size() != 0 {\n _, removedProjects := zcolm.CollectionProjects.Remove(collection.Id)\n if !removedProjects {\n return ErrCollectionNotRemoved\n }\t\n }\n }\n return nil\n}\n\n\nfunc (zcolm *ZCollectionManager) AddProjectToCollection(zpm *ZProjectManager, c Collection, p Project) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\n\texistingCollectionProjects, texist := zcolm.CollectionProjects.Get(c.Id)\n\tif !texist {\n\t\t// If the collections has no projects yet, initialize the slice.\n\t\texistingCollectionProjects = []Project{}\n\t} else {\n\t\tprojects, ok := existingCollectionProjects.([]Project)\n\t\tif !ok {\n\t\t\treturn ErrCollectionsProjectsNotFound\n\t\t}\n\t\texistingCollectionProjects = projects\n\t}\n\tp.RealmId = \"4\"\n\tif err := zpm.EditProject(p); err != nil {\n\t\treturn err\n\t}\n\tupdatedProjects := append(existingCollectionProjects.([]Project), p)\n\tzcolm.CollectionProjects.Set(c.Id, updatedProjects)\n\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) AddTaskToCollection(ztm *ZTaskManager, c Collection, t Task) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\n\texistingCollectionTasks, texist := zcolm.CollectionTasks.Get(c.Id)\n\tif !texist {\n\t\t// If the collections has no tasks yet, initialize the slice.\n\t\texistingCollectionTasks = []Task{}\n\t} else {\n\t\ttasks, ok := existingCollectionTasks.([]Task)\n\t\tif !ok {\n\t\t\treturn ErrCollectionsTasksNotFound\n\t\t}\n\t\texistingCollectionTasks = tasks\n\t}\n\tt.RealmId = \"4\"\n\tif err := ztm.EditTask(t); err != nil {\n\t\treturn err\n\t}\n\tupdatedTasks := append(existingCollectionTasks.([]Task), t)\n\tzcolm.CollectionTasks.Set(c.Id, updatedTasks)\n\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) RemoveProjectFromCollection(zpm *ZProjectManager, c Collection, p Project) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\n\texistingCollectionProjects, texist := zcolm.CollectionProjects.Get(c.Id)\n\tif !texist {\n\t\t// If the collection has no projects yet, return appropriate error\n\t\treturn ErrCollectionsProjectsNotFound\n\t}\n\n\t// Find the index of the project to be removed.\n\tvar index int = -1\n\tfor i, project := range existingCollectionProjects.([]Project) {\n\t\tif project.Id == p.Id {\n\t\t\tindex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// If the project was found, we remove it from the slice.\n\tif index != -1 {\n\t\t// by default we send it back to Assess\n\t\tp.RealmId = \"1\"\n\t\tzpm.EditProject(p)\n\t\texistingCollectionProjects = append(existingCollectionProjects.([]Project)[:index], existingCollectionProjects.([]Project)[index+1:]...)\n\t} else {\n\t\t// Project not found in the collection\n\t\treturn ErrProjectByIdNotFound \n\t}\n\tzcolm.CollectionProjects.Set(c.Id, existingCollectionProjects)\n\n\treturn nil\n}\n\nfunc (zcolm *ZCollectionManager) RemoveTaskFromCollection(ztm *ZTaskManager, c Collection, t Task) (err error) {\n\t// implementation\n\tif zcolm.Collections.Size() != 0 {\n\t\t_, exist := zcolm.Collections.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrCollectionIdNotFound\n\t\t}\n\t}\n\n\texistingCollectionTasks, texist := zcolm.CollectionTasks.Get(c.Id)\n\tif !texist {\n\t\t// If the collection has no tasks yet, return appropriate error\n\t\treturn ErrCollectionsTasksNotFound\n\t}\n\n\t// Find the index of the task to be removed.\n\tvar index int = -1\n\tfor i, task := range existingCollectionTasks.([]Task) {\n\t\tif task.Id == t.Id {\n\t\t\tindex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// If the task was found, we remove it from the slice.\n\tif index != -1 {\n\t\t// by default, we send the task to Assess\n\t\tt.RealmId = \"1\"\n\t\tztm.EditTask(t)\n\t\texistingCollectionTasks = append(existingCollectionTasks.([]Task)[:index], existingCollectionTasks.([]Task)[index+1:]...)\n\t} else {\n\t\t// Task not found in the collection\n\t\treturn ErrTaskByIdNotFound \n\t}\n\tzcolm.CollectionTasks.Set(c.Id, existingCollectionTasks)\n\n\treturn nil\n}\n\n// getters\n\nfunc (zcolm *ZCollectionManager) GetCollectionById(collectionId string) (Collection, error) {\n if zcolm.Collections.Size() != 0 {\n cInterface, exist := zcolm.Collections.Get(collectionId)\n if exist {\n collection := cInterface.(Collection)\n // look for collection Tasks, Projects\n existingCollectionTasks, texist := zcolm.CollectionTasks.Get(collectionId)\n if texist {\n collection.Tasks = existingCollectionTasks.([]Task)\n }\n existingCollectionProjects, pexist := zcolm.CollectionProjects.Get(collectionId)\n if pexist {\n collection.Projects = existingCollectionProjects.([]Project)\n }\n return collection, nil\n }\n return Collection{}, ErrCollectionByIdNotFound\n }\n return Collection{}, ErrCollectionByIdNotFound\n}\n\nfunc (zcolm *ZCollectionManager) GetCollectionTasks(c Collection) (tasks []Task, err error) {\n\t\n\tif zcolm.CollectionTasks.Size() != 0 {\n\t\ttask, exist := zcolm.CollectionTasks.Get(c.Id)\n\t\tif !exist {\n\t\t\t// if there's no record in CollectionTasks, we don't have to return anything\n\t\t\treturn nil, ErrCollectionsTasksNotFound\n\t\t} else {\n\t\t\t// type assertion to convert interface{} to []Task\n\t\t\texistingCollectionTasks, ok := task.([]Task)\n\t\t\tif !ok {\n\t\t\t\treturn nil, ErrTaskFailedToAssert\n\t\t\t}\n\t\t\treturn existingCollectionTasks, nil\n\t\t}\n\t}\n\treturn nil, nil\n}\n\nfunc (zcolm *ZCollectionManager) GetCollectionProjects(c Collection) (projects []Project, err error) {\n\t\n\tif zcolm.CollectionProjects.Size() != 0 {\n\t\tproject, exist := zcolm.CollectionProjects.Get(c.Id)\n\t\tif !exist {\n\t\t\t// if there's no record in CollectionProjets, we don't have to return anything\n\t\t\treturn nil, ErrCollectionsProjectsNotFound\n\t\t} else {\n\t\t\t// type assertion to convert interface{} to []Projet\n\t\t\texistingCollectionProjects, ok := project.([]Project)\n\t\t\tif !ok {\n\t\t\t\treturn nil, ErrProjectFailedToAssert\n\t\t\t}\n\t\t\treturn existingCollectionProjects, nil\n\t\t}\n\t}\n\treturn nil, nil\n}\n\nfunc (zcolm *ZCollectionManager) GetAllCollections() (collections string, err error) {\n\t// implementation\n\tvar allCollections []Collection\n\t\n\t// Iterate over the Collections AVL tree to collect all Project objects.\n\t\n\tzcolm.Collections.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif collection, ok := value.(Collection); ok {\n\t\t\t// get collection tasks, if any\n\t\t\tcollectionTasks, _ := zcolm.GetCollectionTasks(collection)\n\t\t\tif collectionTasks != nil {\n\t\t\t\tcollection.Tasks = collectionTasks\n\t\t\t}\n\t\t\t// get collection prokects, if any\n\t\t\tcollectionProjects, _ := zcolm.GetCollectionProjects(collection)\n\t\t\tif collectionProjects != nil {\n\t\t\t\tcollection.Projects = collectionProjects\n\t\t\t}\n\t\t\tallCollections = append(allCollections, collection)\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a CollectionsObject with all collected tasks.\n\tcollectionsObject := CollectionsObject{\n\t\tCollections: allCollections,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the collections into JSON.\n\tmarshalledCollections, merr := collectionsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\", merr\n\t} \n\treturn string(marshalledCollections), nil\n} " - }, - { - "name": "collections_test.gno", - "body": "package zentasktic\n\nimport (\n\t\"testing\"\n\n \"gno.land/p/demo/avl\"\n)\n/*\n\nfunc Test_AddCollection(t *testing.T) {\n \n collection := Collection{Id: \"1\", RealmId: \"4\", Name: \"First collection\",}\n\n // Test adding a collection successfully.\n err := collection.AddCollection()\n if err != nil {\n t.Errorf(\"Failed to add collection: %v\", err)\n }\n\n // Test adding a duplicate task.\n cerr := collection.AddCollection()\n if cerr != ErrCollectionIdAlreadyExists {\n t.Errorf(\"Expected ErrCollectionIdAlreadyExists, got %v\", cerr)\n }\n}\n\nfunc Test_RemoveCollection(t *testing.T) {\n \n collection := Collection{Id: \"20\", RealmId: \"4\", Name: \"Removable collection\",}\n\n // Test adding a collection successfully.\n err := collection.AddCollection()\n if err != nil {\n t.Errorf(\"Failed to add collection: %v\", err)\n }\n\n retrievedCollection, rerr := GetCollectionById(collection.Id)\n if rerr != nil {\n t.Errorf(\"Could not retrieve the added collection\")\n }\n\n // Test removing a collection\n terr := retrievedCollection.RemoveCollection()\n if terr != ErrCollectionNotRemoved {\n t.Errorf(\"Expected ErrCollectionNotRemoved, got %v\", terr)\n }\n}\n\nfunc Test_EditCollection(t *testing.T) {\n \n collection := Collection{Id: \"2\", RealmId: \"4\", Name: \"Second collection\",}\n\n // Test adding a collection successfully.\n err := collection.AddCollection()\n if err != nil {\n t.Errorf(\"Failed to add collection: %v\", err)\n }\n\n // Test editing the collection\n editedCollection := Collection{Id: collection.Id, RealmId: collection.RealmId, Name: \"Edited collection\",}\n cerr := editedCollection.EditCollection()\n if cerr != nil {\n t.Errorf(\"Failed to edit the collection\")\n }\n\n retrievedCollection, _ := GetCollectionById(editedCollection.Id)\n if retrievedCollection.Name != \"Edited collection\" {\n t.Errorf(\"Collection was not edited\")\n }\n}\n\nfunc Test_AddProjectToCollection(t *testing.T){\n // Example Collection and Projects\n col := Collection{Id: \"1\", Name: \"First collection\", RealmId: \"4\",}\n prj := Project{Id: \"10\", Body: \"Project 10\", RealmId: \"1\",}\n\n Collections.Set(col.Id, col) // Mock existing collections\n\n tests := []struct {\n name string\n collection Collection\n project Project\n wantErr bool\n errMsg error\n }{\n {\n name: \"Attach to existing collection\",\n collection: col,\n project: prj,\n wantErr: false,\n },\n {\n name: \"Attach to non-existing collection\",\n collection: Collection{Id: \"200\", Name: \"Collection 200\", RealmId: \"4\",},\n project: prj,\n wantErr: true,\n errMsg: ErrCollectionIdNotFound,\n },\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n err := tt.collection.AddProjectToCollection(tt.project)\n if (err != nil) != tt.wantErr {\n t.Errorf(\"AddProjectToCollection() error = %v, wantErr %v\", err, tt.wantErr)\n }\n if tt.wantErr && err != tt.errMsg {\n t.Errorf(\"AddProjectToCollection() error = %v, expected %v\", err, tt.errMsg)\n }\n\n // For successful attach, verify the project is added to the collection's tasks.\n if !tt.wantErr {\n projects, exist := CollectionProjects.Get(tt.collection.Id)\n if !exist || len(projects.([]Project)) == 0 {\n t.Errorf(\"Project was not added to the collection\")\n } else {\n found := false\n for _, project := range projects.([]Project) {\n if project.Id == tt.project.Id {\n found = true\n break\n }\n }\n if !found {\n t.Errorf(\"Project was not attached to the collection\")\n }\n }\n }\n })\n }\n}\n\nfunc Test_AddTaskToCollection(t *testing.T){\n // Example Collection and Tasks\n col := Collection{Id: \"2\", Name: \"Second Collection\", RealmId: \"4\",}\n tsk := Task{Id: \"30\", Body: \"Task 30\", RealmId: \"1\",}\n\n Collections.Set(col.Id, col) // Mock existing collections\n\n tests := []struct {\n name string\n collection Collection\n task Task\n wantErr bool\n errMsg error\n }{\n {\n name: \"Attach to existing collection\",\n collection: col,\n task: tsk,\n wantErr: false,\n },\n {\n name: \"Attach to non-existing collection\",\n collection: Collection{Id: \"210\", Name: \"Collection 210\", RealmId: \"4\",},\n task: tsk,\n wantErr: true,\n errMsg: ErrCollectionIdNotFound,\n },\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n err := tt.collection.AddTaskToCollection(tt.task)\n if (err != nil) != tt.wantErr {\n t.Errorf(\"AddTaskToCollection() error = %v, wantErr %v\", err, tt.wantErr)\n }\n if tt.wantErr && err != tt.errMsg {\n t.Errorf(\"AddTaskToCollection() error = %v, expected %v\", err, tt.errMsg)\n }\n\n // For successful attach, verify the task is added to the collection's tasks.\n if !tt.wantErr {\n tasks, exist := CollectionTasks.Get(tt.collection.Id)\n if !exist || len(tasks.([]Task)) == 0 {\n t.Errorf(\"Task was not added to the collection\")\n } else {\n found := false\n for _, task := range tasks.([]Task) {\n if task.Id == tt.task.Id {\n found = true\n break\n }\n }\n if !found {\n t.Errorf(\"Task was not attached to the collection\")\n }\n }\n }\n })\n }\n}\n\nfunc Test_RemoveProjectFromCollection(t *testing.T){\n // Setup:\n\tcollection := Collection{Id: \"300\", Name: \"Collection 300\",}\n\tproject1 := Project{Id: \"21\", Body: \"Project 21\", RealmId: \"1\",}\n\tproject2 := Project{Id: \"22\", Body: \"Project 22\", RealmId: \"1\",}\n\n collection.AddCollection()\n project1.AddProject()\n project2.AddProject()\n collection.AddProjectToCollection(project1)\n collection.AddProjectToCollection(project2)\n\n\ttests := []struct {\n\t\tname string\n\t\tproject Project\n\t\tcollection Collection\n\t\twantErr bool\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname: \"Remove existing project from collection\",\n\t\t\tproject: project1,\n\t\t\tcollection: collection,\n\t\t\twantErr: false,\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to remove project from non-existing collection\",\n\t\t\tproject: project1,\n\t\t\tcollection: Collection{Id: \"nonexistent\"},\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrCollectionIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to remove non-existing project from collection\",\n\t\t\tproject: Project{Id: \"nonexistent\"},\n\t\t\tcollection: collection,\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrProjectByIdNotFound,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.collection.RemoveProjectFromCollection(tt.project)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tif err == nil || err != tt.expectedErr {\n\t\t\t\t\tt.Errorf(\"%s: expected error %v, got %v\", tt.name, tt.expectedErr, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"%s: unexpected error: %v\", tt.name, err)\n\t\t\t\t}\n\n\t\t\t\t// For successful removal, verify the project is no longer part of the collection's projects\n\t\t\t\tif !tt.wantErr {\n\t\t\t\t\tprojects, _ := CollectionProjects.Get(tt.collection.Id)\n\t\t\t\t\tfor _, project := range projects.([]Project) {\n\t\t\t\t\t\tif project.Id == tt.project.Id {\n\t\t\t\t\t\t\tt.Errorf(\"%s: project was not detached from the collection\", tt.name)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_RemoveTaskFromCollection(t *testing.T){\n // setup, re-using parts from Test_AddTaskToCollection\n\tcollection := Collection{Id: \"40\", Name: \"Collection 40\",}\n task1 := Task{Id: \"40\", Body: \"Task 40\", RealmId: \"1\",}\n\n collection.AddCollection()\n task1.AddTask()\n collection.AddTaskToCollection(task1)\n\n\ttests := []struct {\n\t\tname string\n\t\ttask Task\n\t\tcollection Collection\n\t\twantErr bool\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname: \"Remove existing task from collection\",\n\t\t\ttask: task1,\n\t\t\tcollection: collection,\n\t\t\twantErr: false,\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to remove task from non-existing collection\",\n\t\t\ttask: task1,\n\t\t\tcollection: Collection{Id: \"nonexistent\"},\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrCollectionIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to remove non-existing task from collection\",\n\t\t\ttask: Task{Id: \"nonexistent\"},\n\t\t\tcollection: collection,\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrTaskByIdNotFound,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.collection.RemoveTaskFromCollection(tt.task)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tif err == nil || err != tt.expectedErr {\n\t\t\t\t\tt.Errorf(\"%s: expected error %v, got %v\", tt.name, tt.expectedErr, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"%s: unexpected error: %v\", tt.name, err)\n\t\t\t\t}\n\n\t\t\t\t// For successful removal, verify the task is no longer part of the collection's tasks\n\t\t\t\tif !tt.wantErr {\n\t\t\t\t\ttasks, _ := CollectionTasks.Get(tt.collection.Id)\n\t\t\t\t\tfor _, task := range tasks.([]Task) {\n\t\t\t\t\t\tif task.Id == tt.task.Id {\n\t\t\t\t\t\t\tt.Errorf(\"%s: task was not detached from the collection\", tt.name)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_GetCollectionById(t *testing.T){\n // test getting a non-existing collection\n nonCollection, err := GetCollectionById(\"0\")\n if err != ErrCollectionByIdNotFound {\n t.Fatalf(\"Expected ErrCollectionByIdNotFound, got: %v\", err)\n }\n\n // test getting the correct collection by id\n correctCollection, err := GetCollectionById(\"1\")\n if err != nil {\n t.Fatalf(\"Failed to get collection by id, error: %v\", err)\n }\n\n if correctCollection.Name != \"First collection\" {\n t.Fatalf(\"Got the wrong collection, with name: %v\", correctCollection.Name)\n }\n}\n\nfunc Test_GetCollectionTasks(t *testing.T) {\n // retrieving objects based on these mocks\n //col := Collection{Id: \"2\", Name: \"Second Collection\", RealmId: \"4\",}\n tsk := Task{Id: \"30\", Body: \"Task 30\", RealmId: \"1\",}\n\n collection, cerr := GetCollectionById(\"2\")\n if cerr != nil {\n t.Errorf(\"GetCollectionById() failed, %v\", cerr)\n }\n\n collectionTasks, pterr := collection.GetCollectionTasks()\n if len(collectionTasks) == 0 {\n t.Errorf(\"GetCollectionTasks() failed, %v\", pterr)\n }\n\n // test detaching from an existing collection\n dtterr := collection.RemoveTaskFromCollection(tsk)\n if dtterr != nil {\n t.Errorf(\"RemoveTaskFromCollection() failed, %v\", dtterr)\n }\n\n collectionWithNoTasks, pterr := collection.GetCollectionTasks()\n if len(collectionWithNoTasks) != 0 {\n t.Errorf(\"GetCollectionTasks() after detach failed, %v\", pterr)\n }\n\n // add task back to collection, for tests mockup integrity\n collection.AddTaskToCollection(tsk)\n}\n\nfunc Test_GetCollectionProjects(t *testing.T) {\n // retrieving objects based on these mocks\n //col := Collection{Id: \"1\", Name: \"First Collection\", RealmId: \"4\",}\n prj := Project{Id: \"10\", Body: \"Project 10\", RealmId: \"2\", ContextId: \"2\", Due: \"2024-01-01\"}\n\n collection, cerr := GetCollectionById(\"1\")\n if cerr != nil {\n t.Errorf(\"GetCollectionById() failed, %v\", cerr)\n }\n\n collectionProjects, pterr := collection.GetCollectionProjects()\n if len(collectionProjects) == 0 {\n t.Errorf(\"GetCollectionProjects() failed, %v\", pterr)\n }\n\n // test detaching from an existing collection\n dtterr := collection.RemoveProjectFromCollection(prj)\n if dtterr != nil {\n t.Errorf(\"RemoveProjectFromCollection() failed, %v\", dtterr)\n }\n\n collectionWithNoProjects, pterr := collection.GetCollectionProjects()\n if len(collectionWithNoProjects) != 0 {\n t.Errorf(\"GetCollectionProjects() after detach failed, %v\", pterr)\n }\n\n // add project back to collection, for tests mockup integrity\n collection.AddProjectToCollection(prj)\n}\n\nfunc Test_GetAllCollections(t *testing.T){\n // mocking the collections based on previous tests\n // TODO: add isolation?\n knownCollections := []Collection{\n {\n Id: \"1\",\n RealmId: \"4\",\n Name: \"First collection\",\n Tasks: nil, \n Projects: []Project{\n {\n Id: \"10\",\n ContextId: \"2\",\n RealmId: \"4\",\n Tasks: nil, \n Body: \"Project 10\",\n Due: \"2024-01-01\",\n },\n },\n },\n {\n Id: \"2\",\n RealmId: \"4\",\n Name: \"Second Collection\",\n Tasks: []Task{\n {\n Id:\"30\",\n ProjectId:\"\",\n ContextId:\"\",\n RealmId:\"4\",\n Body:\"Task 30\",\n Due:\"\",\n Alert:\"\",\n },\n },\n Projects: nil, \n },\n {\n Id:\"20\",\n RealmId:\"4\",\n Name:\"Removable collection\",\n Tasks: nil,\n Projects: nil,\n },\n {\n Id: \"300\",\n Name: \"Collection 300\",\n Tasks: nil, \n Projects: []Project {\n {\n Id:\"22\",\n ContextId:\"\",\n RealmId:\"4\",\n Tasks: nil,\n Body:\"Project 22\",\n Due:\"\",\n },\n }, \n },\n {\n Id: \"40\",\n Name: \"Collection 40\",\n Tasks: nil, \n Projects: nil, \n },\n }\n \n\n // Manually marshal the known collections to create the expected outcome.\n collectionsObject := CollectionsObject{Collections: knownCollections}\n expected, err := collectionsObject.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal known collections: %v\", err)\n }\n\n // Execute GetAllCollections() to get the actual outcome.\n actual, err := GetAllCollections()\n if err != nil {\n t.Fatalf(\"GetAllCollections() failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual collections JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n*/\n\n\n\n\n" - }, - { - "name": "contexts.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"gno.land/p/demo/avl\"\n)\n\ntype Context struct {\n\tId string `json:\"contextId\"`\n\tName string `json:\"contextName\"`\n}\n\ntype ZContextManager struct {\n\tContexts *avl.Tree\n}\n\nfunc NewZContextManager() *ZContextManager {\n\treturn &ZContextManager{\n\t\tContexts: avl.NewTree(),\n\t}\n}\n\n// Actions\n\nfunc (zcm *ZContextManager) AddContext(c Context) error {\n\tif zcm.Contexts.Size() != 0 {\n\t\t_, exist := zcm.Contexts.Get(c.Id)\n\t\tif exist {\n\t\t\treturn ErrContextIdAlreadyExists\n\t\t}\n\t}\n\tzcm.Contexts.Set(c.Id, c)\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) EditContext(c Context) error {\n\tif zcm.Contexts.Size() != 0 {\n\t\t_, exist := zcm.Contexts.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrContextIdNotFound\n\t\t}\n\t}\n\tzcm.Contexts.Set(c.Id, c)\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) RemoveContext(c Context) error {\n\tif zcm.Contexts.Size() != 0 {\n\t\tcontext, exist := zcm.Contexts.Get(c.Id)\n\t\tif !exist {\n\t\t\treturn ErrContextIdNotFound\n\t\t}\n\t\t_, removed := zcm.Contexts.Remove(context.(Context).Id)\n\t\tif !removed {\n\t\t\treturn ErrContextNotRemoved\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) AddContextToTask(ztm *ZTaskManager, c Context, t Task) error {\n\ttaskInterface, exist := ztm.Tasks.Get(t.Id)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\t_, cexist := zcm.Contexts.Get(c.Id)\n\tif !cexist {\n\t\treturn ErrContextIdNotFound\n\t}\n\n\tif t.RealmId == \"2\" {\n\t\ttask := taskInterface.(Task)\n\t\ttask.ContextId = c.Id\n\t\tztm.Tasks.Set(t.Id, task)\n\t} else {\n\t\treturn ErrTaskNotEditable\n\t}\n\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) AddContextToProject(zpm *ZProjectManager, c Context, p Project) error {\n\tprojectInterface, exist := zpm.Projects.Get(p.Id)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\t_, cexist := zcm.Contexts.Get(c.Id)\n\tif !cexist {\n\t\treturn ErrContextIdNotFound\n\t}\n\n\tif p.RealmId == \"2\" {\n\t\tproject := projectInterface.(Project)\n\t\tproject.ContextId = c.Id\n\t\tzpm.Projects.Set(p.Id, project)\n\t} else {\n\t\treturn ErrProjectNotEditable\n\t}\n\n\treturn nil\n}\n\nfunc (zcm *ZContextManager) AddContextToProjectTask(zpm *ZProjectManager, c Context, p Project, projectTaskId string) error {\n\t\n\t_, cexist := zcm.Contexts.Get(c.Id)\n\tif !cexist {\n\t\treturn ErrContextIdNotFound\n\t}\n\n\texistingProjectInterface, exist := zpm.Projects.Get(p.Id)\n if !exist {\n return ErrProjectIdNotFound\n }\n existingProject := existingProjectInterface.(Project)\n\n\tif existingProject.RealmId != \"2\" {\n\t\treturn ErrProjectNotEditable\n\t}\n\n existingProjectTasksInterface, texist := zpm.ProjectTasks.Get(p.Id)\n if !texist {\n return ErrProjectTasksNotFound\n }\n tasks, ok := existingProjectTasksInterface.([]Task)\n if !ok {\n return ErrProjectTasksNotFound\n }\n existingProject.Tasks = tasks\n\n var index int = -1\n for i, task := range existingProject.Tasks {\n if task.Id == projectTaskId {\n index = i\n break\n }\n }\n\n if index != -1 {\n existingProject.Tasks[index].ContextId = c.Id\n } else {\n return ErrTaskByIdNotFound\n }\n\n zpm.ProjectTasks.Set(p.Id, existingProject.Tasks)\n return nil\n}\n\n// getters\n\nfunc (zcm *ZContextManager) GetContextById(contextId string) (Context, error) {\n\tif zcm.Contexts.Size() != 0 {\n\t\tcInterface, exist := zcm.Contexts.Get(contextId)\n\t\tif exist {\n\t\t\treturn cInterface.(Context), nil\n\t\t}\n\t\treturn Context{}, ErrContextIdNotFound\n\t}\n\treturn Context{}, ErrContextIdNotFound\n}\n\nfunc (zcm *ZContextManager) GetAllContexts() (string) {\n\tvar allContexts []Context\n\n\t// Iterate over the Contexts AVL tree to collect all Context objects.\n\tzcm.Contexts.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif context, ok := value.(Context); ok {\n\t\t\tallContexts = append(allContexts, context)\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a ContextsObject with all collected contexts.\n\tcontextsObject := &ContextsObject{\n\t\tContexts: allContexts,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the contexts into JSON.\n\tmarshalledContexts, merr := contextsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t}\n\treturn string(marshalledContexts)\n}\n\n" - }, - { - "name": "contexts_test.gno", - "body": "package zentasktic\n\nimport (\n\t\"testing\"\n\n \"gno.land/p/demo/avl\"\n)\n/*\nfunc Test_AddContext(t *testing.T) {\n \n context := Context{Id: \"1\", Name: \"Work\"}\n\n // Test adding a context successfully.\n err := context.AddContext()\n if err != nil {\n t.Errorf(\"Failed to add context: %v\", err)\n }\n\n // Test adding a duplicate task.\n cerr := context.AddContext()\n if cerr != ErrContextIdAlreadyExists {\n t.Errorf(\"Expected ErrContextIdAlreadyExists, got %v\", cerr)\n }\n}\n\nfunc Test_EditContext(t *testing.T) {\n \n context := Context{Id: \"2\", Name: \"Home\"}\n\n // Test adding a context successfully.\n err := context.AddContext()\n if err != nil {\n t.Errorf(\"Failed to add context: %v\", err)\n }\n\n // Test editing the context\n editedContext := Context{Id: \"2\", Name: \"Shopping\"}\n cerr := editedContext.EditContext()\n if cerr != nil {\n t.Errorf(\"Failed to edit the context\")\n }\n\n retrievedContext, _ := GetContextById(editedContext.Id)\n if retrievedContext.Name != \"Shopping\" {\n t.Errorf(\"Context was not edited\")\n }\n}\n\nfunc Test_RemoveContext(t *testing.T) {\n \n context := Context{Id: \"4\", Name: \"Gym\",}\n\n // Test adding a context successfully.\n err := context.AddContext()\n if err != nil {\n t.Errorf(\"Failed to add context: %v\", err)\n }\n\n retrievedContext, rerr := GetContextById(context.Id)\n if rerr != nil {\n t.Errorf(\"Could not retrieve the added context\")\n }\n // Test removing a context\n cerr := retrievedContext.RemoveContext()\n if cerr != ErrContextNotRemoved {\n t.Errorf(\"Expected ErrContextNotRemoved, got %v\", cerr)\n }\n}\n\nfunc Test_AddContextToTask(t *testing.T) {\n\n task := Task{Id: \"10\", Body: \"First content\", RealmId: \"2\", ContextId: \"1\",}\n\n // Test adding a task successfully.\n err := task.AddTask()\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n taskInDecide, exist := Tasks.Get(\"10\")\n\tif !exist {\n\t\tt.Errorf(\"Task with id 10 not found\")\n\t}\n\t// check if context exists\n\tcontextToAdd, cexist := Contexts.Get(\"2\")\n\tif !cexist {\n\t\tt.Errorf(\"Context with id 2 not found\")\n\t}\n\n derr := contextToAdd.(Context).AddContextToTask(taskInDecide.(Task))\n if derr != nil {\n t.Errorf(\"Could not add context to a task in Decide, err %v\", derr)\n }\n}\n\nfunc Test_AddContextToProject(t *testing.T) {\n\n project := Project{Id: \"10\", Body: \"Project 10\", RealmId: \"2\", ContextId: \"1\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n projectInDecide, exist := Projects.Get(\"10\")\n\tif !exist {\n\t\tt.Errorf(\"Project with id 10 not found\")\n\t}\n\t// check if context exists\n\tcontextToAdd, cexist := Contexts.Get(\"2\")\n\tif !cexist {\n\t\tt.Errorf(\"Context with id 2 not found\")\n\t}\n\n derr := contextToAdd.(Context).AddContextToProject(projectInDecide.(Project))\n if derr != nil {\n t.Errorf(\"Could not add context to a project in Decide, err %v\", derr)\n }\n}\n\nfunc Test_GetAllContexts(t *testing.T) {\n \n // mocking the contexts based on previous tests\n // TODO: add isolation?\n knownContexts := []Context{\n {Id: \"1\", Name: \"Work\",},\n {Id: \"2\", Name: \"Shopping\",},\n {Id: \"4\", Name: \"Gym\",},\n }\n\n // Manually marshal the known contexts to create the expected outcome.\n contextsObject := ContextsObject{Contexts: knownContexts}\n expected, err := contextsObject.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal known contexts: %v\", err)\n }\n\n // Execute GetAllContexts() to get the actual outcome.\n actual, err := GetAllContexts()\n if err != nil {\n t.Fatalf(\"GetAllContexts() failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual contexts JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n*/\n\n" - }, - { - "name": "core.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"strconv\"\n\n\t\"gno.land/p/demo/avl\"\n)\n\n// holding the path of an object since creation\n// each time we move an object from one realm to another, we add to its path\ntype ObjectPath struct {\n\tObjectType string `json:\"objectType\"` // Task, Project\n\tId string `json:\"id\"` // this is the Id of the object moved, Task, Project\n\tRealmId string `json:\"realmId\"`\n}\n\ntype ZObjectPathManager struct {\n\tPaths avl.Tree\n\tPathId int\n}\n\nfunc NewZObjectPathManager() *ZObjectPathManager {\n\treturn &ZObjectPathManager{\n\t\tPaths: *avl.NewTree(),\n\t\tPathId: 1,\n\t}\n}\n\nfunc (zopm *ZObjectPathManager) AddPath(o ObjectPath) error {\n\tzopm.PathId++\n\tupdated := zopm.Paths.Set(strconv.Itoa(zopm.PathId), o)\n\tif !updated {\n\t\treturn ErrObjectPathNotUpdated\n\t}\n\treturn nil\n}\n\nfunc (zopm *ZObjectPathManager) GetObjectJourney(objectType string, objectId string) (string, error) {\n\tvar objectPaths []ObjectPath\n\n\t// Iterate over the Paths AVL tree to collect all ObjectPath objects.\n\tzopm.Paths.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif objectPath, ok := value.(ObjectPath); ok {\n\t\t\tif objectPath.ObjectType == objectType && objectPath.Id == objectId {\n\t\t\t\tobjectPaths = append(objectPaths, objectPath)\n\t\t\t}\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create an ObjectJourney with all collected paths.\n\tobjectJourney := &ObjectJourney{\n\t\tObjectPaths: objectPaths,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the journey into JSON.\n\tmarshalledJourney, merr := objectJourney.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\", merr\n\t}\n\treturn string(marshalledJourney), nil\n}\n\n\n// GetZenStatus\n/* todo: leave it to the client\nfunc () GetZenStatus() (zenStatus string, err error) {\n\t// implementation\n}\n*/\n" - }, - { - "name": "errors.gno", - "body": "package zentasktic\n\nimport \"errors\"\n\nvar (\n\tErrTaskNotEditable \t= errors.New(\"Task is not editable\")\n\tErrProjectNotEditable = errors.New(\"Project is not editable\")\n\tErrProjectIdNotFound\t\t\t= errors.New(\"Project id not found\")\n\tErrTaskIdNotFound\t\t\t\t= errors.New(\"Task id not found\")\n\tErrTaskFailedToAssert\t\t\t= errors.New(\"Failed to assert Task type\")\n\tErrProjectFailedToAssert\t\t= errors.New(\"Failed to assert Project type\")\n\tErrProjectTasksNotFound\t\t\t= errors.New(\"Could not get tasks for project\")\n\tErrCollectionsProjectsNotFound\t= errors.New(\"Could not get projects for this collection\")\n\tErrCollectionsTasksNotFound\t\t= errors.New(\"Could not get tasks for this collection\")\n\tErrTaskIdAlreadyExists\t\t\t= errors.New(\"A task with the provided id already exists\")\n\tErrCollectionIdAlreadyExists\t= errors.New(\"A collection with the provided id already exists\")\n\tErrProjectIdAlreadyExists\t\t= errors.New(\"A project with the provided id already exists\")\n\tErrTaskByIdNotFound\t\t\t\t= errors.New(\"Can't get task by id\")\n\tErrProjectByIdNotFound\t\t\t= errors.New(\"Can't get project by id\")\n\tErrCollectionByIdNotFound\t\t= errors.New(\"Can't get collection by id\")\n\tErrTaskNotRemovable\t\t\t\t= errors.New(\"Cannot remove a task directly from this realm\")\n\tErrProjectNotRemovable\t\t\t= errors.New(\"Cannot remove a project directly from this realm\")\n\tErrProjectTasksNotRemoved\t\t= errors.New(\"Project tasks were not removed\")\n\tErrTaskNotRemoved\t\t\t\t= errors.New(\"Task was not removed\")\n\tErrTaskNotInAssessRealm\t\t\t= errors.New(\"Task is not in Assess, cannot edit Body\")\n\tErrProjectNotInAssessRealm\t\t= errors.New(\"Project is not in Assess, cannot edit Body\")\n\tErrContextIdAlreadyExists\t\t= errors.New(\"A context with the provided id already exists\")\n\tErrContextIdNotFound\t\t\t= errors.New(\"Context id not found\")\n\tErrCollectionIdNotFound\t\t\t= errors.New(\"Collection id not found\")\n\tErrContextNotRemoved\t\t\t= errors.New(\"Context was not removed\")\n\tErrProjectNotRemoved\t\t\t= errors.New(\"Project was not removed\")\n\tErrCollectionNotRemoved\t\t\t= errors.New(\"Collection was not removed\")\n\tErrObjectPathNotUpdated\t\t\t= errors.New(\"Object path wasn't updated\")\n\tErrInvalidateDateFormat\t\t\t= errors.New(\"Invalida date format\")\n\tErrInvalidDateFilterType\t\t= errors.New(\"Invalid date filter type\")\n\tErrRealmIdAlreadyExists\t\t\t= errors.New(\"A realm with the same id already exists\")\n\tErrRealmIdNotAllowed\t\t\t= errors.New(\"This is a reserved realm id\")\n\tErrRealmIdNotFound\t\t\t\t= errors.New(\"Realm id not found\")\n\tErrRealmNotRemoved\t\t\t\t= errors.New(\"Realm was not removed\")\n)" - }, - { - "name": "marshals.gno", - "body": "package zentasktic\n\nimport (\n\t\"bytes\"\n)\n\n\ntype ContextsObject struct {\n\tContexts\t[]Context\n}\n\ntype TasksObject struct {\n\tTasks\t[]Task\n}\n\ntype ProjectsObject struct {\n\tProjects\t[]Project\n}\n\ntype CollectionsObject struct {\n\tCollections\t[]Collection\n}\n\ntype RealmsObject struct {\n\tRealms\t[]Realm\n}\n\ntype ObjectJourney struct {\n\tObjectPaths []ObjectPath\n}\n\nfunc (c Context) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"contextId\":\"`)\n\tb.WriteString(c.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"contextName\":\"`)\n\tb.WriteString(c.Name)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (cs ContextsObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"contexts\":[`)\n\t\n\tfor i, context := range cs.Contexts {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tcontextJSON, cerr := context.MarshalJSON()\n\t\tif cerr == nil {\n\t\t\tb.WriteString(string(contextJSON))\n\t\t}\n\t}\n\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (t Task) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"taskId\":\"`)\n\tb.WriteString(t.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskProjectId\":\"`)\n\tb.WriteString(t.ProjectId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskContextId\":\"`)\n\tb.WriteString(t.ContextId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskRealmId\":\"`)\n\tb.WriteString(t.RealmId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskBody\":\"`)\n\tb.WriteString(t.Body)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskDue\":\"`)\n\tb.WriteString(t.Due)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"taskAlert\":\"`)\n\tb.WriteString(t.Alert)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (ts TasksObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"tasks\":[`)\n\tfor i, task := range ts.Tasks {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\ttaskJSON, cerr := task.MarshalJSON()\n\t\tif cerr == nil {\n\t\t\tb.WriteString(string(taskJSON))\n\t\t}\n\t}\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (p Project) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"projectId\":\"`)\n\tb.WriteString(p.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"projectContextId\":\"`)\n\tb.WriteString(p.ContextId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"projectRealmId\":\"`)\n\tb.WriteString(p.RealmId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"projectTasks\":[`)\n\n\tif len(p.Tasks) != 0 {\n\t\tfor i, projectTask := range p.Tasks {\n\t\t\tif i > 0 {\n\t\t\t\tb.WriteString(`,`)\n\t\t\t}\n\t\t\tprojectTaskJSON, perr := projectTask.MarshalJSON()\n\t\t\tif perr == nil {\n\t\t\t\tb.WriteString(string(projectTaskJSON))\n\t\t\t}\n\t\t}\n\t}\n\n\tb.WriteString(`],`)\n\n\tb.WriteString(`\"projectBody\":\"`)\n\tb.WriteString(p.Body)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"projectDue\":\"`)\n\tb.WriteString(p.Due)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (ps ProjectsObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"projects\":[`)\n\tfor i, project := range ps.Projects {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tprojectJSON, perr := project.MarshalJSON()\n\t\tif perr == nil {\n\t\t\tb.WriteString(string(projectJSON))\n\t\t}\n\t}\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (c Collection) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"collectionId\":\"`)\n\tb.WriteString(c.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"collectionRealmId\":\"`)\n\tb.WriteString(c.RealmId)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"collectionName\":\"`)\n\tb.WriteString(c.Name)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"collectionTasks\":[`)\n\tfor i, collectionTask := range c.Tasks {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tcollectionTaskJSON, perr := collectionTask.MarshalJSON()\n\t\tif perr == nil {\n\t\t\tb.WriteString(string(collectionTaskJSON))\n\t\t}\n\t}\n\tb.WriteString(`],`)\n\n\tb.WriteString(`\"collectionProjects\":[`)\n\tfor i, collectionProject := range c.Projects {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tcollectionProjectJSON, perr := collectionProject.MarshalJSON()\n\t\tif perr == nil {\n\t\t\tb.WriteString(string(collectionProjectJSON))\n\t\t}\n\t}\n\tb.WriteString(`],`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (co CollectionsObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"collections\":[`)\n\tfor i, collection := range co.Collections {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tcollectionJSON, perr := collection.MarshalJSON()\n\t\tif perr == nil {\n\t\t\tb.WriteString(string(collectionJSON))\n\t\t}\n\t}\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (r Realm) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"realmId\":\"`)\n\tb.WriteString(r.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"realmName\":\"`)\n\tb.WriteString(r.Name)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (rs RealmsObject) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"realms\":[`)\n\t\n\tfor i, realm := range rs.Realms {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\trealmJSON, rerr := realm.MarshalJSON()\n\t\tif rerr == nil {\n\t\t\tb.WriteString(string(realmJSON))\n\t\t}\n\t}\n\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n\nfunc (op ObjectPath) MarshalJSON() ([]byte, error) {\n\n\tvar b bytes.Buffer\n\t\n\tb.WriteByte('{')\n\n\tb.WriteString(`\"objectType\":\"`)\n\tb.WriteString(op.ObjectType)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"id\":\"`)\n\tb.WriteString(op.Id)\n\tb.WriteString(`\",`)\n\n\tb.WriteString(`\"realmId\":\"`)\n\tb.WriteString(op.RealmId)\n\tb.WriteString(`\"`)\n\n\tb.WriteByte('}')\n\n\treturn b.Bytes(), nil\n}\n\nfunc (oj ObjectJourney) MarshalJSON() ([]byte, error) {\n\tvar b bytes.Buffer\n\n\tb.WriteString(`{\"objectJourney\":[`)\n\t\n\tfor i, objectPath := range oj.ObjectPaths {\n\t\tif i > 0 {\n\t\t\tb.WriteString(`,`)\n\t\t}\n\t\tobjectPathJSON, oerr := objectPath.MarshalJSON()\n\t\tif oerr == nil {\n\t\t\tb.WriteString(string(objectPathJSON))\n\t\t}\n\t}\n\n\tb.WriteString(`]}`)\n\n\treturn b.Bytes(), nil\n}\n" - }, - { - "name": "projects.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"time\"\n\n\t\"gno.land/p/demo/avl\"\n)\n\n\ntype Project struct {\n\tId \t\t\tstring `json:\"projectId\"`\n\tContextId\tstring `json:\"projectContextId\"`\n\tRealmId \tstring `json:\"projectRealmId\"`\n\tTasks\t\t[]Task `json:\"projectTasks\"`\n\tBody \t\tstring `json:\"projectBody\"`\n\tDue\t\t\tstring `json:\"projectDue\"`\n}\n\ntype ZProjectManager struct {\n\tProjects *avl.Tree // projectId -> Project\n\tProjectTasks *avl.Tree // projectId -> []Task\n}\n\n\nfunc NewZProjectManager() *ZProjectManager {\n\treturn &ZProjectManager{\n\t\tProjects: avl.NewTree(),\n\t\tProjectTasks: avl.NewTree(),\n\t}\n}\n\n// actions\n\nfunc (zpm *ZProjectManager) AddProject(p Project) (err error) {\n\t// implementation\n\n\tif zpm.Projects.Size() != 0 {\n\t\t_, exist := zpm.Projects.Get(p.Id)\n\t\tif exist {\n\t\t\treturn ErrProjectIdAlreadyExists\n\t\t}\n\t}\n\tzpm.Projects.Set(p.Id, p)\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) RemoveProject(p Project) (err error) {\n\t// implementation, remove from ProjectTasks too\n\texistingProjectInterface, exist := zpm.Projects.Get(p.Id)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\t // project is removable only in Asses (RealmId 1) or via a Collection (RealmId 4)\n\tif existingProject.RealmId != \"1\" && existingProject.RealmId != \"4\" {\n\t\treturn ErrProjectNotRemovable\n\t}\n\n\t_, removed := zpm.Projects.Remove(existingProject.Id)\n\tif !removed {\n\t\treturn ErrProjectNotRemoved\n\t}\n\n\t// manage project tasks, if any\n\n\tif zpm.ProjectTasks.Size() != 0 {\n\t\t_, exist := zpm.ProjectTasks.Get(existingProject.Id)\n\t\tif !exist {\n\t\t\t// if there's no record in ProjectTasks, we don't have to remove anything\n\t\t\treturn nil\n\t\t} else {\n\t\t\t_, removed := zpm.ProjectTasks.Remove(existingProject.Id)\n\t\t\tif !removed {\n\t\t\t\treturn ErrProjectTasksNotRemoved\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) EditProject(p Project) (err error) {\n\t// implementation, get project by Id and replace the object\n\t// this is for the project body and realm, project tasks are managed in the Tasks object\n\texistingProject := Project{}\n\tif zpm.Projects.Size() != 0 {\n\t\t_, exist := zpm.Projects.Get(p.Id)\n\t\tif !exist {\n\t\t\treturn ErrProjectIdNotFound\n\t\t}\n\t}\n\t\n\t// project Body is editable only when project is in Assess, RealmId = \"1\"\n\tif p.RealmId != \"1\" {\n\t\tif p.Body != existingProject.Body {\n\t\t\treturn ErrProjectNotInAssessRealm\n\t\t}\n\t}\n\n\tzpm.Projects.Set(p.Id, p)\n\treturn nil\n}\n\n// helper function, we can achieve the same with EditProject() above\n/*func (zpm *ZProjectManager) MoveProjectToRealm(projectId string, realmId string) (err error) {\n\t// implementation\n\texistingProjectInterface, exist := zpm.Projects.Get(projectId)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\texistingProject.RealmId = realmId\n\tzpm.Projects.Set(projectId, existingProject)\n\treturn nil\n}*/\n\nfunc (zpm *ZProjectManager) MoveProjectToRealm(projectId string, realmId string) error {\n\t// Get the existing project from the Projects map\n\texistingProjectInterface, exist := zpm.Projects.Get(projectId)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\t// Set the project's RealmId to the new RealmId\n\texistingProject.RealmId = realmId\n\n\t// Get the existing project tasks from the ProjectTasks map\n\texistingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n\tif !texist {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\ttasks, ok := existingProjectTasksInterface.([]Task)\n\tif !ok {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\n\t// Iterate through the project's tasks and set their RealmId to the new RealmId\n\tfor i := range tasks {\n\t\ttasks[i].RealmId = realmId\n\t}\n\n\t// Set the updated tasks back into the ProjectTasks map\n\tzpm.ProjectTasks.Set(projectId, tasks)\n\n\t// Set the updated project back into the Projects map\n\tzpm.Projects.Set(projectId, existingProject)\n\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) MarkProjectTaskAsDone(projectId string, projectTaskId string) error {\n // Get the existing project from the Projects map\n existingProjectInterface, exist := zpm.Projects.Get(projectId)\n if !exist {\n return ErrProjectIdNotFound\n }\n existingProject := existingProjectInterface.(Project)\n\n // Get the existing project tasks from the ProjectTasks map\n existingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n if !texist {\n return ErrProjectTasksNotFound\n }\n tasks, ok := existingProjectTasksInterface.([]Task)\n if !ok {\n return ErrProjectTasksNotFound\n }\n\n // Iterate through the project's tasks to find the task to be updated\n var taskFound bool\n for i, task := range tasks {\n if task.Id == projectTaskId {\n tasks[i].RealmId = \"4\" // Change the RealmId to \"4\"\n taskFound = true\n break\n }\n }\n\n if !taskFound {\n return ErrTaskByIdNotFound\n }\n\n // Set the updated tasks back into the ProjectTasks map\n zpm.ProjectTasks.Set(existingProject.Id, tasks)\n\n return nil\n}\n\n\nfunc (zpm *ZProjectManager) GetProjectTasks(p Project) (tasks []Task, err error) {\n\t// implementation, query ProjectTasks and return the []Tasks object\n\tvar existingProjectTasks []Task\n\n\tif zpm.ProjectTasks.Size() != 0 {\n\t\tprojectTasksInterface, exist := zpm.ProjectTasks.Get(p.Id)\n\t\tif !exist {\n\t\t\treturn nil, ErrProjectTasksNotFound\n\t\t}\n\t\texistingProjectTasks = projectTasksInterface.([]Task)\n\t\treturn existingProjectTasks, nil\n\t}\n\treturn nil, nil\n}\n\nfunc (zpm *ZProjectManager) SetProjectDueDate(projectId string, dueDate string) (err error) {\n\tprojectInterface, exist := zpm.Projects.Get(projectId)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\tproject := projectInterface.(Project)\n\n\t// check to see if project is in RealmId = 2 (Decide)\n\tif project.RealmId == \"2\" {\n\t\tproject.Due = dueDate\n\t\tzpm.Projects.Set(project.Id, project)\n\t} else {\n\t\treturn ErrProjectNotEditable\n\t}\n\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) SetProjectTaskDueDate(projectId string, projectTaskId string, dueDate string) (err error){\n\texistingProjectInterface, exist := zpm.Projects.Get(projectId)\n if !exist {\n return ErrProjectIdNotFound\n }\n existingProject := existingProjectInterface.(Project)\n\n\tif existingProject.RealmId != \"2\" {\n\t\treturn ErrProjectNotEditable\n\t}\n\n existingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n if !texist {\n return ErrProjectTasksNotFound\n }\n tasks, ok := existingProjectTasksInterface.([]Task)\n if !ok {\n return ErrProjectTasksNotFound\n }\n existingProject.Tasks = tasks\n\n var index int = -1\n for i, task := range existingProject.Tasks {\n if task.Id == projectTaskId {\n index = i\n break\n }\n }\n\n if index != -1 {\n existingProject.Tasks[index].Due = dueDate\n } else {\n return ErrTaskByIdNotFound\n }\n\n zpm.ProjectTasks.Set(projectId, existingProject.Tasks)\n return nil\n}\n\n// getters\n\nfunc (zpm *ZProjectManager) GetProjectById(projectId string) (Project, error) {\n\tif zpm.Projects.Size() != 0 {\n\t\tpInterface, exist := zpm.Projects.Get(projectId)\n\t\tif exist {\n\t\t\treturn pInterface.(Project), nil\n\t\t}\n\t}\n\treturn Project{}, ErrProjectIdNotFound\n}\n\nfunc (zpm *ZProjectManager) GetAllProjects() (projects string) {\n\t// implementation\n\tvar allProjects []Project\n\t\n\t// Iterate over the Projects AVL tree to collect all Project objects.\n\t\n\tzpm.Projects.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif project, ok := value.(Project); ok {\n\t\t\t// get project tasks, if any\n\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\tif projectTasks != nil {\n\t\t\t\tproject.Tasks = projectTasks\n\t\t\t}\n\t\t\tallProjects = append(allProjects, project)\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a ProjectsObject with all collected tasks.\n\tprojectsObject := ProjectsObject{\n\t\tProjects: allProjects,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledProjects, merr := projectsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledProjects)\n}\n\nfunc (zpm *ZProjectManager) GetProjectsByRealm(realmId string) (projects string) {\n\t// implementation\n\tvar realmProjects []Project\n\t\n\t// Iterate over the Projects AVL tree to collect all Project objects.\n\t\n\tzpm.Projects.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif project, ok := value.(Project); ok {\n\t\t\tif project.RealmId == realmId {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\trealmProjects = append(realmProjects, project)\n\t\t\t}\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a ProjectsObject with all collected tasks.\n\tprojectsObject := ProjectsObject{\n\t\tProjects: realmProjects,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledProjects, merr := projectsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledProjects)\n}\n\nfunc (zpm *ZProjectManager) GetProjectsByContextAndRealm(contextId string, realmId string) (projects string) {\n\t// implementation\n\tvar contextProjects []Project\n\t\n\t// Iterate over the Projects AVL tree to collect all Project objects.\n\t\n\tzpm.Projects.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif project, ok := value.(Project); ok {\n\t\t\tif project.ContextId == contextId && project.RealmId == realmId {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\tcontextProjects = append(contextProjects, project)\n\t\t\t}\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\t// Create a ProjectsObject with all collected tasks.\n\tprojectsObject := ProjectsObject{\n\t\tProjects: contextProjects,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledProjects, merr := projectsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledProjects)\n}\n\nfunc (zpm *ZProjectManager) GetProjectsByDate(projectDate string, filterType string) (projects string) {\n\t// implementation\n\tparsedDate, err:= time.Parse(\"2006-01-02\", projectDate)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\tvar filteredProjects []Project\n\t\n\tzpm.Projects.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tproject, ok := value.(Project)\n\t\tif !ok {\n\t\t\treturn false // Skip this iteration and continue.\n\t\t}\n\n\t\tstoredDate, serr := time.Parse(\"2006-01-02\", project.Due)\n\t\tif serr != nil {\n\t\t\t// Skip projects with invalid dates.\n\t\t\treturn false\n\t\t}\n\n\t\tswitch filterType {\n\t\tcase \"specific\":\n\t\t\tif storedDate.Format(\"2006-01-02\") == parsedDate.Format(\"2006-01-02\") {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\tfilteredProjects = append(filteredProjects, project)\n\t\t\t}\n\t\tcase \"before\":\n\t\t\tif storedDate.Before(parsedDate) {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\tfilteredProjects = append(filteredProjects, project)\n\t\t\t}\n\t\tcase \"after\":\n\t\t\tif storedDate.After(parsedDate) {\n\t\t\t\t// get project tasks, if any\n\t\t\t\tprojectTasks, _ := zpm.GetProjectTasks(project)\n\t\t\t\tif projectTasks != nil {\n\t\t\t\t\tproject.Tasks = projectTasks\n\t\t\t\t}\n\t\t\t\tfilteredProjects = append(filteredProjects, project)\n\t\t\t}\n\t\t}\n\n\t\treturn false // Continue iteration.\n\t})\n\n\tif len(filteredProjects) == 0 {\n\t\treturn \"\"\n\t}\n\n\t// Create a ProjectsObject with all collected tasks.\n\tprojectsObject := ProjectsObject{\n\t\tProjects: filteredProjects,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledProjects, merr := projectsObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledProjects)\n\n}\n" - }, - { - "name": "projects_test.gno", - "body": "package zentasktic\n\nimport (\n\t\"testing\"\n\n \"gno.land/p/demo/avl\"\n)\n/*\nfunc Test_AddProject(t *testing.T) {\n \n project := Project{Id: \"1\", RealmId: \"1\", Body: \"First project\", ContextId: \"1\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n\n // Test adding a duplicate project.\n cerr := project.AddProject()\n if cerr != ErrProjectIdAlreadyExists {\n t.Errorf(\"Expected ErrProjectIdAlreadyExists, got %v\", cerr)\n }\n}\n\n\nfunc Test_RemoveProject(t *testing.T) {\n \n project := Project{Id: \"20\", Body: \"Removable project\", RealmId: \"1\", ContextId: \"2\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n\n retrievedProject, rerr := GetProjectById(project.Id)\n if rerr != nil {\n t.Errorf(\"Could not retrieve the added project\")\n }\n\n // Test removing a project\n terr := retrievedProject.RemoveProject()\n if terr != ErrProjectNotRemoved {\n t.Errorf(\"Expected ErrProjectNotRemoved, got %v\", terr)\n }\n}\n\n\nfunc Test_EditProject(t *testing.T) {\n \n project := Project{Id: \"2\", Body: \"Second project content\", RealmId: \"1\", ContextId: \"2\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n\n // Test editing the project\n editedProject := Project{Id: project.Id, Body: \"Edited project content\", RealmId: project.RealmId, ContextId: \"2\",}\n cerr := editedProject.EditProject()\n if cerr != nil {\n t.Errorf(\"Failed to edit the project\")\n }\n\n retrievedProject, _ := GetProjectById(editedProject.Id)\n if retrievedProject.Body != \"Edited project content\" {\n t.Errorf(\"Project was not edited\")\n }\n}\n\n\nfunc Test_MoveProjectToRealm(t *testing.T) {\n \n project := Project{Id: \"3\", Body: \"Project id 3 content\", RealmId: \"1\", ContextId: \"1\",}\n\n // Test adding a project successfully.\n err := project.AddProject()\n if err != nil {\n t.Errorf(\"Failed to add project: %v\", err)\n }\n\n // Test moving the project to another realm\n \n cerr := project.MoveProjectToRealm(\"2\")\n if cerr != nil {\n t.Errorf(\"Failed to move project to another realm\")\n }\n\n retrievedProject, _ := GetProjectById(project.Id)\n if retrievedProject.RealmId != \"2\" {\n t.Errorf(\"Project was moved to the wrong realm\")\n }\n}\n\nfunc Test_SetProjectDueDate(t *testing.T) {\n\tprojectRealmIdOne, _ := GetProjectById(\"1\")\n projectRealmIdTwo, _ := GetProjectById(\"10\") \n\t// Define test cases\n\ttests := []struct {\n\t\tname string\n\t\tproject Project\n\t\tdueDate string\n\t\twantErr error\n\t}{\n\t\t{\n\t\t\tname: \"Project does not exist\",\n\t\t\tproject: Project{Id: \"nonexistent\", RealmId: \"2\"},\n\t\t\twantErr: ErrProjectIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Project not editable due to wrong realm\",\n\t\t\tproject: projectRealmIdOne,\n\t\t\twantErr: ErrProjectNotEditable,\n\t\t},\n\t\t{\n\t\t\tname: \"Successfully set alert\",\n\t\t\tproject: projectRealmIdTwo,\n\t\t\tdueDate: \"2024-01-01\",\n\t\t\twantErr: nil,\n\t\t},\n\t}\n\n\t// Execute test cases\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.project.SetProjectDueDate(tc.dueDate)\n\n\t\t\t// Validate\n\t\t\tif err != tc.wantErr {\n\t\t\t\tt.Errorf(\"Expected error %v, got %v\", tc.wantErr, err)\n\t\t\t}\n\n\t\t\t// Additional check for the success case to ensure the due date was actually set\n\t\t\tif err == nil {\n\t\t\t\t// Fetch the task again to check if the due date was set correctly\n\t\t\t\tupdatedProject, exist := Projects.Get(tc.project.Id)\n\t\t\t\tif !exist {\n\t\t\t\t\tt.Fatalf(\"Project %v was not found after setting the due date\", tc.project.Id)\n\t\t\t\t}\n\t\t\t\tif updatedProject.(Project).Due != tc.dueDate {\n\t\t\t\t\tt.Errorf(\"Expected due date to be %v, got %v\", tc.dueDate, updatedProject.(Project).Due)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\n// getters\n\nfunc Test_GetAllProjects(t *testing.T) {\n \n // mocking the tasks based on previous tests\n // TODO: add isolation?\n knownProjects := []Project{\n {Id: \"1\", Body: \"First project\", RealmId: \"1\", ContextId: \"1\",},\n {Id: \"10\", Body: \"Project 10\", RealmId: \"2\", ContextId: \"2\", Due: \"2024-01-01\"},\n\t\t{Id: \"2\", Body: \"Edited project content\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"20\", Body: \"Removable project\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"21\", Body: \"Project 21\", RealmId: \"1\",},\n {Id: \"22\", Body: \"Project 22\", RealmId: \"1\",},\n\t\t{Id: \"3\", Body: \"Project id 3 content\", RealmId: \"2\", ContextId: \"1\",},\n }\n\n // Manually marshal the known projects to create the expected outcome.\n projectsObject := ProjectsObject{Projects: knownProjects}\n expected, err := projectsObject.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal known projects: %v\", err)\n }\n\n // Execute GetAllProjects() to get the actual outcome.\n actual, err := GetAllProjects()\n if err != nil {\n t.Fatalf(\"GetAllProjects() failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual project JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n\nfunc Test_GetProjectsByDate(t *testing.T) {\n\t\n\ttests := []struct {\n\t\tname string\n\t\tprojectDate string\n\t\tfilterType string\n\t\twant string\n\t\twantErr bool\n\t}{\n\t\t{\"SpecificDate\", \"2024-01-01\", \"specific\", `{\"projects\":[{\"projectId\":\"10\",\"projectContextId\":\"2\",\"projectRealmId\":\"2\",\"projectTasks\":[],\"projectBody\":\"Project 10\",\"projectDue\":\"2024-01-01\"}]}`, false},\n\t\t{\"BeforeDate\", \"2022-04-05\", \"before\", \"\", false},\n\t\t{\"AfterDate\", \"2025-04-05\", \"after\", \"\", false},\n\t\t{\"NoMatch\", \"2002-04-07\", \"specific\", \"\", false},\n\t\t{\"InvalidDateFormat\", \"April 5, 2023\", \"specific\", \"\", true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := GetProjectsByDate(tt.projectDate, tt.filterType)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"GetProjectsByDate() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err == nil && got != tt.want {\n\t\t\t\tt.Errorf(\"GetProjectsByDate() got = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_GetProjectTasks(t *testing.T){\n \n task := Task{Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",}\n\n project, perr := GetProjectById(\"1\")\n if perr != nil {\n t.Errorf(\"GetProjectById() failed, %v\", perr)\n }\n\n // test attaching to an existing project\n atterr := task.AttachTaskToProject(project)\n if atterr != nil {\n t.Errorf(\"AttachTaskToProject() failed, %v\", atterr)\n }\n\n projectTasks, pterr := project.GetProjectTasks()\n if len(projectTasks) == 0 {\n t.Errorf(\"GetProjectTasks() failed, %v\", pterr)\n }\n\n // test detaching from an existing project\n dtterr := task.DetachTaskFromProject(project)\n if dtterr != nil {\n t.Errorf(\"DetachTaskFromProject() failed, %v\", dtterr)\n }\n\n projectWithNoTasks, pterr := project.GetProjectTasks()\n if len(projectWithNoTasks) != 0 {\n t.Errorf(\"GetProjectTasks() after detach failed, %v\", pterr)\n }\n}\n\nfunc Test_GetProjectById(t *testing.T){\n // test getting a non-existing project\n nonProject, err := GetProjectById(\"0\")\n if err != ErrProjectByIdNotFound {\n t.Fatalf(\"Expected ErrProjectByIdNotFound, got: %v\", err)\n }\n\n // test getting the correct task by id\n correctProject, err := GetProjectById(\"1\")\n if err != nil {\n t.Fatalf(\"Failed to get project by id, error: %v\", err)\n }\n\n if correctProject.Body != \"First project\" {\n t.Fatalf(\"Got the wrong project, with body: %v\", correctProject.Body)\n }\n}\n\nfunc Test_GetProjectsByRealm(t *testing.T) {\n \n // mocking the projects based on previous tests\n // TODO: add isolation?\n projectsInAssessRealm := []Project{\n {Id: \"1\", Body: \"First project\", RealmId: \"1\", ContextId: \"1\",},\n\t\t{Id: \"2\", Body: \"Edited project content\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"20\", Body: \"Removable project\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"21\", Body: \"Project 21\", RealmId: \"1\",},\n {Id: \"22\", Body: \"Project 22\", RealmId: \"1\",},\n }\n\n // Manually marshal the known projects to create the expected outcome.\n projectsObjectAssess := ProjectsObject{Projects: projectsInAssessRealm}\n expected, err := projectsObjectAssess.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal projects in Assess: %v\", err)\n }\n\n actual, err := GetProjectsByRealm(\"1\")\n if err != nil {\n t.Fatalf(\"GetProjectByRealm('1') failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual projects JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n\nfunc Test_GetProjectsByContext(t *testing.T) {\n \n // mocking the projects based on previous tests\n // TODO: add isolation?\n projectsInContextOne := []Project{\n {Id: \"1\", Body: \"First project\", RealmId: \"1\", ContextId: \"1\",},\n\t\t{Id: \"3\", Body: \"Project id 3 content\", RealmId: \"2\", ContextId: \"1\",},\n }\n\n // Manually marshal the known tasks to create the expected outcome.\n projectsObjectForContexts := ProjectsObject{Projects: projectsInContextOne}\n expected, err := projectsObjectForContexts.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal projects for ContextId 1: %v\", err)\n }\n\n actual, err := GetProjectsByContext(\"1\")\n if err != nil {\n t.Fatalf(\"GetProjectsByContext('1') failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual project JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n*/\n\n" - }, - { - "name": "realms.gno", - "body": "// base implementation\npackage zentasktic\n\nimport (\n\t\"gno.land/p/demo/avl\"\n)\n\n// structs\n\ntype Realm struct {\n\tId \t\t\tstring `json:\"realmId\"`\n\tName \t\tstring `json:\"realmName\"`\n}\n\ntype ZRealmManager struct {\n\tRealms *avl.Tree\n}\n\nfunc NewZRealmManager() *ZRealmManager {\n\tzrm := &ZRealmManager{\n\t\tRealms: avl.NewTree(),\n\t}\n\tzrm.initializeHardcodedRealms()\n\treturn zrm\n}\n\n\nfunc (zrm *ZRealmManager) initializeHardcodedRealms() {\n\thardcodedRealms := []Realm{\n\t\t{Id: \"1\", Name: \"Assess\"},\n\t\t{Id: \"2\", Name: \"Decide\"},\n\t\t{Id: \"3\", Name: \"Do\"},\n\t\t{Id: \"4\", Name: \"Collections\"},\n\t}\n\n\tfor _, realm := range hardcodedRealms {\n\t\tzrm.Realms.Set(realm.Id, realm)\n\t}\n}\n\n\nfunc (zrm *ZRealmManager) AddRealm(r Realm) (err error){\n\t// implementation\n\tif zrm.Realms.Size() != 0 {\n\t\t_, exist := zrm.Realms.Get(r.Id)\n\t\tif exist {\n\t\t\treturn ErrRealmIdAlreadyExists\n\t\t}\n\t}\n\t// check for hardcoded values\n\tif r.Id == \"1\" || r.Id == \"2\" || r.Id == \"3\" || r.Id == \"4\" {\n\t\treturn ErrRealmIdNotAllowed\n\t}\n\tzrm.Realms.Set(r.Id, r)\n\treturn nil\n\t\n}\n\nfunc (zrm *ZRealmManager) RemoveRealm(r Realm) (err error){\n\t// implementation\n\tif zrm.Realms.Size() != 0 {\n\t\t_, exist := zrm.Realms.Get(r.Id)\n\t\tif !exist {\n\t\t\treturn ErrRealmIdNotFound\n\t\t} else {\n\t\t\t// check for hardcoded values, not removable\n\t\t\tif r.Id == \"1\" || r.Id == \"2\" || r.Id == \"3\" || r.Id == \"4\" {\n\t\t\t\treturn ErrRealmIdNotAllowed\n\t\t\t}\n\t\t}\n\t}\n\t\n\t_, removed := zrm.Realms.Remove(r.Id)\n\tif !removed {\n\t\treturn ErrRealmNotRemoved\n\t}\n\treturn nil\n\t\n}\n\n// getters\nfunc (zrm *ZRealmManager) GetRealmById(realmId string) (r Realm, err error) {\n\t// implementation\n\tif zrm.Realms.Size() != 0 {\n\t\trInterface, exist := zrm.Realms.Get(realmId)\n\t\tif exist {\n\t\t\treturn rInterface.(Realm), nil\n\t\t} else {\n\t\t\treturn Realm{}, ErrRealmIdNotFound\n\t\t}\n\t}\n\treturn Realm{}, ErrRealmIdNotFound\n}\n\nfunc (zrm *ZRealmManager) GetRealms() (realms string, err error) {\n\t// implementation\n\tvar allRealms []Realm\n\n\t// Iterate over the Realms AVL tree to collect all Context objects.\n\tzrm.Realms.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif realm, ok := value.(Realm); ok {\n\t\t\tallRealms = append(allRealms, realm)\n\t\t}\n\t\treturn false // Continue iteration until all nodes have been visited.\n\t})\n\n\n\t// Create a RealmsObject with all collected contexts.\n\trealmsObject := &RealmsObject{\n\t\tRealms: allRealms,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the realms into JSON.\n\tmarshalledRealms, rerr := realmsObject.MarshalJSON()\n\tif rerr != nil {\n\t\treturn \"\", rerr\n\t} \n\treturn string(marshalledRealms), nil\n}\n" - }, - { - "name": "tasks.gno", - "body": "package zentasktic\n\nimport (\n\t\"time\"\n\n\t\"gno.land/p/demo/avl\"\n)\n\ntype Task struct {\n\tId \t\t\tstring `json:\"taskId\"`\n\tProjectId \tstring `json:\"taskProjectId\"`\n\tContextId\tstring `json:\"taskContextId\"`\n\tRealmId \tstring `json:\"taskRealmId\"`\n\tBody \t\tstring `json:\"taskBody\"`\n\tDue\t\t\tstring `json:\"taskDue\"`\n\tAlert\t\tstring `json:\"taskAlert\"`\n}\n\ntype ZTaskManager struct {\n\tTasks *avl.Tree\n}\n\nfunc NewZTaskManager() *ZTaskManager {\n\treturn &ZTaskManager{\n\t\tTasks: avl.NewTree(),\n\t}\n}\n\n// actions\n\nfunc (ztm *ZTaskManager) AddTask(t Task) error {\n\tif ztm.Tasks.Size() != 0 {\n\t\t_, exist := ztm.Tasks.Get(t.Id)\n\t\tif exist {\n\t\t\treturn ErrTaskIdAlreadyExists\n\t\t}\n\t}\n\tztm.Tasks.Set(t.Id, t)\n\treturn nil\n}\n\nfunc (ztm *ZTaskManager) RemoveTask(t Task) error {\n\texistingTaskInterface, exist := ztm.Tasks.Get(t.Id)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\texistingTask := existingTaskInterface.(Task)\n\n\t // task is removable only in Asses (RealmId 1) or via a Collection (RealmId 4)\n\tif existingTask.RealmId != \"1\" && existingTask.RealmId != \"4\" {\n\t\treturn ErrTaskNotRemovable\n\t}\n\n\t_, removed := ztm.Tasks.Remove(existingTask.Id)\n\tif !removed {\n\t\treturn ErrTaskNotRemoved\n\t}\n\treturn nil\n}\n\nfunc (ztm *ZTaskManager) EditTask(t Task) error {\n\texistingTaskInterface, exist := ztm.Tasks.Get(t.Id)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\texistingTask := existingTaskInterface.(Task)\n\n\t// task Body is editable only when task is in Assess, RealmId = \"1\"\n\tif t.RealmId != \"1\" {\n\t\tif t.Body != existingTask.Body {\n\t\t\treturn ErrTaskNotInAssessRealm\n\t\t}\n\t}\n\n\tztm.Tasks.Set(t.Id, t)\n\treturn nil\n}\n\n// Helper function to move a task to a different realm\nfunc (ztm *ZTaskManager) MoveTaskToRealm(taskId, realmId string) error {\n\texistingTaskInterface, exist := ztm.Tasks.Get(taskId)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\texistingTask := existingTaskInterface.(Task)\n\texistingTask.RealmId = realmId\n\tztm.Tasks.Set(taskId, existingTask)\n\treturn nil\n}\n\nfunc (ztm *ZTaskManager) SetTaskDueDate(taskId, dueDate string) error {\n\ttaskInterface, exist := ztm.Tasks.Get(taskId)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\ttask := taskInterface.(Task)\n\n\tif task.RealmId == \"2\" {\n\t\ttask.Due = dueDate\n\t\tztm.Tasks.Set(task.Id, task)\n\t} else {\n\t\treturn ErrTaskNotEditable\n\t}\n\n\treturn nil\n}\n\nfunc (ztm *ZTaskManager) SetTaskAlert(taskId, alertDate string) error {\n\ttaskInterface, exist := ztm.Tasks.Get(taskId)\n\tif !exist {\n\t\treturn ErrTaskIdNotFound\n\t}\n\ttask := taskInterface.(Task)\n\n\tif task.RealmId == \"2\" {\n\t\ttask.Alert = alertDate\n\t\tztm.Tasks.Set(task.Id, task)\n\t} else {\n\t\treturn ErrTaskNotEditable\n\t}\n\n\treturn nil\n}\n\n// tasks & projects association\n\nfunc (zpm *ZProjectManager) AttachTaskToProject(ztm *ZTaskManager, t Task, p Project) error {\n\texistingProjectInterface, exist := zpm.Projects.Get(p.Id)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\texistingProjectTasksInterface, texist := zpm.ProjectTasks.Get(p.Id)\n\tif !texist {\n\t\texistingProject.Tasks = []Task{}\n\t} else {\n\t\ttasks, ok := existingProjectTasksInterface.([]Task)\n\t\tif !ok {\n\t\t\treturn ErrProjectTasksNotFound\n\t\t}\n\t\texistingProject.Tasks = tasks\n\t}\n\n\tt.ProjectId = p.Id\n\t// @todo we need to remove it from Tasks if it was previously added there, then detached\n\texistingTask, err := ztm.GetTaskById(t.Id)\n\tif err == nil {\n\t\tztm.RemoveTask(existingTask)\n\t}\n\tupdatedTasks := append(existingProject.Tasks, t)\n\tzpm.ProjectTasks.Set(p.Id, updatedTasks)\n\n\treturn nil\n}\n\nfunc (zpm *ZProjectManager) EditProjectTask(projectTaskId string, projectTaskBody string, projectId string) error {\n existingProjectInterface, exist := zpm.Projects.Get(projectId)\n if !exist {\n return ErrProjectIdNotFound\n }\n existingProject := existingProjectInterface.(Project)\n\n\tif existingProject.RealmId != \"1\" {\n\t\treturn ErrProjectNotEditable\n\t}\n\n existingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n if !texist {\n return ErrProjectTasksNotFound\n }\n tasks, ok := existingProjectTasksInterface.([]Task)\n if !ok {\n return ErrProjectTasksNotFound\n }\n existingProject.Tasks = tasks\n\n var index int = -1\n for i, task := range existingProject.Tasks {\n if task.Id == projectTaskId {\n index = i\n break\n }\n }\n\n if index != -1 {\n existingProject.Tasks[index].Body = projectTaskBody\n } else {\n return ErrTaskByIdNotFound\n }\n\n zpm.ProjectTasks.Set(projectId, existingProject.Tasks)\n return nil\n}\n\nfunc (zpm *ZProjectManager) DetachTaskFromProject(ztm *ZTaskManager, projectTaskId string, detachedTaskId string, p Project) error {\n\texistingProjectInterface, exist := zpm.Projects.Get(p.Id)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\texistingProjectTasksInterface, texist := zpm.ProjectTasks.Get(p.Id)\n\tif !texist {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\ttasks, ok := existingProjectTasksInterface.([]Task)\n\tif !ok {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\texistingProject.Tasks = tasks\n\n\tvar foundTask Task\n\tvar index int = -1\n\tfor i, task := range existingProject.Tasks {\n\t\tif task.Id == projectTaskId {\n\t\t\tindex = i\n\t\t\tfoundTask = task\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif index != -1 {\n\t\texistingProject.Tasks = append(existingProject.Tasks[:index], existingProject.Tasks[index+1:]...)\n\t} else {\n\t\treturn ErrTaskByIdNotFound\n\t}\n\n\tfoundTask.ProjectId = \"\"\n\tfoundTask.Id = detachedTaskId\n\t// Tasks and ProjectTasks have different storage, if a task is detached from a Project\n\t// we add it to the Tasks storage\n\tif err := ztm.AddTask(foundTask); err != nil {\n\t\treturn err\n\t}\n\n\tzpm.ProjectTasks.Set(p.Id, existingProject.Tasks)\n\treturn nil\n}\n\n\nfunc (zpm *ZProjectManager) RemoveTaskFromProject(projectTaskId string, projectId string) error {\n\texistingProjectInterface, exist := zpm.Projects.Get(projectId)\n\tif !exist {\n\t\treturn ErrProjectIdNotFound\n\t}\n\texistingProject := existingProjectInterface.(Project)\n\n\texistingProjectTasksInterface, texist := zpm.ProjectTasks.Get(projectId)\n\tif !texist {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\ttasks, ok := existingProjectTasksInterface.([]Task)\n\tif !ok {\n\t\treturn ErrProjectTasksNotFound\n\t}\n\texistingProject.Tasks = tasks\n\n\tvar index int = -1\n\tfor i, task := range existingProject.Tasks {\n\t\tif task.Id == projectTaskId {\n\t\t\tindex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif index != -1 {\n\t\texistingProject.Tasks = append(existingProject.Tasks[:index], existingProject.Tasks[index+1:]...)\n\t} else {\n\t\treturn ErrTaskByIdNotFound\n\t}\n\n\tzpm.ProjectTasks.Set(projectId, existingProject.Tasks)\n\treturn nil\n}\n\n// getters\n\nfunc (ztm *ZTaskManager) GetTaskById(taskId string) (Task, error) {\n\tif ztm.Tasks.Size() != 0 {\n\t\ttInterface, exist := ztm.Tasks.Get(taskId)\n\t\tif exist {\n\t\t\treturn tInterface.(Task), nil\n\t\t}\n\t}\n\treturn Task{}, ErrTaskIdNotFound\n}\n\nfunc (ztm *ZTaskManager) GetAllTasks() (task string) {\n\tvar allTasks []Task\n\n\tztm.Tasks.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif task, ok := value.(Task); ok {\n\t\t\tallTasks = append(allTasks, task)\n\t\t}\n\t\treturn false\n\t})\n\t// Create a TasksObject with all collected tasks.\n\ttasksObject := &TasksObject{\n\t\tTasks: allTasks,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledTasks, merr := tasksObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledTasks)\t\n}\n\nfunc (ztm *ZTaskManager) GetTasksByRealm(realmId string) (tasks string) {\n\tvar realmTasks []Task\n\n\tztm.Tasks.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif task, ok := value.(Task); ok {\n\t\t\tif task.RealmId == realmId {\n\t\t\t\trealmTasks = append(realmTasks, task)\n\t\t\t}\n\t\t}\n\t\treturn false\n\t})\n\n\t// Create a TasksObject with all collected tasks.\n\ttasksObject := &TasksObject{\n\t\tTasks: realmTasks,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledTasks, merr := tasksObject.MarshalJSON()\n\tif merr != nil {\n\t\t\treturn \"\"\n\t} \n\treturn string(marshalledTasks)\n}\n\nfunc (ztm *ZTaskManager) GetTasksByContextAndRealm(contextId string, realmId string) (tasks string) {\n\tvar contextTasks []Task\n\n\tztm.Tasks.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\tif task, ok := value.(Task); ok {\n\t\t\tif task.ContextId == contextId && task.ContextId == realmId {\n\t\t\t\tcontextTasks = append(contextTasks, task)\n\t\t\t}\n\t\t}\n\t\treturn false\n\t})\n\n\t// Create a TasksObject with all collected tasks.\n\ttasksObject := &TasksObject{\n\t\tTasks: contextTasks,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledTasks, merr := tasksObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledTasks)\n}\n\nfunc (ztm *ZTaskManager) GetTasksByDate(taskDate string, filterType string) (tasks string) {\n\tparsedDate, err := time.Parse(\"2006-01-02\", taskDate)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\tvar filteredTasks []Task\n\n\tztm.Tasks.Iterate(\"\", \"\", func(key string, value interface{}) bool {\n\t\ttask, ok := value.(Task)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\n\t\tstoredDate, serr := time.Parse(\"2006-01-02\", task.Due)\n\t\tif serr != nil {\n\t\t\treturn false\n\t\t}\n\n\t\tswitch filterType {\n\t\tcase \"specific\":\n\t\t\tif storedDate.Format(\"2006-01-02\") == parsedDate.Format(\"2006-01-02\") {\n\t\t\t\tfilteredTasks = append(filteredTasks, task)\n\t\t\t}\n\t\tcase \"before\":\n\t\t\tif storedDate.Before(parsedDate) {\n\t\t\t\tfilteredTasks = append(filteredTasks, task)\n\t\t\t}\n\t\tcase \"after\":\n\t\t\tif storedDate.After(parsedDate) {\n\t\t\t\tfilteredTasks = append(filteredTasks, task)\n\t\t\t}\n\t\t}\n\n\t\treturn false\n\t})\n\n\t// Create a TasksObject with all collected tasks.\n\ttasksObject := &TasksObject{\n\t\tTasks: filteredTasks,\n\t}\n\n\t// Use the custom MarshalJSON method to marshal the tasks into JSON.\n\tmarshalledTasks, merr := tasksObject.MarshalJSON()\n\tif merr != nil {\n\t\treturn \"\"\n\t} \n\treturn string(marshalledTasks)\n}\n" - }, - { - "name": "tasks_test.gno", - "body": "package zentasktic\n\nimport (\n\t\"testing\"\n\n \"gno.land/p/demo/avl\"\n)\n\n// Shared instance of ZTaskManager\nvar ztm *ZTaskManager\n\nfunc init() {\n ztm = NewZTaskManager()\n}\n\nfunc Test_AddTask(t *testing.T) {\n task := Task{Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",}\n\n // Test adding a task successfully.\n err := ztm.AddTask(task)\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n\n // Test adding a duplicate task.\n cerr := ztm.AddTask(task)\n if cerr != ErrTaskIdAlreadyExists {\n t.Errorf(\"Expected ErrTaskIdAlreadyExists, got %v\", cerr)\n }\n}\n\nfunc Test_RemoveTask(t *testing.T) {\n \n task := Task{Id: \"20\", Body: \"Removable task\", RealmId: \"1\"}\n\n // Test adding a task successfully.\n err := ztm.AddTask(task)\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n\n retrievedTask, rerr := ztm.GetTaskById(task.Id)\n if rerr != nil {\n t.Errorf(\"Could not retrieve the added task\")\n }\n\n // Test removing a task\n terr := ztm.RemoveTask(retrievedTask)\n if terr != nil {\n t.Errorf(\"Expected nil, got %v\", terr)\n }\n}\n\nfunc Test_EditTask(t *testing.T) {\n \n task := Task{Id: \"2\", Body: \"First content\", RealmId: \"1\", ContextId: \"2\"}\n\n // Test adding a task successfully.\n err := ztm.AddTask(task)\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n\n // Test editing the task\n editedTask := Task{Id: task.Id, Body: \"Edited content\", RealmId: task.RealmId, ContextId: \"2\"}\n cerr := ztm.EditTask(editedTask)\n if cerr != nil {\n t.Errorf(\"Failed to edit the task\")\n }\n\n retrievedTask, _ := ztm.GetTaskById(editedTask.Id)\n if retrievedTask.Body != \"Edited content\" {\n t.Errorf(\"Task was not edited\")\n }\n}\n/*\nfunc Test_MoveTaskToRealm(t *testing.T) {\n \n task := Task{Id: \"3\", Body: \"First content\", RealmId: \"1\", ContextId: \"1\"}\n\n // Test adding a task successfully.\n err := task.AddTask()\n if err != nil {\n t.Errorf(\"Failed to add task: %v\", err)\n }\n\n // Test moving the task to another realm\n \n cerr := task.MoveTaskToRealm(\"2\")\n if cerr != nil {\n t.Errorf(\"Failed to move task to another realm\")\n }\n\n retrievedTask, _ := GetTaskById(task.Id)\n if retrievedTask.RealmId != \"2\" {\n t.Errorf(\"Task was moved to the wrong realm\")\n }\n}\n\nfunc Test_AttachTaskToProject(t *testing.T) {\n \n // Example Projects and Tasks\n prj := Project{Id: \"1\", Body: \"Project 1\", RealmId: \"1\",}\n tsk := Task{Id: \"4\", Body: \"Task 4\", RealmId: \"1\",}\n\n Projects.Set(prj.Id, prj) // Mock existing project\n\n tests := []struct {\n name string\n project Project\n task Task\n wantErr bool\n errMsg error\n }{\n {\n name: \"Attach to existing project\",\n project: prj,\n task: tsk,\n wantErr: false,\n },\n {\n name: \"Attach to non-existing project\",\n project: Project{Id: \"200\", Body: \"Project 200\", RealmId: \"1\",},\n task: tsk,\n wantErr: true,\n errMsg: ErrProjectIdNotFound,\n },\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n err := tt.task.AttachTaskToProject(tt.project)\n if (err != nil) != tt.wantErr {\n t.Errorf(\"AttachTaskToProject() error = %v, wantErr %v\", err, tt.wantErr)\n }\n if tt.wantErr && err != tt.errMsg {\n t.Errorf(\"AttachTaskToProject() error = %v, expected %v\", err, tt.errMsg)\n }\n\n // For successful attach, verify the task is added to the project's tasks.\n if !tt.wantErr {\n tasks, exist := ProjectTasks.Get(tt.project.Id)\n if !exist || len(tasks.([]Task)) == 0 {\n t.Errorf(\"Task was not attached to the project\")\n } else {\n found := false\n for _, task := range tasks.([]Task) {\n if task.Id == tt.task.Id {\n found = true\n break\n }\n }\n if !found {\n t.Errorf(\"Task was not attached to the project\")\n }\n }\n }\n })\n }\n}\n\nfunc TestDetachTaskFromProject(t *testing.T) {\n\t\n\t// Setup:\n\tproject := Project{Id: \"p1\", Body: \"Test Project\"}\n\ttask1 := Task{Id: \"5\", Body: \"Task One\"}\n\ttask2 := Task{Id: \"6\", Body: \"Task Two\"}\n\n\tProjects.Set(project.Id, project)\n\tProjectTasks.Set(project.Id, []Task{task1, task2})\n\n\ttests := []struct {\n\t\tname string\n\t\ttask Task\n\t\tproject Project\n\t\twantErr bool\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname: \"Detach existing task from project\",\n\t\t\ttask: task1,\n\t\t\tproject: project,\n\t\t\twantErr: false,\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to detach task from non-existing project\",\n\t\t\ttask: task1,\n\t\t\tproject: Project{Id: \"nonexistent\"},\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrProjectIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Try to detach non-existing task from project\",\n\t\t\ttask: Task{Id: \"nonexistent\"},\n\t\t\tproject: project,\n\t\t\twantErr: true,\n\t\t\texpectedErr: ErrTaskByIdNotFound,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.task.DetachTaskFromProject(tt.project)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tif err == nil || err != tt.expectedErr {\n\t\t\t\t\tt.Errorf(\"%s: expected error %v, got %v\", tt.name, tt.expectedErr, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"%s: unexpected error: %v\", tt.name, err)\n\t\t\t\t}\n\n\t\t\t\t// For successful detachment, verify the task is no longer part of the project's tasks\n\t\t\t\tif !tt.wantErr {\n\t\t\t\t\ttasks, _ := ProjectTasks.Get(tt.project.Id)\n\t\t\t\t\tfor _, task := range tasks.([]Task) {\n\t\t\t\t\t\tif task.Id == tt.task.Id {\n\t\t\t\t\t\t\tt.Errorf(\"%s: task was not detached from the project\", tt.name)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_SetTaskDueDate(t *testing.T) {\n\ttaskRealmIdOne, _ := GetTaskById(\"1\")\n taskRealmIdTwo, _ := GetTaskById(\"10\") \n\t// Define test cases\n\ttests := []struct {\n\t\tname string\n\t\ttask Task\n\t\tdueDate string\n\t\twantErr error\n\t}{\n\t\t{\n\t\t\tname: \"Task does not exist\",\n\t\t\ttask: Task{Id: \"nonexistent\", RealmId: \"2\"},\n\t\t\twantErr: ErrTaskIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Task not editable due to wrong realm\",\n\t\t\ttask: taskRealmIdOne,\n\t\t\twantErr: ErrTaskNotEditable,\n\t\t},\n\t\t{\n\t\t\tname: \"Successfully set due date\",\n\t\t\ttask: taskRealmIdTwo,\n\t\t\tdueDate: \"2023-01-01\",\n\t\t\twantErr: nil,\n\t\t},\n\t}\n\n\t// Execute test cases\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.task.SetTaskDueDate(tc.dueDate)\n\n\t\t\t// Validate\n\t\t\tif err != tc.wantErr {\n\t\t\t\tt.Errorf(\"Expected error %v, got %v\", tc.wantErr, err)\n\t\t\t}\n\n\t\t\t// Additional check for the success case to ensure the due date was actually set\n\t\t\tif err == nil {\n\t\t\t\t// Fetch the task again to check if the due date was set correctly\n\t\t\t\tupdatedTask, exist := Tasks.Get(tc.task.Id)\n\t\t\t\tif !exist {\n\t\t\t\t\tt.Fatalf(\"Task %v was not found after setting the due date\", tc.task.Id)\n\t\t\t\t}\n\t\t\t\tif updatedTask.(Task).Due != tc.dueDate {\n\t\t\t\t\tt.Errorf(\"Expected due date to be %v, got %v\", tc.dueDate, updatedTask.(Task).Due)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_SetTaskAlert(t *testing.T) {\n\ttaskRealmIdOne, _ := GetTaskById(\"1\")\n taskRealmIdTwo, _ := GetTaskById(\"10\") \n\t// Define test cases\n\ttests := []struct {\n\t\tname string\n\t\ttask Task\n\t\talertDate string\n\t\twantErr error\n\t}{\n\t\t{\n\t\t\tname: \"Task does not exist\",\n\t\t\ttask: Task{Id: \"nonexistent\", RealmId: \"2\"},\n\t\t\twantErr: ErrTaskIdNotFound,\n\t\t},\n\t\t{\n\t\t\tname: \"Task not editable due to wrong realm\",\n\t\t\ttask: taskRealmIdOne,\n\t\t\twantErr: ErrTaskNotEditable,\n\t\t},\n\t\t{\n\t\t\tname: \"Successfully set alert\",\n\t\t\ttask: taskRealmIdTwo,\n\t\t\talertDate: \"2024-01-01\",\n\t\t\twantErr: nil,\n\t\t},\n\t}\n\n\t// Execute test cases\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.task.SetTaskAlert(tc.alertDate)\n\n\t\t\t// Validate\n\t\t\tif err != tc.wantErr {\n\t\t\t\tt.Errorf(\"Expected error %v, got %v\", tc.wantErr, err)\n\t\t\t}\n\n\t\t\t// Additional check for the success case to ensure the due date was actually set\n\t\t\tif err == nil {\n\t\t\t\t// Fetch the task again to check if the due date was set correctly\n\t\t\t\tupdatedTask, exist := Tasks.Get(tc.task.Id)\n\t\t\t\tif !exist {\n\t\t\t\t\tt.Fatalf(\"Task %v was not found after setting the due date\", tc.task.Id)\n\t\t\t\t}\n\t\t\t\tif updatedTask.(Task).Alert != tc.alertDate {\n\t\t\t\t\tt.Errorf(\"Expected due date to be %v, got %v\", tc.alertDate, updatedTask.(Task).Due)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\n// getters\n\nfunc Test_GetAllTasks(t *testing.T) {\n \n // mocking the tasks based on previous tests\n // TODO: add isolation?\n knownTasks := []Task{\n {Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",},\n {Id: \"10\", Body: \"First content\", RealmId: \"2\", ContextId: \"2\", Due: \"2023-01-01\", Alert: \"2024-01-01\"},\n {Id: \"2\", Body: \"Edited content\", RealmId: \"1\", ContextId: \"2\",},\n {Id: \"20\", Body: \"Removable task\", RealmId: \"1\",},\n {Id: \"3\", Body: \"First content\", RealmId: \"2\", ContextId: \"1\",},\n {Id: \"40\", Body: \"Task 40\", RealmId: \"1\",},\n }\n\n // Manually marshal the known tasks to create the expected outcome.\n tasksObject := TasksObject{Tasks: knownTasks}\n expected, err := tasksObject.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal known tasks: %v\", err)\n }\n\n // Execute GetAllTasks() to get the actual outcome.\n actual, err := GetAllTasks()\n if err != nil {\n t.Fatalf(\"GetAllTasks() failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual task JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n\nfunc Test_GetTasksByDate(t *testing.T) {\n\t\n\ttests := []struct {\n\t\tname string\n\t\ttaskDate string\n\t\tfilterType string\n\t\twant string\n\t\twantErr bool\n\t}{\n\t\t{\"SpecificDate\", \"2023-01-01\", \"specific\", `{\"tasks\":[{\"taskId\":\"10\",\"taskProjectId\":\"\",\"taskContextId\":\"2\",\"taskRealmId\":\"2\",\"taskBody\":\"First content\",\"taskDue\":\"2023-01-01\",\"taskAlert\":\"2024-01-01\"}]}`, false},\n\t\t{\"BeforeDate\", \"2022-04-05\", \"before\", \"\", false},\n\t\t{\"AfterDate\", \"2023-04-05\", \"after\", \"\", false},\n\t\t{\"NoMatch\", \"2002-04-07\", \"specific\", \"\", false},\n\t\t{\"InvalidDateFormat\", \"April 5, 2023\", \"specific\", \"\", true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := GetTasksByDate(tt.taskDate, tt.filterType)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"GetTasksByDate() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err == nil && got != tt.want {\n\t\t\t\tt.Errorf(\"GetTasksByDate() got = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_GetTaskById(t *testing.T){\n // test getting a non-existing task\n nonTask, err := GetTaskById(\"0\")\n if err != ErrTaskByIdNotFound {\n t.Fatalf(\"Expected ErrTaskByIdNotFound, got: %v\", err)\n }\n\n // test getting the correct task by id\n correctTask, err := GetTaskById(\"1\")\n if err != nil {\n t.Fatalf(\"Failed to get task by id, error: %v\", err)\n }\n\n if correctTask.Body != \"First task\" {\n t.Fatalf(\"Got the wrong task, with body: %v\", correctTask.Body)\n }\n}\n\nfunc Test_GetTasksByRealm(t *testing.T) {\n \n // mocking the tasks based on previous tests\n // TODO: add isolation?\n tasksInAssessRealm := []Task{\n {Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",},\n {Id: \"2\", RealmId: \"1\", Body: \"Edited content\", ContextId: \"2\",},\n {Id: \"20\", Body: \"Removable task\", RealmId: \"1\",},\n {Id: \"40\", Body: \"Task 40\", RealmId: \"1\",},\n }\n\n // Manually marshal the known tasks to create the expected outcome.\n tasksObjectAssess := TasksObject{Tasks: tasksInAssessRealm}\n expected, err := tasksObjectAssess.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal tasks in Assess: %v\", err)\n }\n\n actual, err := GetTasksByRealm(\"1\")\n if err != nil {\n t.Fatalf(\"GetTasksByRealm('1') failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual task JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n\nfunc Test_GetTasksByContext(t *testing.T) {\n \n // mocking the tasks based on previous tests\n // TODO: add isolation?\n tasksInContextOne := []Task{\n {Id: \"1\", RealmId: \"1\", Body: \"First task\", ContextId: \"1\",},\n {Id: \"3\", RealmId: \"2\", Body: \"First content\", ContextId: \"1\",},\n }\n\n // Manually marshal the known tasks to create the expected outcome.\n tasksObjectForContexts := TasksObject{Tasks: tasksInContextOne}\n expected, err := tasksObjectForContexts.MarshalJSON()\n if err != nil {\n t.Fatalf(\"Failed to manually marshal tasks for ContextId 1: %v\", err)\n }\n\n actual, err := GetTasksByContext(\"1\")\n if err != nil {\n t.Fatalf(\"GetTasksByContext('1') failed with error: %v\", err)\n }\n\n // Compare the expected and actual outcomes.\n if string(expected) != actual {\n t.Errorf(\"Expected and actual task JSON strings do not match.\\nExpected: %s\\nActual: %s\", string(expected), actual)\n }\n}\n*/\n" - } - ] - }, - "deposit": "" - } - ], - "fee": { - "gas_wanted": "15000000", - "gas_fee": "1000000ugnot" - }, - "signatures": [], - "memo": "" -} - --- tx3.tx -- -{ - "msg": [ - { - "@type": "/vm.m_addpkg", - "creator": "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5", - "package": { - "name": "zentasktic_core", - "path": "gno.land/r/g17ernafy6ctpcz6uepfsq2js8x2vz0wladh5yc3/zentasktic_core", - "files": [ - { - "name": "workable.gno", - "body": "package zentasktic_core\n\ntype Workable interface {\n\t// restrict implementation of Workable to this realm\n\tassertWorkable()\n}\n\ntype isWorkable struct {}\n\nfunc (wt *WorkableTask) assertWorkable() {}\n\nfunc (wp *WorkableProject) assertWorkable() {}\n\nvar _ Workable = &WorkableTask{}\nvar _ Workable = &WorkableProject{}\n" - }, - { - "name": "wrapper.gno", - "body": "package zentasktic_core\n\n\nimport (\n\t\"strconv\"\n\n\t\"gno.land/p/g17ernafy6ctpcz6uepfsq2js8x2vz0wladh5yc3/zentasktic\"\n)\n\n// this is a convenience wrapper on top of the functions declared in the zentasktic package\n// to maintain consistency\n\n// wrapping zentasktic types\n\ntype WorkableTask struct {\n zentasktic.Task\n}\ntype WorkableProject struct {\n zentasktic.Project\n}\n\ntype WorkableRealm struct {\n\tId string\n\tName string\n}\n\ntype WorkableContext struct {\n\tzentasktic.Context\n}\n\ntype WorkableCollection struct {\n\tzentasktic.Collection\n}\n\ntype WorkableObjectPath struct {\n\tzentasktic.ObjectPath\n}\n\n// zentasktic managers\n\nvar ztm *zentasktic.ZTaskManager\nvar zpm *zentasktic.ZProjectManager\nvar zrm *zentasktic.ZRealmManager\nvar zcm *zentasktic.ZContextManager\nvar zcl *zentasktic.ZCollectionManager\nvar zom *zentasktic.ZObjectPathManager\nvar currentTaskID int\nvar currentProjectTaskID int\nvar currentProjectID int\nvar currentContextID int\nvar currentCollectionID int\nvar currentPathID int\n\nfunc init() {\n ztm = zentasktic.NewZTaskManager()\n zpm = zentasktic.NewZProjectManager()\n\tzrm = zentasktic.NewZRealmManager()\n\tzcm = zentasktic.NewZContextManager()\n\tzcl = zentasktic.NewZCollectionManager()\n\tzom = zentasktic.NewZObjectPathManager()\n\tcurrentTaskID = 0\n\tcurrentProjectTaskID = 0\n\tcurrentProjectID = 0\n\tcurrentContextID = 0\n\tcurrentCollectionID = 0\n\tcurrentPathID = 0\n}\n\n// tasks\n\nfunc AddTask(taskBody string) error {\n\ttaskID := incrementTaskID()\n\twt := &WorkableTask{\n\t\tTask: zentasktic.Task{\n\t\t\tId: strconv.Itoa(taskID),\n\t\t\tBody: taskBody,\n\t\t\tRealmId: \t \"1\",\n\t\t},\n\t}\n\treturn ztm.AddTask(wt.Task)\n}\n\n\nfunc EditTask(taskId string, taskBody string) error {\n\ttaskToEdit, err := GetTaskById(taskId)\n\tif err != nil {\n\t\treturn err\t\n\t}\n\ttaskToEdit.Body = taskBody;\n\treturn ztm.EditTask(taskToEdit.Task)\n}\n\nfunc RemoveTask(taskId string) error {\n\ttaskToRemove, err := GetTaskById(taskId)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn ztm.RemoveTask(taskToRemove.Task)\n}\n\nfunc MoveTaskToRealm(taskId string, realmId string) error {\n\treturn ztm.MoveTaskToRealm(taskId, realmId)\n}\n\nfunc SetTaskDueDate(taskId string, dueDate string) error {\n\treturn ztm.SetTaskDueDate(taskId, dueDate)\n}\n\nfunc SetTaskAlert(taskId string, alert string) error {\n\treturn ztm.SetTaskAlert(taskId, alert)\n}\n\nfunc AttachTaskToProject(taskBody string, projectId string) error {\n\tprojectTaskID := incrementProjectTaskID()\n\twt := &WorkableTask{\n\t\tTask: zentasktic.Task{\n\t\t\tId: strconv.Itoa(projectTaskID),\n\t\t\tBody: taskBody,\n\t\t\tRealmId: \t \"1\",\n\t\t},\n\t}\n\t//ztm.AddTask(wt.Task)\n\tprojectToAdd, err := GetProjectById(projectId)\n\tif err != nil {\n\t\treturn err\t\n\t}\n\treturn zpm.AttachTaskToProject(ztm, wt.Task, projectToAdd.Project)\n}\n\nfunc EditProjectTask(projectTaskId string, projectTaskBody string, projectId string) error {\n\treturn zpm.EditProjectTask(projectTaskId, projectTaskBody, projectId)\n}\n\nfunc DetachTaskFromProject(projectTaskId string, projectId string) error {\n\tprojectToDetachFrom, err := GetProjectById(projectId)\n\tif err != nil {\n\t\treturn err\t\n\t}\n\tdetachedTaskId := strconv.Itoa(incrementTaskID())\n\treturn zpm.DetachTaskFromProject(ztm, projectTaskId, detachedTaskId, projectToDetachFrom.Project)\n}\n\nfunc RemoveTaskFromProject(projectTaskId string, projectId string) error {\n\treturn zpm.RemoveTaskFromProject(projectTaskId, projectId)\n}\n\nfunc GetTaskById(taskId string) (WorkableTask, error) {\n\ttask, err := ztm.GetTaskById(taskId)\n\tif err != nil {\n\t\treturn WorkableTask{}, err\n\t}\n\treturn WorkableTask{Task: task}, nil\n}\n\nfunc GetAllTasks() (string){\n\treturn ztm.GetAllTasks()\n}\n\nfunc GetTasksByRealm(realmId string) (string){\n\treturn ztm.GetTasksByRealm(realmId)\n}\n\nfunc GetTasksByContextAndRealm(contextId string, realmId string) (string){\n\treturn ztm.GetTasksByContextAndRealm(contextId, realmId)\n}\n\nfunc GetTasksByDate(dueDate string, filterType string) (string){\n\treturn ztm.GetTasksByDate(dueDate, filterType)\n}\n\nfunc incrementTaskID() int {\n\tcurrentTaskID++\n\treturn currentTaskID\n}\n\nfunc incrementProjectTaskID() int {\n\tcurrentProjectTaskID++\n\treturn currentProjectTaskID\n}\n\n// projects\n\nfunc AddProject(projectBody string) error {\n\tprojectID := incrementProjectID()\n\twp := &WorkableProject{\n\t\tProject: zentasktic.Project{\n\t\t\tId: strconv.Itoa(projectID),\n\t\t\tBody: projectBody,\n\t\t\tRealmId: \t \"1\",\n\t\t},\n\t}\n\treturn zpm.AddProject(wp.Project)\n}\n\nfunc EditProject(projectId string, projectBody string) error {\n\tprojectToEdit, err := GetProjectById(projectId)\n\tif err != nil {\n\t\treturn err\t\n\t}\n\tprojectToEdit.Body = projectBody;\n\treturn zpm.EditProject(projectToEdit.Project)\n}\n\nfunc RemoveProject(projectId string) error {\n\tprojectToRemove, err := GetProjectById(projectId)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn zpm.RemoveProject(projectToRemove.Project)\n}\n\nfunc MoveProjectToRealm(projectId string, realmId string) error {\n\treturn zpm.MoveProjectToRealm(projectId, realmId)\n}\n\nfunc MarkProjectTaskAsDone(projectId string, projectTaskId string) error {\n\treturn zpm.MarkProjectTaskAsDone(projectId, projectTaskId)\n}\n\nfunc GetProjectTasks(wp WorkableProject) ([]WorkableTask, error){\n\ttasks, err := zpm.GetProjectTasks(wp.Project)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Convert []zentasktic.Task to []WorkableTask\n\tvar workableTasks []WorkableTask\n\tfor _, task := range tasks {\n\t\tworkableTasks = append(workableTasks, WorkableTask{Task: task})\n\t}\n\n\treturn workableTasks, nil\n}\n\nfunc SetProjectDueDate(projectId string, dueDate string) error {\n\treturn zpm.SetProjectDueDate(projectId, dueDate)\n}\n\nfunc GetProjectById(projectId string) (WorkableProject, error) {\n\tproject, err := zpm.GetProjectById(projectId)\n\tif err != nil {\n\t\treturn WorkableProject{}, err\n\t}\n\treturn WorkableProject{Project: project}, nil\n}\n\nfunc SetProjectTaskDueDate(projectId string, projectTaskId string, dueDate string) error {\n\treturn zpm.SetProjectTaskDueDate(projectId, projectTaskId, dueDate)\n}\n\nfunc GetAllProjects() (string){\n\treturn zpm.GetAllProjects()\n}\n\nfunc GetProjectsByRealm(realmId string) (string){\n\treturn zpm.GetProjectsByRealm(realmId)\n}\n\nfunc GetProjectsByContextAndRealm(contextId string, realmId string) (string){\n\treturn zpm.GetProjectsByContextAndRealm(contextId, realmId)\n}\n\nfunc GetProjectsByDate(dueDate string, filterType string) (string){\n\treturn zpm.GetProjectsByDate(dueDate, filterType)\n}\n\nfunc incrementProjectID() int {\n\tcurrentProjectID++\n\treturn currentProjectID\n}\n\n// realms\n\nfunc AddRealm(wr WorkableRealm) error {\n\tr := zentasktic.Realm{\n\t\tId: wr.Id,\n\t\tName: wr.Name,\n\t}\n\treturn zrm.AddRealm(r)\n}\n\nfunc RemoveRealm(wr WorkableRealm) error {\n\tr := zentasktic.Realm{\n\t\tId: wr.Id,\n\t\tName: wr.Name,\n\t}\n\treturn zrm.RemoveRealm(r)\n}\n\nfunc GetRealmById(realmId string) (WorkableRealm, error) {\n\tr, err := zrm.GetRealmById(realmId)\n\tif err != nil {\n\t\treturn WorkableRealm{}, err\n\t}\n\treturn WorkableRealm{\n\t\tId: r.Id,\n\t\tName: r.Name,\n\t}, nil\n}\n\nfunc GetAllRealms() (string, error) {\n\treturn zrm.GetRealms()\n}\n\n// contexts\n\nfunc AddContext(contextName string) error {\n\tcontextID := incrementContextID()\n\twc := &WorkableContext{\n\t\tContext: zentasktic.Context{\n\t\t\tId: strconv.Itoa(contextID),\n\t\t\tName: contextName,\n\t\t},\n\t}\n\treturn zcm.AddContext(wc.Context)\n}\n\nfunc EditContext(contextId string, newContext string) error {\n\tcontextToEdit, err := GetContextById(contextId)\n\tif err != nil {\n\t\treturn err\t\n\t}\n\tcontextToEdit.Name = newContext;\n\treturn zcm.EditContext(contextToEdit.Context)\n}\n\nfunc RemoveContext(contextId string) error {\n\tcontextToRemove, err := GetContextById(contextId)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn zcm.RemoveContext(contextToRemove.Context)\n}\n\nfunc AddContextToTask(contextId string, taskId string) error {\n\tcontextToAdd, err := GetContextById(contextId)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttaskToAddContextTo, merr := GetTaskById(taskId)\n\tif merr != nil {\n\t\treturn merr\n\t}\n\treturn zcm.AddContextToTask(ztm, contextToAdd.Context, taskToAddContextTo.Task)\n}\n\nfunc AddContextToProject(contextId string, projectId string) error {\n\tcontextToAdd, err := GetContextById(contextId)\n\tif err != nil {\n\t\treturn err\n\t}\n\tprojectToAddContextTo, merr := GetProjectById(projectId)\n\tif merr != nil {\n\t\treturn merr\n\t}\n\treturn zcm.AddContextToProject(zpm, contextToAdd.Context, projectToAddContextTo.Project)\n}\n\nfunc AddContextToProjectTask(contextId string, projectId string, projectTaskId string) error {\n\tcontextToAdd, err := GetContextById(contextId)\n\tif err != nil {\n\t\treturn err\n\t}\n\tprojectToAddContextTo, merr := GetProjectById(projectId)\n\tif merr != nil {\n\t\treturn merr\n\t}\n\treturn zcm.AddContextToProjectTask(zpm, contextToAdd.Context, projectToAddContextTo.Project, projectTaskId)\n}\n\nfunc GetContextById(contextId string) (WorkableContext, error) {\n\tcontext, err := zcm.GetContextById(contextId)\n\tif err != nil {\n\t\treturn WorkableContext{}, err\n\t}\n\treturn WorkableContext{Context: context}, nil\n}\n\nfunc GetAllContexts() (string) {\n\treturn zcm.GetAllContexts()\n}\n\nfunc incrementContextID() int {\n\tcurrentContextID++\n\treturn currentContextID\n}\n\n// collections\n/*\nfunc AddCollection(wc WorkableCollection) error {\n\tc := zentasktic.Collection{\n\t\tId: wc.Id,\n\t\tRealmId: wc.RealmId,\n\t\tName: wc.Name,\n\t\tTasks: toZentaskticTasks(wc.Tasks),\n\t\tProjects: toZentaskticProjects(wc.Projects),\n\t}\n\treturn zcl.AddCollection(c)\n}\n\nfunc EditCollection(wc WorkableCollection) error {\n\tc := zentasktic.Collection{\n\t\tId: wc.Id,\n\t\tRealmId: wc.RealmId,\n\t\tName: wc.Name,\n\t\tTasks: toZentaskticTasks(wc.Tasks),\n\t\tProjects: toZentaskticProjects(wc.Projects),\n\t}\n\treturn zcl.EditCollection(c)\n}\n\nfunc RemoveCollection(wc WorkableCollection) error {\n\tc := zentasktic.Collection{\n\t\tId: wc.Id,\n\t\tRealmId: wc.RealmId,\n\t\tName: wc.Name,\n\t\tTasks: toZentaskticTasks(wc.Tasks),\n\t\tProjects: toZentaskticProjects(wc.Projects),\n\t}\n\treturn zcl.RemoveCollection(c)\n}\n\nfunc GetCollectionById(collectionId string) (WorkableCollection, error) {\n\tc, err := zcl.GetCollectionById(collectionId)\n\tif err != nil {\n\t\treturn WorkableCollection{}, err\n\t}\n\treturn WorkableCollection{\n\t\tId: c.Id,\n\t\tRealmId: c.RealmId,\n\t\tName: c.Name,\n\t\tTasks: toWorkableTasks(c.Tasks),\n\t\tProjects: toWorkableProjects(c.Projects),\n\t}, nil\n}\n\nfunc GetCollectionTasks(wc WorkableCollection) ([]WorkableTask, error) {\n\tc := zentasktic.Collection{\n\t\tId: wc.Id,\n\t}\n\ttasks, err := zcl.GetCollectionTasks(c)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn toWorkableTasks(tasks), nil\n}\n\nfunc GetCollectionProjects(wc WorkableCollection) ([]WorkableProject, error) {\n\tc := zentasktic.Collection{\n\t\tId: wc.Id,\n\t}\n\tprojects, err := zcl.GetCollectionProjects(c)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn toWorkableProjects(projects), nil\n}\n\nfunc GetAllCollections() (string, error) {\n\treturn zcl.GetAllCollections()\n}\n\n// Helper functions to convert between Workable and zentasktic types\nfunc toZentaskticTasks(tasks []WorkableTask) []zentasktic.Task {\n\tztasks := make([]zentasktic.Task, len(tasks))\n\tfor i, t := range tasks {\n\t\tztasks[i] = t.Task\n\t}\n\treturn ztasks\n}\n\nfunc toWorkableTasks(tasks []zentasktic.Task) []WorkableTask {\n\twtasks := make([]WorkableTask, len(tasks))\n\tfor i, t := range tasks {\n\t\twtasks[i] = WorkableTask{Task: t}\n\t}\n\treturn wtasks\n}\n\nfunc toZentaskticProjects(projects []WorkableProject) []zentasktic.Project {\n\tzprojects := make([]zentasktic.Project, len(projects))\n\tfor i, p := range projects {\n\t\tzprojects[i] = p.Project\n\t}\n\treturn zprojects\n}\n\nfunc toWorkableProjects(projects []zentasktic.Project) []WorkableProject {\n\twprojects := make([]WorkableProject, len(projects))\n\tfor i, p := range projects {\n\t\twprojects[i] = WorkableProject{Project: p}\n\t}\n\treturn wprojects\n}*/\n\n// object Paths\n\nfunc AddPath(wop WorkableObjectPath) error {\n\to := zentasktic.ObjectPath{\n\t\tObjectType: wop.ObjectType,\n\t\tId: wop.Id,\n\t\tRealmId: wop.RealmId,\n\t}\n\treturn zom.AddPath(o)\n}\n\n\nfunc GetObjectJourney(objectType string, objectId string) (string, error) {\n\treturn zom.GetObjectJourney(objectType, objectId)\n}\n" - } - ] - }, - "deposit": "" - } - ], - "fee": { - "gas_wanted": "15000000", - "gas_fee": "1000000ugnot" - }, - "signatures": [], - "memo": "" -} - diff --git a/gno.land/cmd/gnoland/testdata/restart_nonval.txtar b/gno.land/cmd/gnoland/testdata/restart_nonval.txtar deleted file mode 100644 index 87b4ad4ecb9..00000000000 --- a/gno.land/cmd/gnoland/testdata/restart_nonval.txtar +++ /dev/null @@ -1,5 +0,0 @@ -# This txtar tests for starting up a non-validator node; then also restarting it. -loadpkg gno.land/p/demo/avl - -gnoland start -non-validator -gnoland restart diff --git a/gno.land/pkg/gnoclient/client_test.go b/gno.land/pkg/gnoclient/client_test.go index b7eb21837a7..8aef07451d6 100644 --- a/gno.land/pkg/gnoclient/client_test.go +++ b/gno.land/pkg/gnoclient/client_test.go @@ -6,19 +6,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" ctypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/crypto/keys" - "github.com/gnolang/gno/tm2/pkg/sdk/bank" "github.com/gnolang/gno/tm2/pkg/std" ) -var testGasFee = ugnot.ValueString(10000) - func TestRender(t *testing.T) { t.Parallel() testRealmPath := "gno.land/r/demo/deep/very/deep" @@ -93,35 +88,25 @@ func TestCallSingle(t *testing.T) { cfg := BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", } - caller, err := client.Signer.Info() - require.NoError(t, err) - - msg := []vm.MsgCall{ + msg := []MsgCall{ { - Caller: caller.GetAddress(), - PkgPath: "gno.land/r/demo/deep/very/deep", - Func: "Render", - Args: []string{""}, - Send: std.Coins{{Denom: ugnot.Denom, Amount: int64(100)}}, + PkgPath: "gno.land/r/demo/deep/very/deep", + FuncName: "Render", + Args: []string{""}, + Send: "100ugnot", }, } res, err := client.Call(cfg, msg...) assert.NoError(t, err) require.NotNil(t, res) - expected := "it works!" - assert.Equal(t, string(res.DeliverTx.Data), expected) - - res, err = callSigningSeparately(t, client, cfg, msg...) - assert.NoError(t, err) - require.NotNil(t, res) - assert.Equal(t, string(res.DeliverTx.Data), expected) + assert.Equal(t, string(res.DeliverTx.Data), "it works!") } func TestCallMultiple(t *testing.T) { @@ -162,60 +147,47 @@ func TestCallMultiple(t *testing.T) { cfg := BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", } - caller, err := client.Signer.Info() - require.NoError(t, err) - - msg := []vm.MsgCall{ + msg := []MsgCall{ { - Caller: caller.GetAddress(), - PkgPath: "gno.land/r/demo/deep/very/deep", - Func: "Render", - Args: []string{""}, - Send: std.Coins{{Denom: ugnot.Denom, Amount: int64(100)}}, + PkgPath: "gno.land/r/demo/deep/very/deep", + FuncName: "Render", + Args: []string{""}, + Send: "100ugnot", }, { - Caller: caller.GetAddress(), - PkgPath: "gno.land/r/demo/wugnot", - Func: "Deposit", - Args: []string{""}, - Send: std.Coins{{Denom: ugnot.Denom, Amount: int64(1000)}}, + PkgPath: "gno.land/r/demo/wugnot", + FuncName: "Deposit", + Args: []string{""}, + Send: "1000ugnot", }, { - Caller: caller.GetAddress(), - PkgPath: "gno.land/r/demo/tamagotchi", - Func: "Feed", - Args: []string{""}, - Send: nil, + PkgPath: "gno.land/r/demo/tamagotchi", + FuncName: "Feed", + Args: []string{""}, + Send: "", }, } res, err := client.Call(cfg, msg...) assert.NoError(t, err) assert.NotNil(t, res) - - res, err = callSigningSeparately(t, client, cfg, msg...) - assert.NoError(t, err) - assert.NotNil(t, res) } func TestCallErrors(t *testing.T) { t.Parallel() - // These tests don't actually sign - mockAddress, _ := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") - testCases := []struct { name string client Client cfg BaseTxCfg - msgs []vm.MsgCall - expectedError string + msgs []MsgCall + expectedError error }{ { name: "Invalid Signer", @@ -225,21 +197,20 @@ func TestCallErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgCall{ + msgs: []MsgCall{ { - Caller: mockAddress, - PkgPath: "gno.land/r/random/path", - Func: "RandomName", - Send: nil, - Args: []string{}, + PkgPath: "random/path", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, - expectedError: ErrMissingSigner.Error(), + expectedError: ErrMissingSigner, }, { name: "Invalid RPCClient", @@ -249,21 +220,20 @@ func TestCallErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgCall{ + msgs: []MsgCall{ { - Caller: mockAddress, - PkgPath: "gno.land/r/random/path", - Func: "RandomName", - Send: nil, - Args: []string{}, + PkgPath: "random/path", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, - expectedError: ErrMissingRPCClient.Error(), + expectedError: ErrMissingRPCClient, }, { name: "Invalid Gas Fee", @@ -278,14 +248,13 @@ func TestCallErrors(t *testing.T) { SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgCall{ + msgs: []MsgCall{ { - Caller: mockAddress, - PkgPath: "gno.land/r/random/path", - Func: "RandomName", + PkgPath: "random/path", + FuncName: "RandomName", }, }, - expectedError: ErrInvalidGasFee.Error(), + expectedError: ErrInvalidGasFee, }, { name: "Negative Gas Wanted", @@ -295,21 +264,20 @@ func TestCallErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: -1, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgCall{ + msgs: []MsgCall{ { - Caller: mockAddress, - PkgPath: "gno.land/r/random/path", - Func: "RandomName", - Send: nil, - Args: []string{}, + PkgPath: "random/path", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, - expectedError: ErrInvalidGasWanted.Error(), + expectedError: ErrInvalidGasWanted, }, { name: "0 Gas Wanted", @@ -319,21 +287,20 @@ func TestCallErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 0, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgCall{ + msgs: []MsgCall{ { - Caller: mockAddress, - PkgPath: "gno.land/r/random/path", - Func: "RandomName", - Send: nil, - Args: []string{}, + PkgPath: "random/path", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, - expectedError: ErrInvalidGasWanted.Error(), + expectedError: ErrInvalidGasWanted, }, { name: "Invalid PkgPath", @@ -343,21 +310,20 @@ func TestCallErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgCall{ + msgs: []MsgCall{ { - Caller: mockAddress, - PkgPath: "", - Func: "RandomName", - Send: nil, - Args: []string{}, + PkgPath: "", + FuncName: "RandomName", + Send: "", + Args: []string{}, }, }, - expectedError: vm.InvalidPkgPathError{}.Error(), + expectedError: ErrEmptyPkgPath, }, { name: "Invalid FuncName", @@ -367,21 +333,20 @@ func TestCallErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgCall{ + msgs: []MsgCall{ { - Caller: mockAddress, - PkgPath: "gno.land/r/random/path", - Func: "", - Send: nil, - Args: []string{}, + PkgPath: "random/path", + FuncName: "", + Send: "", + Args: []string{}, }, }, - expectedError: vm.InvalidExprError{}.Error(), + expectedError: ErrEmptyFuncName, }, } @@ -392,7 +357,7 @@ func TestCallErrors(t *testing.T) { res, err := tc.client.Call(tc.cfg, tc.msgs...) assert.Nil(t, res) - assert.ErrorContains(t, err, tc.expectedError) + assert.ErrorIs(t, err, tc.expectedError) }) } } @@ -400,16 +365,13 @@ func TestCallErrors(t *testing.T) { func TestClient_Send_Errors(t *testing.T) { t.Parallel() - // These tests don't actually sign - mockAddress, _ := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") - toAddress, _ := crypto.AddressFromBech32("g14a0y9a64dugh3l7hneshdxr4w0rfkkww9ls35p") testCases := []struct { name string client Client cfg BaseTxCfg - msgs []bank.MsgSend - expectedError string + msgs []MsgSend + expectedError error }{ { name: "Invalid Signer", @@ -419,19 +381,18 @@ func TestClient_Send_Errors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []bank.MsgSend{ + msgs: []MsgSend{ { - FromAddress: mockAddress, - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(1)}}, + ToAddress: toAddress, + Send: "1ugnot", }, }, - expectedError: ErrMissingSigner.Error(), + expectedError: ErrMissingSigner, }, { name: "Invalid RPCClient", @@ -441,19 +402,18 @@ func TestClient_Send_Errors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []bank.MsgSend{ + msgs: []MsgSend{ { - FromAddress: mockAddress, - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(1)}}, + ToAddress: toAddress, + Send: "1ugnot", }, }, - expectedError: ErrMissingRPCClient.Error(), + expectedError: ErrMissingRPCClient, }, { name: "Invalid Gas Fee", @@ -468,14 +428,13 @@ func TestClient_Send_Errors(t *testing.T) { SequenceNumber: 1, Memo: "Test memo", }, - msgs: []bank.MsgSend{ + msgs: []MsgSend{ { - FromAddress: mockAddress, - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(1)}}, + ToAddress: toAddress, + Send: "1ugnot", }, }, - expectedError: ErrInvalidGasFee.Error(), + expectedError: ErrInvalidGasFee, }, { name: "Negative Gas Wanted", @@ -485,19 +444,18 @@ func TestClient_Send_Errors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: -1, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []bank.MsgSend{ + msgs: []MsgSend{ { - FromAddress: mockAddress, - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(1)}}, + ToAddress: toAddress, + Send: "1ugnot", }, }, - expectedError: ErrInvalidGasWanted.Error(), + expectedError: ErrInvalidGasWanted, }, { name: "0 Gas Wanted", @@ -507,19 +465,18 @@ func TestClient_Send_Errors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 0, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []bank.MsgSend{ + msgs: []MsgSend{ { - FromAddress: mockAddress, - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(1)}}, + ToAddress: toAddress, + Send: "1ugnot", }, }, - expectedError: ErrInvalidGasWanted.Error(), + expectedError: ErrInvalidGasWanted, }, { name: "Invalid To Address", @@ -538,19 +495,18 @@ func TestClient_Send_Errors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []bank.MsgSend{ + msgs: []MsgSend{ { - FromAddress: mockAddress, - ToAddress: crypto.Address{}, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(1)}}, + ToAddress: crypto.Address{}, + Send: "1ugnot", }, }, - expectedError: std.InvalidAddressError{}.Error(), + expectedError: ErrInvalidToAddress, }, { name: "Invalid Send Coins", @@ -569,19 +525,18 @@ func TestClient_Send_Errors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []bank.MsgSend{ + msgs: []MsgSend{ { - FromAddress: mockAddress, - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(-1)}}, + ToAddress: toAddress, + Send: "-1ugnot", }, }, - expectedError: std.InvalidCoinsError{}.Error(), + expectedError: ErrInvalidSendAmount, }, } @@ -592,7 +547,7 @@ func TestClient_Send_Errors(t *testing.T) { res, err := tc.client.Send(tc.cfg, tc.msgs...) assert.Nil(t, res) - assert.ErrorContains(t, err, tc.expectedError) + assert.ErrorIs(t, err, tc.expectedError) }) } } @@ -631,7 +586,7 @@ func TestRunSingle(t *testing.T) { cfg := BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", @@ -647,11 +602,7 @@ func main() { println(ufmt.Sprintf("%s", deep.Render("gnoclient!"))) }` - caller, err := client.Signer.Info() - require.NoError(t, err) - - msg := vm.MsgRun{ - Caller: caller.GetAddress(), + msg := MsgRun{ Package: &std.MemPackage{ Files: []*std.MemFile{ { @@ -660,19 +611,13 @@ func main() { }, }, }, - Send: nil, + Send: "", } res, err := client.Run(cfg, msg) assert.NoError(t, err) require.NotNil(t, res) - expected := "hi gnoclient!\n" - assert.Equal(t, expected, string(res.DeliverTx.Data)) - - res, err = runSigningSeparately(t, client, cfg, msg) - assert.NoError(t, err) - require.NotNil(t, res) - assert.Equal(t, expected, string(res.DeliverTx.Data)) + assert.Equal(t, "hi gnoclient!\n", string(res.DeliverTx.Data)) } func TestRunMultiple(t *testing.T) { @@ -708,7 +653,7 @@ func TestRunMultiple(t *testing.T) { cfg := BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", @@ -724,11 +669,7 @@ func main() { println(ufmt.Sprintf("%s", deep.Render("gnoclient!"))) }` - caller, err := client.Signer.Info() - require.NoError(t, err) - - msg1 := vm.MsgRun{ - Caller: caller.GetAddress(), + msg1 := MsgRun{ Package: &std.MemPackage{ Files: []*std.MemFile{ { @@ -737,11 +678,10 @@ func main() { }, }, }, - Send: nil, + Send: "", } - msg2 := vm.MsgRun{ - Caller: caller.GetAddress(), + msg2 := MsgRun{ Package: &std.MemPackage{ Files: []*std.MemFile{ { @@ -750,33 +690,24 @@ func main() { }, }, }, - Send: nil, + Send: "", } res, err := client.Run(cfg, msg1, msg2) assert.NoError(t, err) require.NotNil(t, res) - expected := "hi gnoclient!\nhi gnoclient!\n" - assert.Equal(t, expected, string(res.DeliverTx.Data)) - - res, err = runSigningSeparately(t, client, cfg, msg1, msg2) - assert.NoError(t, err) - require.NotNil(t, res) - assert.Equal(t, expected, string(res.DeliverTx.Data)) + assert.Equal(t, "hi gnoclient!\nhi gnoclient!\n", string(res.DeliverTx.Data)) } func TestRunErrors(t *testing.T) { t.Parallel() - // These tests don't actually sign - mockAddress, _ := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") - testCases := []struct { name string client Client cfg BaseTxCfg - msgs []vm.MsgRun - expectedError string + msgs []MsgRun + expectedError error }{ { name: "Invalid Signer", @@ -786,14 +717,13 @@ func TestRunErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgRun{ + msgs: []MsgRun{ { - Caller: mockAddress, Package: &std.MemPackage{ Name: "", Path: "", @@ -804,10 +734,10 @@ func TestRunErrors(t *testing.T) { }, }, }, - Send: nil, + Send: "", }, }, - expectedError: ErrMissingSigner.Error(), + expectedError: ErrMissingSigner, }, { name: "Invalid RPCClient", @@ -817,13 +747,13 @@ func TestRunErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgRun{}, - expectedError: ErrMissingRPCClient.Error(), + msgs: []MsgRun{}, + expectedError: ErrMissingRPCClient, }, { name: "Invalid Gas Fee", @@ -838,9 +768,8 @@ func TestRunErrors(t *testing.T) { SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgRun{ + msgs: []MsgRun{ { - Caller: mockAddress, Package: &std.MemPackage{ Name: "", Path: "", @@ -851,10 +780,10 @@ func TestRunErrors(t *testing.T) { }, }, }, - Send: nil, + Send: "", }, }, - expectedError: ErrInvalidGasFee.Error(), + expectedError: ErrInvalidGasFee, }, { name: "Negative Gas Wanted", @@ -864,14 +793,13 @@ func TestRunErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: -1, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgRun{ + msgs: []MsgRun{ { - Caller: mockAddress, Package: &std.MemPackage{ Name: "", Path: "", @@ -882,10 +810,10 @@ func TestRunErrors(t *testing.T) { }, }, }, - Send: nil, + Send: "", }, }, - expectedError: ErrInvalidGasWanted.Error(), + expectedError: ErrInvalidGasWanted, }, { name: "0 Gas Wanted", @@ -895,14 +823,13 @@ func TestRunErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 0, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgRun{ + msgs: []MsgRun{ { - Caller: mockAddress, Package: &std.MemPackage{ Name: "", Path: "", @@ -913,10 +840,10 @@ func TestRunErrors(t *testing.T) { }, }, }, - Send: nil, + Send: "", }, }, - expectedError: ErrInvalidGasWanted.Error(), + expectedError: ErrInvalidGasWanted, }, { name: "Invalid Empty Package", @@ -935,19 +862,18 @@ func TestRunErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgRun{ + msgs: []MsgRun{ { - Caller: mockAddress, - Package: &std.MemPackage{Name: "", Path: " "}, - Send: nil, + Package: nil, + Send: "", }, }, - expectedError: vm.InvalidPkgPathError{}.Error(), + expectedError: ErrEmptyPackage, }, } @@ -958,7 +884,7 @@ func TestRunErrors(t *testing.T) { res, err := tc.client.Run(tc.cfg, tc.msgs...) assert.Nil(t, res) - assert.ErrorContains(t, err, tc.expectedError) + assert.ErrorIs(t, err, tc.expectedError) }) } } @@ -967,15 +893,12 @@ func TestRunErrors(t *testing.T) { func TestAddPackageErrors(t *testing.T) { t.Parallel() - // These tests don't actually sign - mockAddress, _ := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") - testCases := []struct { name string client Client cfg BaseTxCfg - msgs []vm.MsgAddPackage - expectedError string + msgs []MsgAddPackage + expectedError error }{ { name: "Invalid Signer", @@ -985,14 +908,13 @@ func TestAddPackageErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgAddPackage{ + msgs: []MsgAddPackage{ { - Creator: mockAddress, Package: &std.MemPackage{ Name: "", Path: "", @@ -1003,10 +925,10 @@ func TestAddPackageErrors(t *testing.T) { }, }, }, - Deposit: nil, + Deposit: "", }, }, - expectedError: ErrMissingSigner.Error(), + expectedError: ErrMissingSigner, }, { name: "Invalid RPCClient", @@ -1016,13 +938,13 @@ func TestAddPackageErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgAddPackage{}, - expectedError: ErrMissingRPCClient.Error(), + msgs: []MsgAddPackage{}, + expectedError: ErrMissingRPCClient, }, { name: "Invalid Gas Fee", @@ -1037,9 +959,8 @@ func TestAddPackageErrors(t *testing.T) { SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgAddPackage{ + msgs: []MsgAddPackage{ { - Creator: mockAddress, Package: &std.MemPackage{ Name: "", Path: "", @@ -1050,10 +971,10 @@ func TestAddPackageErrors(t *testing.T) { }, }, }, - Deposit: nil, + Deposit: "", }, }, - expectedError: ErrInvalidGasFee.Error(), + expectedError: ErrInvalidGasFee, }, { name: "Negative Gas Wanted", @@ -1063,14 +984,13 @@ func TestAddPackageErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: -1, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgAddPackage{ + msgs: []MsgAddPackage{ { - Creator: mockAddress, Package: &std.MemPackage{ Name: "", Path: "", @@ -1081,10 +1001,10 @@ func TestAddPackageErrors(t *testing.T) { }, }, }, - Deposit: nil, + Deposit: "", }, }, - expectedError: ErrInvalidGasWanted.Error(), + expectedError: ErrInvalidGasWanted, }, { name: "0 Gas Wanted", @@ -1094,14 +1014,13 @@ func TestAddPackageErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 0, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgAddPackage{ + msgs: []MsgAddPackage{ { - Creator: mockAddress, Package: &std.MemPackage{ Name: "", Path: "", @@ -1112,10 +1031,10 @@ func TestAddPackageErrors(t *testing.T) { }, }, }, - Deposit: nil, + Deposit: "", }, }, - expectedError: ErrInvalidGasWanted.Error(), + expectedError: ErrInvalidGasWanted, }, { name: "Invalid Empty Package", @@ -1134,19 +1053,18 @@ func TestAddPackageErrors(t *testing.T) { }, cfg: BaseTxCfg{ GasWanted: 100000, - GasFee: testGasFee, + GasFee: "10000ugnot", AccountNumber: 1, SequenceNumber: 1, Memo: "Test memo", }, - msgs: []vm.MsgAddPackage{ + msgs: []MsgAddPackage{ { - Creator: mockAddress, - Package: &std.MemPackage{Name: "", Path: ""}, - Deposit: nil, + Package: nil, + Deposit: "", }, }, - expectedError: vm.InvalidPkgPathError{}.Error(), + expectedError: ErrEmptyPackage, }, } @@ -1157,7 +1075,7 @@ func TestAddPackageErrors(t *testing.T) { res, err := tc.client.AddPackage(tc.cfg, tc.msgs...) assert.Nil(t, res) - assert.ErrorContains(t, err, tc.expectedError) + assert.ErrorIs(t, err, tc.expectedError) }) } } @@ -1348,63 +1266,3 @@ func TestLatestBlockHeightErrors(t *testing.T) { }) } } - -// The same as client.Call, but test signing separately -func callSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msgs ...vm.MsgCall) (*ctypes.ResultBroadcastTxCommit, error) { - t.Helper() - tx, err := NewCallTx(cfg, msgs...) - assert.NoError(t, err) - require.NotNil(t, tx) - signedTx, err := client.SignTx(*tx, cfg.AccountNumber, cfg.SequenceNumber) - assert.NoError(t, err) - require.NotNil(t, signedTx) - res, err := client.BroadcastTxCommit(signedTx) - assert.NoError(t, err) - require.NotNil(t, res) - return res, nil -} - -// The same as client.Run, but test signing separately -func runSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msgs ...vm.MsgRun) (*ctypes.ResultBroadcastTxCommit, error) { - t.Helper() - tx, err := NewRunTx(cfg, msgs...) - assert.NoError(t, err) - require.NotNil(t, tx) - signedTx, err := client.SignTx(*tx, cfg.AccountNumber, cfg.SequenceNumber) - assert.NoError(t, err) - require.NotNil(t, signedTx) - res, err := client.BroadcastTxCommit(signedTx) - assert.NoError(t, err) - require.NotNil(t, res) - return res, nil -} - -// The same as client.Send, but test signing separately -func sendSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msgs ...bank.MsgSend) (*ctypes.ResultBroadcastTxCommit, error) { - t.Helper() - tx, err := NewSendTx(cfg, msgs...) - assert.NoError(t, err) - require.NotNil(t, tx) - signedTx, err := client.SignTx(*tx, cfg.AccountNumber, cfg.SequenceNumber) - assert.NoError(t, err) - require.NotNil(t, signedTx) - res, err := client.BroadcastTxCommit(signedTx) - assert.NoError(t, err) - require.NotNil(t, res) - return res, nil -} - -// The same as client.AddPackage, but test signing separately -func addPackageSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*ctypes.ResultBroadcastTxCommit, error) { - t.Helper() - tx, err := NewAddPackageTx(cfg, msgs...) - assert.NoError(t, err) - require.NotNil(t, tx) - signedTx, err := client.SignTx(*tx, cfg.AccountNumber, cfg.SequenceNumber) - assert.NoError(t, err) - require.NotNil(t, signedTx) - res, err := client.BroadcastTxCommit(signedTx) - assert.NoError(t, err) - require.NotNil(t, res) - return res, nil -} diff --git a/gno.land/pkg/gnoclient/client_txs.go b/gno.land/pkg/gnoclient/client_txs.go index 9d3dbde22ae..a32a6899abe 100644 --- a/gno.land/pkg/gnoclient/client_txs.go +++ b/gno.land/pkg/gnoclient/client_txs.go @@ -4,16 +4,22 @@ import ( "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/gnolang/gno/tm2/pkg/amino" ctypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" + "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/sdk/bank" "github.com/gnolang/gno/tm2/pkg/std" ) var ( - ErrInvalidGasWanted = errors.New("invalid gas wanted") - ErrInvalidGasFee = errors.New("invalid gas fee") - ErrMissingSigner = errors.New("missing Signer") - ErrMissingRPCClient = errors.New("missing RPCClient") + ErrEmptyPackage = errors.New("empty package to run") + ErrEmptyPkgPath = errors.New("empty pkg path") + ErrEmptyFuncName = errors.New("empty function name") + ErrInvalidGasWanted = errors.New("invalid gas wanted") + ErrInvalidGasFee = errors.New("invalid gas fee") + ErrMissingSigner = errors.New("missing Signer") + ErrMissingRPCClient = errors.New("missing RPCClient") + ErrInvalidToAddress = errors.New("invalid send to address") + ErrInvalidSendAmount = errors.New("invalid send amount") ) // BaseTxCfg defines the base transaction configuration, shared by all message types @@ -25,8 +31,34 @@ type BaseTxCfg struct { Memo string // Memo } +// MsgCall - syntax sugar for vm.MsgCall +type MsgCall struct { + PkgPath string // Package path + FuncName string // Function name + Args []string // Function arguments + Send string // Send amount +} + +// MsgSend - syntax sugar for bank.MsgSend +type MsgSend struct { + ToAddress crypto.Address // Send to address + Send string // Send amount +} + +// MsgRun - syntax sugar for vm.MsgRun +type MsgRun struct { + Package *std.MemPackage // Package to run + Send string // Send amount +} + +// MsgAddPackage - syntax sugar for vm.MsgAddPackage +type MsgAddPackage struct { + Package *std.MemPackage // Package to add + Deposit string // Coin deposit +} + // Call executes one or more MsgCall calls on the blockchain -func (c *Client) Call(cfg BaseTxCfg, msgs ...vm.MsgCall) (*ctypes.ResultBroadcastTxCommit, error) { +func (c *Client) Call(cfg BaseTxCfg, msgs ...MsgCall) (*ctypes.ResultBroadcastTxCommit, error) { // Validate required client fields. if err := c.validateSigner(); err != nil { return nil, err @@ -35,29 +67,38 @@ func (c *Client) Call(cfg BaseTxCfg, msgs ...vm.MsgCall) (*ctypes.ResultBroadcas return nil, err } - tx, err := NewCallTx(cfg, msgs...) - if err != nil { - return nil, err - } - return c.signAndBroadcastTxCommit(*tx, cfg.AccountNumber, cfg.SequenceNumber) -} - -// NewCallTx makes an unsigned transaction from one or more MsgCall. -// The Caller field must be set. -func NewCallTx(cfg BaseTxCfg, msgs ...vm.MsgCall) (*std.Tx, error) { // Validate base transaction config if err := cfg.validateBaseTxConfig(); err != nil { return nil, err } + // Parse MsgCall slice vmMsgs := make([]std.Msg, 0, len(msgs)) for _, msg := range msgs { // Validate MsgCall fields - if err := msg.ValidateBasic(); err != nil { + if err := msg.validateMsgCall(); err != nil { + return nil, err + } + + // Parse send coins + send, err := std.ParseCoins(msg.Send) + if err != nil { + return nil, err + } + + caller, err := c.Signer.Info() + if err != nil { return nil, err } - vmMsgs = append(vmMsgs, std.Msg(msg)) + // Unwrap syntax sugar to vm.MsgCall slice + vmMsgs = append(vmMsgs, std.Msg(vm.MsgCall{ + Caller: caller.GetAddress(), + PkgPath: msg.PkgPath, + Func: msg.FuncName, + Args: msg.Args, + Send: send, + })) } // Parse gas fee @@ -67,16 +108,18 @@ func NewCallTx(cfg BaseTxCfg, msgs ...vm.MsgCall) (*std.Tx, error) { } // Pack transaction - return &std.Tx{ + tx := std.Tx{ Msgs: vmMsgs, Fee: std.NewFee(cfg.GasWanted, gasFeeCoins), Signatures: nil, Memo: cfg.Memo, - }, nil + } + + return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) } // Run executes one or more MsgRun calls on the blockchain -func (c *Client) Run(cfg BaseTxCfg, msgs ...vm.MsgRun) (*ctypes.ResultBroadcastTxCommit, error) { +func (c *Client) Run(cfg BaseTxCfg, msgs ...MsgRun) (*ctypes.ResultBroadcastTxCommit, error) { // Validate required client fields. if err := c.validateSigner(); err != nil { return nil, err @@ -85,29 +128,39 @@ func (c *Client) Run(cfg BaseTxCfg, msgs ...vm.MsgRun) (*ctypes.ResultBroadcastT return nil, err } - tx, err := NewRunTx(cfg, msgs...) - if err != nil { - return nil, err - } - return c.signAndBroadcastTxCommit(*tx, cfg.AccountNumber, cfg.SequenceNumber) -} - -// NewRunTx makes an unsigned transaction from one or more MsgRun. -// The Caller field must be set. -func NewRunTx(cfg BaseTxCfg, msgs ...vm.MsgRun) (*std.Tx, error) { // Validate base transaction config if err := cfg.validateBaseTxConfig(); err != nil { return nil, err } + // Parse MsgRun slice vmMsgs := make([]std.Msg, 0, len(msgs)) for _, msg := range msgs { - // Validate MsgRun fields - if err := msg.ValidateBasic(); err != nil { + // Validate MsgCall fields + if err := msg.validateMsgRun(); err != nil { return nil, err } - vmMsgs = append(vmMsgs, std.Msg(msg)) + // Parse send coins + send, err := std.ParseCoins(msg.Send) + if err != nil { + return nil, err + } + + caller, err := c.Signer.Info() + if err != nil { + return nil, err + } + + msg.Package.Name = "main" + msg.Package.Path = "" + + // Unwrap syntax sugar to vm.MsgCall slice + vmMsgs = append(vmMsgs, std.Msg(vm.MsgRun{ + Caller: caller.GetAddress(), + Package: msg.Package, + Send: send, + })) } // Parse gas fee @@ -117,16 +170,18 @@ func NewRunTx(cfg BaseTxCfg, msgs ...vm.MsgRun) (*std.Tx, error) { } // Pack transaction - return &std.Tx{ + tx := std.Tx{ Msgs: vmMsgs, Fee: std.NewFee(cfg.GasWanted, gasFeeCoins), Signatures: nil, Memo: cfg.Memo, - }, nil + } + + return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) } // Send executes one or more MsgSend calls on the blockchain -func (c *Client) Send(cfg BaseTxCfg, msgs ...bank.MsgSend) (*ctypes.ResultBroadcastTxCommit, error) { +func (c *Client) Send(cfg BaseTxCfg, msgs ...MsgSend) (*ctypes.ResultBroadcastTxCommit, error) { // Validate required client fields. if err := c.validateSigner(); err != nil { return nil, err @@ -135,29 +190,36 @@ func (c *Client) Send(cfg BaseTxCfg, msgs ...bank.MsgSend) (*ctypes.ResultBroadc return nil, err } - tx, err := NewSendTx(cfg, msgs...) - if err != nil { - return nil, err - } - return c.signAndBroadcastTxCommit(*tx, cfg.AccountNumber, cfg.SequenceNumber) -} - -// NewSendTx makes an unsigned transaction from one or more MsgSend. -// The FromAddress field must be set. -func NewSendTx(cfg BaseTxCfg, msgs ...bank.MsgSend) (*std.Tx, error) { // Validate base transaction config if err := cfg.validateBaseTxConfig(); err != nil { return nil, err } + // Parse MsgSend slice vmMsgs := make([]std.Msg, 0, len(msgs)) for _, msg := range msgs { // Validate MsgSend fields - if err := msg.ValidateBasic(); err != nil { + if err := msg.validateMsgSend(); err != nil { + return nil, err + } + + // Parse send coins + send, err := std.ParseCoins(msg.Send) + if err != nil { + return nil, err + } + + caller, err := c.Signer.Info() + if err != nil { return nil, err } - vmMsgs = append(vmMsgs, std.Msg(msg)) + // Unwrap syntax sugar to vm.MsgSend slice + vmMsgs = append(vmMsgs, std.Msg(bank.MsgSend{ + FromAddress: caller.GetAddress(), + ToAddress: msg.ToAddress, + Amount: send, + })) } // Parse gas fee @@ -167,16 +229,18 @@ func NewSendTx(cfg BaseTxCfg, msgs ...bank.MsgSend) (*std.Tx, error) { } // Pack transaction - return &std.Tx{ + tx := std.Tx{ Msgs: vmMsgs, Fee: std.NewFee(cfg.GasWanted, gasFeeCoins), Signatures: nil, Memo: cfg.Memo, - }, nil + } + + return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) } // AddPackage executes one or more AddPackage calls on the blockchain -func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*ctypes.ResultBroadcastTxCommit, error) { +func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...MsgAddPackage) (*ctypes.ResultBroadcastTxCommit, error) { // Validate required client fields. if err := c.validateSigner(); err != nil { return nil, err @@ -185,29 +249,36 @@ func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*ctypes.Re return nil, err } - tx, err := NewAddPackageTx(cfg, msgs...) - if err != nil { - return nil, err - } - return c.signAndBroadcastTxCommit(*tx, cfg.AccountNumber, cfg.SequenceNumber) -} - -// NewAddPackageTx makes an unsigned transaction from one or more MsgAddPackage. -// The Creator field must be set. -func NewAddPackageTx(cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*std.Tx, error) { // Validate base transaction config if err := cfg.validateBaseTxConfig(); err != nil { return nil, err } + // Parse MsgRun slice vmMsgs := make([]std.Msg, 0, len(msgs)) for _, msg := range msgs { - // Validate MsgAddPackage fields - if err := msg.ValidateBasic(); err != nil { + // Validate MsgCall fields + if err := msg.validateMsgAddPackage(); err != nil { return nil, err } - vmMsgs = append(vmMsgs, std.Msg(msg)) + // Parse deposit coins + deposit, err := std.ParseCoins(msg.Deposit) + if err != nil { + return nil, err + } + + caller, err := c.Signer.Info() + if err != nil { + return nil, err + } + + // Unwrap syntax sugar to vm.MsgCall slice + vmMsgs = append(vmMsgs, std.Msg(vm.MsgAddPackage{ + Creator: caller.GetAddress(), + Package: msg.Package, + Deposit: deposit, + })) } // Parse gas fee @@ -217,29 +288,18 @@ func NewAddPackageTx(cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*std.Tx, error) { } // Pack transaction - return &std.Tx{ + tx := std.Tx{ Msgs: vmMsgs, Fee: std.NewFee(cfg.GasWanted, gasFeeCoins), Signatures: nil, Memo: cfg.Memo, - }, nil + } + + return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) } // signAndBroadcastTxCommit signs a transaction and broadcasts it, returning the result func (c *Client) signAndBroadcastTxCommit(tx std.Tx, accountNumber, sequenceNumber uint64) (*ctypes.ResultBroadcastTxCommit, error) { - signedTx, err := c.SignTx(tx, accountNumber, sequenceNumber) - if err != nil { - return nil, err - } - return c.BroadcastTxCommit(signedTx) -} - -// SignTx signs a transaction and returns a signed tx ready for broadcasting. -// If accountNumber or sequenceNumber is 0 then query the blockchain for the value. -func (c *Client) SignTx(tx std.Tx, accountNumber, sequenceNumber uint64) (*std.Tx, error) { - if err := c.validateSigner(); err != nil { - return nil, err - } caller, err := c.Signer.Info() if err != nil { return nil, err @@ -263,15 +323,7 @@ func (c *Client) SignTx(tx std.Tx, accountNumber, sequenceNumber uint64) (*std.T if err != nil { return nil, errors.Wrap(err, "sign") } - return signedTx, nil -} -// BroadcastTxCommit marshals and broadcasts the signed transaction, returning the result. -// If the result has a delivery error, then return a wrapped error. -func (c *Client) BroadcastTxCommit(signedTx *std.Tx) (*ctypes.ResultBroadcastTxCommit, error) { - if err := c.validateRPCClient(); err != nil { - return nil, err - } bz, err := amino.Marshal(signedTx) if err != nil { return nil, errors.Wrap(err, "marshaling tx binary bytes") diff --git a/gno.land/pkg/gnoclient/integration_test.go b/gno.land/pkg/gnoclient/integration_test.go index ea068e0680b..06360244b7f 100644 --- a/gno.land/pkg/gnoclient/integration_test.go +++ b/gno.land/pkg/gnoclient/integration_test.go @@ -5,12 +5,9 @@ import ( "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/tm2/pkg/sdk/bank" "github.com/gnolang/gno/tm2/pkg/std" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/gno.land/pkg/integration" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/gnolang/gno/gnovm/pkg/gnoenv" rpcclient "github.com/gnolang/gno/tm2/pkg/bft/rpc/client" "github.com/gnolang/gno/tm2/pkg/crypto" @@ -39,23 +36,19 @@ func TestCallSingle_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ - GasFee: ugnot.ValueString(10000), + GasFee: "10000ugnot", GasWanted: 8000000, AccountNumber: 0, SequenceNumber: 0, Memo: "", } - caller, err := client.Signer.Info() - require.NoError(t, err) - // Make Msg config - msg := vm.MsgCall{ - Caller: caller.GetAddress(), - PkgPath: "gno.land/r/demo/deep/very/deep", - Func: "Render", - Args: []string{"test argument"}, - Send: nil, + msg := MsgCall{ + PkgPath: "gno.land/r/demo/deep/very/deep", + FuncName: "Render", + Args: []string{"test argument"}, + Send: "", } // Execute call @@ -66,11 +59,6 @@ func TestCallSingle_Integration(t *testing.T) { got := string(res.DeliverTx.Data) assert.Equal(t, expected, got) - - res, err = callSigningSeparately(t, client, baseCfg, msg) - require.NoError(t, err) - got = string(res.DeliverTx.Data) - assert.Equal(t, expected, got) } func TestCallMultiple_Integration(t *testing.T) { @@ -92,32 +80,27 @@ func TestCallMultiple_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ - GasFee: ugnot.ValueString(10000), + GasFee: "10000ugnot", GasWanted: 8000000, AccountNumber: 0, SequenceNumber: 0, Memo: "", } - caller, err := client.Signer.Info() - require.NoError(t, err) - // Make Msg configs - msg1 := vm.MsgCall{ - Caller: caller.GetAddress(), - PkgPath: "gno.land/r/demo/deep/very/deep", - Func: "Render", - Args: []string{""}, - Send: nil, + msg1 := MsgCall{ + PkgPath: "gno.land/r/demo/deep/very/deep", + FuncName: "Render", + Args: []string{""}, + Send: "", } // Same call, different argument - msg2 := vm.MsgCall{ - Caller: caller.GetAddress(), - PkgPath: "gno.land/r/demo/deep/very/deep", - Func: "Render", - Args: []string{"test argument"}, - Send: nil, + msg2 := MsgCall{ + PkgPath: "gno.land/r/demo/deep/very/deep", + FuncName: "Render", + Args: []string{"test argument"}, + Send: "", } expected := "(\"it works!\" string)\n\n(\"hi test argument\" string)\n\n" @@ -128,11 +111,6 @@ func TestCallMultiple_Integration(t *testing.T) { got := string(res.DeliverTx.Data) assert.Equal(t, expected, got) - - res, err = callSigningSeparately(t, client, baseCfg, msg1, msg2) - require.NoError(t, err) - got = string(res.DeliverTx.Data) - assert.Equal(t, expected, got) } func TestSendSingle_Integration(t *testing.T) { @@ -154,23 +132,19 @@ func TestSendSingle_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ - GasFee: ugnot.ValueString(10000), + GasFee: "10000ugnot", GasWanted: 8000000, AccountNumber: 0, SequenceNumber: 0, Memo: "", } - caller, err := client.Signer.Info() - require.NoError(t, err) - // Make Send config for a new address on the blockchain toAddress, _ := crypto.AddressFromBech32("g14a0y9a64dugh3l7hneshdxr4w0rfkkww9ls35p") amount := 10 - msg := bank.MsgSend{ - FromAddress: caller.GetAddress(), - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(amount)}}, + msg := MsgSend{ + ToAddress: toAddress, + Send: std.Coin{"ugnot", int64(amount)}.String(), } // Execute send @@ -182,21 +156,10 @@ func TestSendSingle_Integration(t *testing.T) { account, _, err := client.QueryAccount(toAddress) require.NoError(t, err) - expected := std.Coins{{Denom: ugnot.Denom, Amount: int64(amount)}} + expected := std.Coins{{"ugnot", int64(amount)}} got := account.GetCoins() assert.Equal(t, expected, got) - - res, err = sendSigningSeparately(t, client, baseCfg, msg) - require.NoError(t, err) - assert.Equal(t, "", string(res.DeliverTx.Data)) - - // Get the new account balance - account, _, err = client.QueryAccount(toAddress) - require.NoError(t, err) - expected2 := std.Coins{{Denom: ugnot.Denom, Amount: int64(2 * amount)}} - got = account.GetCoins() - assert.Equal(t, expected2, got) } func TestSendMultiple_Integration(t *testing.T) { @@ -218,31 +181,26 @@ func TestSendMultiple_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ - GasFee: ugnot.ValueString(10000), + GasFee: "10000ugnot", GasWanted: 8000000, AccountNumber: 0, SequenceNumber: 0, Memo: "", } - caller, err := client.Signer.Info() - require.NoError(t, err) - // Make Msg configs toAddress, _ := crypto.AddressFromBech32("g14a0y9a64dugh3l7hneshdxr4w0rfkkww9ls35p") amount1 := 10 - msg1 := bank.MsgSend{ - FromAddress: caller.GetAddress(), - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(amount1)}}, + msg1 := MsgSend{ + ToAddress: toAddress, + Send: std.Coin{"ugnot", int64(amount1)}.String(), } // Same send, different argument amount2 := 20 - msg2 := bank.MsgSend{ - FromAddress: caller.GetAddress(), - ToAddress: toAddress, - Amount: std.Coins{{Denom: ugnot.Denom, Amount: int64(amount2)}}, + msg2 := MsgSend{ + ToAddress: toAddress, + Send: std.Coin{"ugnot", int64(amount2)}.String(), } // Execute send @@ -254,21 +212,10 @@ func TestSendMultiple_Integration(t *testing.T) { account, _, err := client.QueryAccount(toAddress) assert.NoError(t, err) - expected := std.Coins{{Denom: ugnot.Denom, Amount: int64(amount1 + amount2)}} + expected := std.Coins{{"ugnot", int64(amount1 + amount2)}} got := account.GetCoins() assert.Equal(t, expected, got) - - res, err = sendSigningSeparately(t, client, baseCfg, msg1, msg2) - require.NoError(t, err) - assert.Equal(t, "", string(res.DeliverTx.Data)) - - // Get the new account balance - account, _, err = client.QueryAccount(toAddress) - require.NoError(t, err) - expected2 := std.Coins{{Denom: ugnot.Denom, Amount: int64(2 * (amount1 + amount2))}} - got = account.GetCoins() - assert.Equal(t, expected2, got) } // Run tests @@ -290,7 +237,7 @@ func TestRunSingle_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ - GasFee: ugnot.ValueString(10000), + GasFee: "10000ugnot", GasWanted: 8000000, AccountNumber: 0, SequenceNumber: 0, @@ -310,14 +257,9 @@ func main() { println(ufmt.Sprintf("- after: %d", tests.Counter())) }` - caller, err := client.Signer.Info() - require.NoError(t, err) - // Make Msg configs - msg := vm.MsgRun{ - Caller: caller.GetAddress(), + msg := MsgRun{ Package: &std.MemPackage{ - Name: "main", Files: []*std.MemFile{ { Name: "main.gno", @@ -325,18 +267,13 @@ func main() { }, }, }, - Send: nil, + Send: "", } res, err := client.Run(baseCfg, msg) assert.NoError(t, err) require.NotNil(t, res) assert.Equal(t, string(res.DeliverTx.Data), "- before: 0\n- after: 10\n") - - res, err = runSigningSeparately(t, client, baseCfg, msg) - assert.NoError(t, err) - require.NotNil(t, res) - assert.Equal(t, string(res.DeliverTx.Data), "- before: 10\n- after: 20\n") } // Run tests @@ -358,7 +295,7 @@ func TestRunMultiple_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ - GasFee: ugnot.ValueString(10000), + GasFee: "10000ugnot", GasWanted: 8000000, AccountNumber: 0, SequenceNumber: 0, @@ -387,14 +324,9 @@ func main() { println(ufmt.Sprintf("%s", deep.Render("gnoclient!"))) }` - caller, err := client.Signer.Info() - require.NoError(t, err) - // Make Msg configs - msg1 := vm.MsgRun{ - Caller: caller.GetAddress(), + msg1 := MsgRun{ Package: &std.MemPackage{ - Name: "main", Files: []*std.MemFile{ { Name: "main.gno", @@ -402,12 +334,10 @@ func main() { }, }, }, - Send: nil, + Send: "", } - msg2 := vm.MsgRun{ - Caller: caller.GetAddress(), + msg2 := MsgRun{ Package: &std.MemPackage{ - Name: "main", Files: []*std.MemFile{ { Name: "main.gno", @@ -415,7 +345,7 @@ func main() { }, }, }, - Send: nil, + Send: "", } expected := "- before: 0\n- after: 10\nhi gnoclient!\n" @@ -424,12 +354,6 @@ func main() { assert.NoError(t, err) require.NotNil(t, res) assert.Equal(t, expected, string(res.DeliverTx.Data)) - - res, err = runSigningSeparately(t, client, baseCfg, msg1, msg2) - require.NoError(t, err) - require.NotNil(t, res) - expected2 := "- before: 10\n- after: 20\nhi gnoclient!\n" - assert.Equal(t, expected2, string(res.DeliverTx.Data)) } func TestAddPackageSingle_Integration(t *testing.T) { @@ -451,7 +375,7 @@ func TestAddPackageSingle_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ - GasFee: ugnot.ValueString(10000), + GasFee: "10000ugnot", GasWanted: 8000000, AccountNumber: 0, SequenceNumber: 0, @@ -466,14 +390,10 @@ func Echo(str string) string { fileName := "echo.gno" deploymentPath := "gno.land/p/demo/integration/test/echo" - deposit := std.Coins{{Denom: ugnot.Denom, Amount: int64(100)}} - - caller, err := client.Signer.Info() - require.NoError(t, err) + deposit := "100ugnot" // Make Msg config - msg := vm.MsgAddPackage{ - Creator: caller.GetAddress(), + msg := MsgAddPackage{ Package: &std.MemPackage{ Name: "echo", Path: deploymentPath, @@ -502,19 +422,7 @@ func Echo(str string) string { // Query balance to validate deposit baseAcc, _, err := client.QueryAccount(gnolang.DerivePkgAddr(deploymentPath)) require.NoError(t, err) - assert.Equal(t, baseAcc.GetCoins(), deposit) - - // Test signing separately (using a different deployment path) - deploymentPathB := "gno.land/p/demo/integration/test/echo2" - msg.Package.Path = deploymentPathB - _, err = addPackageSigningSeparately(t, client, baseCfg, msg) - assert.NoError(t, err) - query, err = client.Query(QueryCfg{ - Path: "vm/qfile", - Data: []byte(deploymentPathB), - }) - require.NoError(t, err) - assert.Equal(t, string(query.Response.Data), fileName) + assert.Equal(t, baseAcc.GetCoins().String(), deposit) } func TestAddPackageMultiple_Integration(t *testing.T) { @@ -536,14 +444,14 @@ func TestAddPackageMultiple_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ - GasFee: ugnot.ValueString(10000), + GasFee: "10000ugnot", GasWanted: 8000000, AccountNumber: 0, SequenceNumber: 0, Memo: "", } - deposit := std.Coins{{Denom: ugnot.Denom, Amount: int64(100)}} + deposit := "100ugnot" deploymentPath1 := "gno.land/p/demo/integration/test/echo" body1 := `package echo @@ -559,11 +467,7 @@ func Hello(str string) string { return "Hello " + str + "!" }` - caller, err := client.Signer.Info() - require.NoError(t, err) - - msg1 := vm.MsgAddPackage{ - Creator: caller.GetAddress(), + msg1 := MsgAddPackage{ Package: &std.MemPackage{ Name: "echo", Path: deploymentPath1, @@ -574,11 +478,10 @@ func Hello(str string) string { }, }, }, - Deposit: nil, + Deposit: "", } - msg2 := vm.MsgAddPackage{ - Creator: caller.GetAddress(), + msg2 := MsgAddPackage{ Package: &std.MemPackage{ Name: "hello", Path: deploymentPath2, @@ -625,28 +528,7 @@ func Hello(str string) string { // Query balance to validate deposit baseAcc, _, err = client.QueryAccount(gnolang.DerivePkgAddr(deploymentPath2)) require.NoError(t, err) - assert.Equal(t, baseAcc.GetCoins(), deposit) - - // Test signing separately (using a different deployment path) - deploymentPath1B := "gno.land/p/demo/integration/test/echo2" - deploymentPath2B := "gno.land/p/demo/integration/test/hello2" - msg1.Package.Path = deploymentPath1B - msg2.Package.Path = deploymentPath2B - _, err = addPackageSigningSeparately(t, client, baseCfg, msg1, msg2) - assert.NoError(t, err) - query, err = client.Query(QueryCfg{ - Path: "vm/qfile", - Data: []byte(deploymentPath1B), - }) - require.NoError(t, err) - assert.Equal(t, string(query.Response.Data), "echo.gno") - query, err = client.Query(QueryCfg{ - Path: "vm/qfile", - Data: []byte(deploymentPath2B), - }) - require.NoError(t, err) - assert.Contains(t, string(query.Response.Data), "hello.gno") - assert.Contains(t, string(query.Response.Data), "gno.mod") + assert.Equal(t, baseAcc.GetCoins().String(), deposit) } // todo add more integration tests: diff --git a/gno.land/pkg/gnoclient/signer.go b/gno.land/pkg/gnoclient/signer.go index 6e652080c72..0462865f2be 100644 --- a/gno.land/pkg/gnoclient/signer.go +++ b/gno.land/pkg/gnoclient/signer.go @@ -3,7 +3,6 @@ package gnoclient import ( "fmt" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/gnolang/gno/tm2/pkg/crypto/keys" "github.com/gnolang/gno/tm2/pkg/errors" @@ -48,7 +47,7 @@ func (s SignerFromKeybase) Validate() error { signCfg := SignCfg{ UnsignedTX: std.Tx{ Msgs: []std.Msg{msg}, - Fee: std.NewFee(0, std.NewCoin(ugnot.Denom, 1000000)), + Fee: std.NewFee(0, std.NewCoin("ugnot", 1000000)), }, } if _, err = s.Sign(signCfg); err != nil { diff --git a/gno.land/pkg/gnoclient/util.go b/gno.land/pkg/gnoclient/util.go index 50099eb4bd8..177e6d92906 100644 --- a/gno.land/pkg/gnoclient/util.go +++ b/gno.land/pkg/gnoclient/util.go @@ -1,5 +1,7 @@ package gnoclient +import "github.com/gnolang/gno/tm2/pkg/std" + func (cfg BaseTxCfg) validateBaseTxConfig() error { if cfg.GasWanted <= 0 { return ErrInvalidGasWanted @@ -10,3 +12,42 @@ func (cfg BaseTxCfg) validateBaseTxConfig() error { return nil } + +func (msg MsgCall) validateMsgCall() error { + if msg.PkgPath == "" { + return ErrEmptyPkgPath + } + if msg.FuncName == "" { + return ErrEmptyFuncName + } + + return nil +} + +func (msg MsgSend) validateMsgSend() error { + if msg.ToAddress.IsZero() { + return ErrInvalidToAddress + } + _, err := std.ParseCoins(msg.Send) + if err != nil { + return ErrInvalidSendAmount + } + + return nil +} + +func (msg MsgRun) validateMsgRun() error { + if msg.Package == nil || len(msg.Package.Files) == 0 { + return ErrEmptyPackage + } + + return nil +} + +func (msg MsgAddPackage) validateMsgAddPackage() error { + if msg.Package == nil || len(msg.Package.Files) == 0 { + return ErrEmptyPackage + } + + return nil +} diff --git a/gno.land/pkg/gnoland/app.go b/gno.land/pkg/gnoland/app.go index 2380658c6e9..f4d353411f8 100644 --- a/gno.land/pkg/gnoland/app.go +++ b/gno.land/pkg/gnoland/app.go @@ -1,4 +1,3 @@ -// Package gnoland contains the bootstrapping code to launch a gno.land node. package gnoland import ( @@ -6,7 +5,6 @@ import ( "log/slog" "path/filepath" "strconv" - "time" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/gnolang/gno/gnovm/pkg/gnoenv" @@ -27,46 +25,48 @@ import ( // Only goleveldb is supported for now. _ "github.com/gnolang/gno/tm2/pkg/db/_tags" _ "github.com/gnolang/gno/tm2/pkg/db/goleveldb" + "github.com/gnolang/gno/tm2/pkg/db/memdb" ) -// AppOptions contains the options to create the gno.land ABCI application. type AppOptions struct { - DB dbm.DB // required - Logger *slog.Logger // required - EventSwitch events.EventSwitch // required - MaxCycles int64 // hard limit for cycles in GnoVM - InitChainerConfig // options related to InitChainer + DB dbm.DB + // `gnoRootDir` should point to the local location of the gno repository. + // It serves as the gno equivalent of GOROOT. + GnoRootDir string + GenesisTxHandler GenesisTxHandler + Logger *slog.Logger + EventSwitch events.EventSwitch + MaxCycles int64 + // Whether to cache the result of loading the standard libraries. + // This is useful if you have to start many nodes, like in testing. + // This disables loading existing packages; so it should only be used + // on a fresh database. + CacheStdlibLoad bool } -// DefaultAppOptions provides a "ready" default [AppOptions] for use with -// [NewAppWithOptions], using the provided db. -func TestAppOptions(db dbm.DB) *AppOptions { +func NewAppOptions() *AppOptions { return &AppOptions{ - DB: db, - Logger: log.NewNoopLogger(), - EventSwitch: events.NewEventSwitch(), - InitChainerConfig: InitChainerConfig{ - GenesisTxResultHandler: PanicOnFailingTxResultHandler, - StdlibDir: filepath.Join(gnoenv.RootDir(), "gnovm", "stdlibs"), - CacheStdlibLoad: true, - }, + GenesisTxHandler: PanicOnFailingTxHandler, + Logger: log.NewNoopLogger(), + DB: memdb.NewMemDB(), + GnoRootDir: gnoenv.RootDir(), + EventSwitch: events.NilEventSwitch(), } } -func (c AppOptions) validate() error { - // Required fields - switch { - case c.DB == nil: - return fmt.Errorf("no db provided") - case c.Logger == nil: +func (c *AppOptions) validate() error { + if c.Logger == nil { return fmt.Errorf("no logger provided") - case c.EventSwitch == nil: - return fmt.Errorf("no event switch provided") } + + if c.DB == nil { + return fmt.Errorf("no db provided") + } + return nil } -// NewAppWithOptions creates the gno.land application with specified options. +// NewAppWithOptions creates the GnoLand application with specified options func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { if err := cfg.validate(); err != nil { return nil, err @@ -88,13 +88,13 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { // Construct keepers. acctKpr := auth.NewAccountKeeper(mainKey, ProtoGnoAccount) bankKpr := bank.NewBankKeeper(acctKpr) - vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, cfg.MaxCycles) + + // XXX: Embed this ? + stdlibsDir := filepath.Join(cfg.GnoRootDir, "gnovm", "stdlibs") + vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, stdlibsDir, cfg.MaxCycles) // Set InitChainer - icc := cfg.InitChainerConfig - icc.baseApp = baseApp - icc.acctKpr, icc.bankKpr, icc.vmKpr = acctKpr, bankKpr, vmk - baseApp.SetInitChainer(icc.InitChainer) + baseApp.SetInitChainer(InitChainer(baseApp, acctKpr, bankKpr, cfg.GenesisTxHandler)) // Set AnteHandler authOptions := auth.AnteOptions{ @@ -108,28 +108,14 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { newCtx sdk.Context, res sdk.Result, abort bool, ) { // Override auth params. - ctx = ctx. - WithValue(auth.AuthParamsContextKey{}, auth.DefaultParams()) + ctx = ctx.WithValue( + auth.AuthParamsContextKey{}, auth.DefaultParams()) // Continue on with default auth ante handler. newCtx, res, abort = authAnteHandler(ctx, tx, simulate) return }, ) - // Set begin and end transaction hooks. - // These are used to create gno transaction stores and commit them when finishing - // the tx - in other words, data from a failing transaction won't be persisted - // to the gno store caches. - baseApp.SetBeginTxHook(func(ctx sdk.Context) sdk.Context { - // Create Gno transaction store. - return vmk.MakeGnoTransactionStore(ctx) - }) - baseApp.SetEndTxHook(func(ctx sdk.Context, result sdk.Result) { - if result.IsOK() { - vmk.CommitGnoTransactionStore(ctx) - } - }) - // Set up the event collector c := newCollector[validatorUpdate]( cfg.EventSwitch, // global event switch filled by the node @@ -157,13 +143,13 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { // Initialize the VMKeeper. ms := baseApp.GetCacheMultiStore() - vmk.Initialize(cfg.Logger, ms) + vmk.Initialize(cfg.Logger, ms, cfg.CacheStdlibLoad) ms.MultiWrite() // XXX why was't this needed? return baseApp, nil } -// NewApp creates the gno.land application. +// NewApp creates the GnoLand application. func NewApp( dataRootDir string, skipFailingGenesisTxs bool, @@ -172,16 +158,9 @@ func NewApp( ) (abci.Application, error) { var err error - cfg := &AppOptions{ - Logger: logger, - EventSwitch: evsw, - InitChainerConfig: InitChainerConfig{ - GenesisTxResultHandler: PanicOnFailingTxResultHandler, - StdlibDir: filepath.Join(gnoenv.RootDir(), "gnovm", "stdlibs"), - }, - } + cfg := NewAppOptions() if skipFailingGenesisTxs { - cfg.GenesisTxResultHandler = NoopGenesisTxResultHandler + cfg.GenesisTxHandler = NoopGenesisTxHandler } // Get main DB. @@ -190,135 +169,74 @@ func NewApp( return nil, fmt.Errorf("error initializing database %q using path %q: %w", dbm.GoLevelDBBackend, dataRootDir, err) } + cfg.Logger = logger + cfg.EventSwitch = evsw + return NewAppWithOptions(cfg) } -// GenesisTxResultHandler is called in the InitChainer after a genesis -// transaction is executed. -type GenesisTxResultHandler func(ctx sdk.Context, tx std.Tx, res sdk.Result) +type GenesisTxHandler func(ctx sdk.Context, tx std.Tx, res sdk.Result) -// NoopGenesisTxResultHandler is a no-op GenesisTxResultHandler. -func NoopGenesisTxResultHandler(_ sdk.Context, _ std.Tx, _ sdk.Result) {} +func NoopGenesisTxHandler(_ sdk.Context, _ std.Tx, _ sdk.Result) {} -// PanicOnFailingTxResultHandler handles genesis transactions by panicking if -// res.IsErr() returns true. -func PanicOnFailingTxResultHandler(_ sdk.Context, _ std.Tx, res sdk.Result) { +func PanicOnFailingTxHandler(_ sdk.Context, _ std.Tx, res sdk.Result) { if res.IsErr() { panic(res.Log) } } -// InitChainerConfig keeps the configuration for the InitChainer. -// [NewAppWithOptions] will set [InitChainerConfig.InitChainer] as its InitChainer -// function. -type InitChainerConfig struct { - // Handles the results of each genesis transaction. - GenesisTxResultHandler - - // Standard library directory. - StdlibDir string - // Whether to keep a record of the DB operations to load standard libraries, - // so they can be quickly replicated on additional genesis executions. - // This should be used for integration testing, where InitChainer will be - // called several times. - CacheStdlibLoad bool - - // These fields are passed directly by NewAppWithOptions, and should not be - // configurable by end-users. - baseApp *sdk.BaseApp - vmKpr vm.VMKeeperI - acctKpr auth.AccountKeeperI - bankKpr bank.BankKeeperI -} - -// InitChainer is the function that can be used as a [sdk.InitChainer]. -func (cfg InitChainerConfig) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - start := time.Now() - ctx.Logger().Debug("InitChainer: started") - - // load standard libraries; immediately committed to store so that they are - // available for use when processing the genesis transactions below. - cfg.loadStdlibs(ctx) - ctx.Logger().Debug("InitChainer: standard libraries loaded", - "elapsed", time.Since(start)) - - // load app state. AppState may be nil mostly in some minimal testing setups; - // so log a warning when that happens. - txResponses, err := cfg.loadAppState(ctx, req.AppState) - if err != nil { - return abci.ResponseInitChain{ - ResponseBase: abci.ResponseBase{ - Error: abci.StringError(err.Error()), - }, +// InitChainer returns a function that can initialize the chain with genesis. +func InitChainer( + baseApp *sdk.BaseApp, + acctKpr auth.AccountKeeperI, + bankKpr bank.BankKeeperI, + resHandler GenesisTxHandler, +) func(sdk.Context, abci.RequestInitChain) abci.ResponseInitChain { + return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + txResponses := []abci.ResponseDeliverTx{} + + if req.AppState != nil { + // Get genesis state + genState := req.AppState.(GnoGenesisState) + + // Parse and set genesis state balances + for _, bal := range genState.Balances { + acc := acctKpr.NewAccountWithAddress(ctx, bal.Address) + acctKpr.SetAccount(ctx, acc) + err := bankKpr.SetCoins(ctx, bal.Address, bal.Amount) + if err != nil { + panic(err) + } + } + + // Run genesis txs + for _, tx := range genState.Txs { + res := baseApp.Deliver(tx) + if res.IsErr() { + ctx.Logger().Error( + "Unable to deliver genesis tx", + "log", res.Log, + "error", res.Error, + "gas-used", res.GasUsed, + ) + } + + txResponses = append(txResponses, abci.ResponseDeliverTx{ + ResponseBase: res.ResponseBase, + GasWanted: res.GasWanted, + GasUsed: res.GasUsed, + }) + + resHandler(ctx, tx, res) + } } - } - - ctx.Logger().Debug("InitChainer: genesis transactions loaded", - "elapsed", time.Since(start)) - - // Done! - return abci.ResponseInitChain{ - Validators: req.Validators, - TxResponses: txResponses, - } -} - -func (cfg InitChainerConfig) loadStdlibs(ctx sdk.Context) { - // cache-wrapping is necessary for non-validator nodes; in the tm2 BaseApp, - // this is done using BaseApp.cacheTxContext; so we replicate it here. - ms := ctx.MultiStore() - msCache := ms.MultiCacheWrap() - - stdlibCtx := cfg.vmKpr.MakeGnoTransactionStore(ctx) - stdlibCtx = stdlibCtx.WithMultiStore(msCache) - if cfg.CacheStdlibLoad { - cfg.vmKpr.LoadStdlibCached(stdlibCtx, cfg.StdlibDir) - } else { - cfg.vmKpr.LoadStdlib(stdlibCtx, cfg.StdlibDir) - } - cfg.vmKpr.CommitGnoTransactionStore(stdlibCtx) - - msCache.MultiWrite() -} -func (cfg InitChainerConfig) loadAppState(ctx sdk.Context, appState any) ([]abci.ResponseDeliverTx, error) { - state, ok := appState.(GnoGenesisState) - if !ok { - return nil, fmt.Errorf("invalid AppState of type %T", appState) - } - - // Parse and set genesis state balances - for _, bal := range state.Balances { - acc := cfg.acctKpr.NewAccountWithAddress(ctx, bal.Address) - cfg.acctKpr.SetAccount(ctx, acc) - err := cfg.bankKpr.SetCoins(ctx, bal.Address, bal.Amount) - if err != nil { - panic(err) - } - } - - txResponses := make([]abci.ResponseDeliverTx, 0, len(state.Txs)) - // Run genesis txs - for _, tx := range state.Txs { - res := cfg.baseApp.Deliver(tx) - if res.IsErr() { - ctx.Logger().Error( - "Unable to deliver genesis tx", - "log", res.Log, - "error", res.Error, - "gas-used", res.GasUsed, - ) + // Done! + return abci.ResponseInitChain{ + Validators: req.Validators, + TxResponses: txResponses, } - - txResponses = append(txResponses, abci.ResponseDeliverTx{ - ResponseBase: res.ResponseBase, - GasWanted: res.GasWanted, - GasUsed: res.GasUsed, - }) - - cfg.GenesisTxResultHandler(ctx, tx, res) } - return txResponses, nil } // endBlockerApp is the app abstraction required by any EndBlocker diff --git a/gno.land/pkg/gnoland/app_test.go b/gno.land/pkg/gnoland/app_test.go index 193ff0b0b14..852d090f3af 100644 --- a/gno.land/pkg/gnoland/app_test.go +++ b/gno.land/pkg/gnoland/app_test.go @@ -1,202 +1,20 @@ package gnoland import ( - "context" "errors" "fmt" "strings" "testing" - "time" - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" - gnostd "github.com/gnolang/gno/gnovm/stdlibs/std" - "github.com/gnolang/gno/tm2/pkg/amino" + "github.com/gnolang/gno/gnovm/stdlibs/std" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" - bft "github.com/gnolang/gno/tm2/pkg/bft/types" - "github.com/gnolang/gno/tm2/pkg/crypto" - "github.com/gnolang/gno/tm2/pkg/db/memdb" + "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/events" - "github.com/gnolang/gno/tm2/pkg/log" "github.com/gnolang/gno/tm2/pkg/sdk" - "github.com/gnolang/gno/tm2/pkg/std" - "github.com/gnolang/gno/tm2/pkg/store" - "github.com/gnolang/gno/tm2/pkg/store/dbadapter" - "github.com/gnolang/gno/tm2/pkg/store/iavl" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -// Tests that NewAppWithOptions works even when only providing a simple DB. -func TestNewAppWithOptions(t *testing.T) { - t.Parallel() - - app, err := NewAppWithOptions(TestAppOptions(memdb.NewMemDB())) - require.NoError(t, err) - bapp := app.(*sdk.BaseApp) - assert.Equal(t, "dev", bapp.AppVersion()) - assert.Equal(t, "gnoland", bapp.Name()) - - addr := crypto.AddressFromPreimage([]byte("test1")) - resp := bapp.InitChain(abci.RequestInitChain{ - Time: time.Now(), - ChainID: "dev", - ConsensusParams: &abci.ConsensusParams{ - Block: defaultBlockParams(), - }, - Validators: []abci.ValidatorUpdate{}, - AppState: GnoGenesisState{ - Balances: []Balance{ - { - Address: addr, - Amount: []std.Coin{{Amount: 1e15, Denom: "ugnot"}}, - }, - }, - Txs: []std.Tx{ - { - Msgs: []std.Msg{vm.NewMsgAddPackage(addr, "gno.land/r/demo", []*std.MemFile{ - { - Name: "demo.gno", - Body: "package demo; func Hello() string { return `hello`; }", - }, - })}, - Fee: std.Fee{GasWanted: 1e6, GasFee: std.Coin{Amount: 1e6, Denom: "ugnot"}}, - Signatures: []std.Signature{{}}, // one empty signature - }, - }, - }, - }) - require.True(t, resp.IsOK(), "InitChain response: %v", resp) - - tx := amino.MustMarshal(std.Tx{ - Msgs: []std.Msg{vm.NewMsgCall(addr, nil, "gno.land/r/demo", "Hello", nil)}, - Fee: std.Fee{ - GasWanted: 100_000, - GasFee: std.Coin{ - Denom: "ugnot", - Amount: 1_000_000, - }, - }, - Signatures: []std.Signature{{}}, // one empty signature - Memo: "", - }) - dtxResp := bapp.DeliverTx(abci.RequestDeliverTx{ - RequestBase: abci.RequestBase{}, - Tx: tx, - }) - require.True(t, dtxResp.IsOK(), "DeliverTx response: %v", dtxResp) -} - -func TestNewAppWithOptions_ErrNoDB(t *testing.T) { - t.Parallel() - - _, err := NewAppWithOptions(&AppOptions{}) - assert.ErrorContains(t, err, "no db provided") -} - -func TestNewApp(t *testing.T) { - // NewApp should have good defaults and manage to run InitChain. - td := t.TempDir() - - app, err := NewApp(td, true, events.NewEventSwitch(), log.NewNoopLogger()) - require.NoError(t, err, "NewApp should be successful") - - resp := app.InitChain(abci.RequestInitChain{ - RequestBase: abci.RequestBase{}, - Time: time.Time{}, - ChainID: "dev", - ConsensusParams: &abci.ConsensusParams{ - Block: defaultBlockParams(), - Validator: &abci.ValidatorParams{ - PubKeyTypeURLs: []string{}, - }, - }, - Validators: []abci.ValidatorUpdate{}, - AppState: GnoGenesisState{}, - }) - assert.True(t, resp.IsOK(), "resp is not OK: %v", resp) -} - -// Test whether InitChainer calls to load the stdlibs correctly. -func TestInitChainer_LoadStdlib(t *testing.T) { - t.Parallel() - - t.Run("cached", func(t *testing.T) { testInitChainerLoadStdlib(t, true) }) - t.Run("uncached", func(t *testing.T) { testInitChainerLoadStdlib(t, false) }) -} - -func testInitChainerLoadStdlib(t *testing.T, cached bool) { //nolint:thelper - t.Parallel() - - type gsContextType string - const ( - stdlibDir = "test-stdlib-dir" - gnoStoreKey gsContextType = "gno-store-key" - gnoStoreValue gsContextType = "gno-store-value" - ) - db := memdb.NewMemDB() - ms := store.NewCommitMultiStore(db) - baseCapKey := store.NewStoreKey("baseCapKey") - iavlCapKey := store.NewStoreKey("iavlCapKey") - - ms.MountStoreWithDB(baseCapKey, dbadapter.StoreConstructor, db) - ms.MountStoreWithDB(iavlCapKey, iavl.StoreConstructor, db) - ms.LoadLatestVersion() - testCtx := sdk.NewContext(sdk.RunTxModeDeliver, ms.MultiCacheWrap(), &bft.Header{ChainID: "test-chain-id"}, log.NewNoopLogger()) - - // mock set-up - var ( - makeCalls int - commitCalls int - loadStdlibCalls int - loadStdlibCachedCalls int - ) - containsGnoStore := func(ctx sdk.Context) bool { - return ctx.Context().Value(gnoStoreKey) == gnoStoreValue - } - // ptr is pointer to either loadStdlibCalls or loadStdlibCachedCalls - loadStdlib := func(ptr *int) func(ctx sdk.Context, dir string) { - return func(ctx sdk.Context, dir string) { - assert.Equal(t, stdlibDir, dir, "stdlibDir should match provided dir") - assert.True(t, containsGnoStore(ctx), "should contain gno store") - *ptr++ - } - } - mock := &mockVMKeeper{ - makeGnoTransactionStoreFn: func(ctx sdk.Context) sdk.Context { - makeCalls++ - assert.False(t, containsGnoStore(ctx), "should not already contain gno store") - return ctx.WithContext(context.WithValue(ctx.Context(), gnoStoreKey, gnoStoreValue)) - }, - commitGnoTransactionStoreFn: func(ctx sdk.Context) { - commitCalls++ - assert.True(t, containsGnoStore(ctx), "should contain gno store") - }, - loadStdlibFn: loadStdlib(&loadStdlibCalls), - loadStdlibCachedFn: loadStdlib(&loadStdlibCachedCalls), - } - - // call initchainer - cfg := InitChainerConfig{ - StdlibDir: stdlibDir, - vmKpr: mock, - CacheStdlibLoad: cached, - } - cfg.InitChainer(testCtx, abci.RequestInitChain{ - AppState: GnoGenesisState{}, - }) - - // assert number of calls - assert.Equal(t, 1, makeCalls, "should call MakeGnoTransactionStore once") - assert.Equal(t, 1, commitCalls, "should call CommitGnoTransactionStore once") - if cached { - assert.Equal(t, 0, loadStdlibCalls, "should call LoadStdlib never") - assert.Equal(t, 1, loadStdlibCachedCalls, "should call LoadStdlibCached once") - } else { - assert.Equal(t, 1, loadStdlibCalls, "should call LoadStdlib once") - assert.Equal(t, 0, loadStdlibCachedCalls, "should call LoadStdlibCached never") - } -} - // generateValidatorUpdates generates dummy validator updates func generateValidatorUpdates(t *testing.T, count int) []abci.ValidatorUpdate { t.Helper() @@ -263,7 +81,7 @@ func TestEndBlocker(t *testing.T) { t.Run("no collector events", func(t *testing.T) { t.Parallel() - noFilter := func(_ events.Event) []validatorUpdate { + noFilter := func(e events.Event) []validatorUpdate { return []validatorUpdate{} } @@ -284,7 +102,7 @@ func TestEndBlocker(t *testing.T) { t.Parallel() var ( - noFilter = func(_ events.Event) []validatorUpdate { + noFilter = func(e events.Event) []validatorUpdate { return make([]validatorUpdate, 1) // 1 update } @@ -308,7 +126,7 @@ func TestEndBlocker(t *testing.T) { c := newCollector[validatorUpdate](mockEventSwitch, noFilter) // Fire a GnoVM event - mockEventSwitch.FireEvent(gnostd.GnoEvent{}) + mockEventSwitch.FireEvent(std.GnoEvent{}) // Create the EndBlocker eb := EndBlocker(c, mockVMKeeper, &mockEndBlockerApp{}) @@ -327,7 +145,7 @@ func TestEndBlocker(t *testing.T) { t.Parallel() var ( - noFilter = func(_ events.Event) []validatorUpdate { + noFilter = func(e events.Event) []validatorUpdate { return make([]validatorUpdate, 1) // 1 update } @@ -351,7 +169,7 @@ func TestEndBlocker(t *testing.T) { c := newCollector[validatorUpdate](mockEventSwitch, noFilter) // Fire a GnoVM event - mockEventSwitch.FireEvent(gnostd.GnoEvent{}) + mockEventSwitch.FireEvent(std.GnoEvent{}) // Create the EndBlocker eb := EndBlocker(c, mockVMKeeper, &mockEndBlockerApp{}) @@ -390,7 +208,7 @@ func TestEndBlocker(t *testing.T) { // Construct the GnoVM events vmEvents := make([]abci.Event, 0, len(changes)) for index := range changes { - event := gnostd.GnoEvent{ + event := std.GnoEvent{ Type: validatorAddedEvent, PkgPath: valRealm, } @@ -399,7 +217,7 @@ func TestEndBlocker(t *testing.T) { if index%2 == 0 { changes[index].Power = 0 - event = gnostd.GnoEvent{ + event = std.GnoEvent{ Type: validatorRemovedEvent, PkgPath: valRealm, } @@ -409,8 +227,8 @@ func TestEndBlocker(t *testing.T) { } // Fire the tx result event - txEvent := bft.EventTx{ - Result: bft.TxResult{ + txEvent := types.EventTx{ + Result: types.TxResult{ Response: abci.ResponseDeliverTx{ ResponseBase: abci.ResponseBase{ Events: vmEvents, diff --git a/gno.land/pkg/gnoland/balance_test.go b/gno.land/pkg/gnoland/balance_test.go index 99a348e9f2f..59dffcc4333 100644 --- a/gno.land/pkg/gnoland/balance_test.go +++ b/gno.land/pkg/gnoland/balance_test.go @@ -7,7 +7,6 @@ import ( "strings" "testing" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/amino" bft "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/crypto" @@ -79,7 +78,7 @@ func TestBalance_Parse(t *testing.T) { func TestBalance_AminoUnmarshalJSON(t *testing.T) { expected := Balance{ Address: crypto.MustAddressFromString("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"), - Amount: std.MustParseCoins(ugnot.ValueString(100)), + Amount: std.MustParseCoins("100ugnot"), } value := fmt.Sprintf("[%q]", expected.String()) @@ -96,7 +95,7 @@ func TestBalance_AminoUnmarshalJSON(t *testing.T) { func TestBalance_AminoMarshalJSON(t *testing.T) { expected := Balance{ Address: crypto.MustAddressFromString("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"), - Amount: std.MustParseCoins(ugnot.ValueString(100)), + Amount: std.MustParseCoins("100ugnot"), } expectedJSON := fmt.Sprintf("[%q]", expected.String()) @@ -113,15 +112,15 @@ func TestBalances_GetBalancesFromEntries(t *testing.T) { // Generate dummy keys dummyKeys := getDummyKeys(t, 2) - amount := std.NewCoins(std.NewCoin(ugnot.Denom, 10)) + amount := std.NewCoins(std.NewCoin("ugnot", 10)) entries := make([]string, len(dummyKeys)) for index, key := range dummyKeys { entries[index] = fmt.Sprintf( - "%s=%s", + "%s=%dugnot", key.Address().String(), - ugnot.ValueString(amount.AmountOf(ugnot.Denom)), + amount.AmountOf("ugnot"), ) } @@ -151,7 +150,7 @@ func TestBalances_GetBalancesFromEntries(t *testing.T) { t.Parallel() balances := []string{ - "dummyaddress=" + ugnot.ValueString(10), + "dummyaddress=10ugnot", } balanceMap, err := GetBalancesFromEntries(balances...) @@ -166,10 +165,9 @@ func TestBalances_GetBalancesFromEntries(t *testing.T) { balances := []string{ fmt.Sprintf( - "%s=%s%s", + "%s=%sugnot", dummyKey.Address().String(), strconv.FormatUint(math.MaxUint64, 10), - ugnot.Denom, ), } @@ -187,15 +185,15 @@ func TestBalances_GetBalancesFromSheet(t *testing.T) { // Generate dummy keys dummyKeys := getDummyKeys(t, 2) - amount := std.NewCoins(std.NewCoin(ugnot.Denom, 10)) + amount := std.NewCoins(std.NewCoin("ugnot", 10)) balances := make([]string, len(dummyKeys)) for index, key := range dummyKeys { balances[index] = fmt.Sprintf( - "%s=%s", + "%s=%dugnot", key.Address().String(), - ugnot.ValueString(amount.AmountOf(ugnot.Denom)), + amount.AmountOf("ugnot"), ) } @@ -217,10 +215,9 @@ func TestBalances_GetBalancesFromSheet(t *testing.T) { balances := []string{ fmt.Sprintf( - "%s=%s%s", + "%s=%sugnot", dummyKey.Address().String(), strconv.FormatUint(math.MaxUint64, 10), - ugnot.Denom, ), } diff --git a/gno.land/pkg/gnoland/mock_test.go b/gno.land/pkg/gnoland/mock_test.go index 62aecaf5278..1ff9f168bd1 100644 --- a/gno.land/pkg/gnoland/mock_test.go +++ b/gno.land/pkg/gnoland/mock_test.go @@ -45,15 +45,18 @@ func (m *mockEventSwitch) RemoveListener(listenerID string) { } } +type ( + addPackageDelegate func(sdk.Context, vm.MsgAddPackage) error + callDelegate func(sdk.Context, vm.MsgCall) (string, error) + queryEvalDelegate func(sdk.Context, string, string) (string, error) + runDelegate func(sdk.Context, vm.MsgRun) (string, error) +) + type mockVMKeeper struct { - addPackageFn func(sdk.Context, vm.MsgAddPackage) error - callFn func(sdk.Context, vm.MsgCall) (string, error) - queryFn func(sdk.Context, string, string) (string, error) - runFn func(sdk.Context, vm.MsgRun) (string, error) - loadStdlibFn func(sdk.Context, string) - loadStdlibCachedFn func(sdk.Context, string) - makeGnoTransactionStoreFn func(ctx sdk.Context) sdk.Context - commitGnoTransactionStoreFn func(ctx sdk.Context) + addPackageFn addPackageDelegate + callFn callDelegate + queryFn queryEvalDelegate + runFn runDelegate } func (m *mockVMKeeper) AddPackage(ctx sdk.Context, msg vm.MsgAddPackage) error { @@ -88,31 +91,6 @@ func (m *mockVMKeeper) Run(ctx sdk.Context, msg vm.MsgRun) (res string, err erro return "", nil } -func (m *mockVMKeeper) LoadStdlib(ctx sdk.Context, stdlibDir string) { - if m.loadStdlibFn != nil { - m.loadStdlibFn(ctx, stdlibDir) - } -} - -func (m *mockVMKeeper) LoadStdlibCached(ctx sdk.Context, stdlibDir string) { - if m.loadStdlibCachedFn != nil { - m.loadStdlibCachedFn(ctx, stdlibDir) - } -} - -func (m *mockVMKeeper) MakeGnoTransactionStore(ctx sdk.Context) sdk.Context { - if m.makeGnoTransactionStoreFn != nil { - return m.makeGnoTransactionStoreFn(ctx) - } - return ctx -} - -func (m *mockVMKeeper) CommitGnoTransactionStore(ctx sdk.Context) { - if m.commitGnoTransactionStoreFn != nil { - m.commitGnoTransactionStoreFn(ctx) - } -} - type ( lastBlockHeightDelegate func() int64 loggerDelegate func() *slog.Logger diff --git a/gno.land/pkg/gnoland/node_inmemory.go b/gno.land/pkg/gnoland/node_inmemory.go index d168c955607..02691f89c3e 100644 --- a/gno.land/pkg/gnoland/node_inmemory.go +++ b/gno.land/pkg/gnoland/node_inmemory.go @@ -3,7 +3,6 @@ package gnoland import ( "fmt" "log/slog" - "path/filepath" "time" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" @@ -23,11 +22,8 @@ type InMemoryNodeConfig struct { PrivValidator bft.PrivValidator // identity of the validator Genesis *bft.GenesisDoc TMConfig *tmcfg.Config + GenesisTxHandler GenesisTxHandler GenesisMaxVMCycles int64 - DB *memdb.MemDB // will be initialized if nil - - // If StdlibDir not set, then it's filepath.Join(TMConfig.RootDir, "gnovm", "stdlibs") - InitChainerConfig } // NewMockedPrivValidator generate a new key @@ -41,7 +37,12 @@ func NewDefaultGenesisConfig(chainid string) *bft.GenesisDoc { GenesisTime: time.Now(), ChainID: chainid, ConsensusParams: abci.ConsensusParams{ - Block: defaultBlockParams(), + Block: &abci.BlockParams{ + MaxTxBytes: 1_000_000, // 1MB, + MaxDataBytes: 2_000_000, // 2MB, + MaxGas: 100_000_000, // 100M gas + TimeIotaMS: 100, // 100ms + }, }, AppState: &GnoGenesisState{ Balances: []Balance{}, @@ -50,15 +51,6 @@ func NewDefaultGenesisConfig(chainid string) *bft.GenesisDoc { } } -func defaultBlockParams() *abci.BlockParams { - return &abci.BlockParams{ - MaxTxBytes: 1_000_000, // 1MB, - MaxDataBytes: 2_000_000, // 2MB, - MaxGas: 100_000_000, // 100M gas - TimeIotaMS: 100, // 100ms - } -} - func NewDefaultTMConfig(rootdir string) *tmcfg.Config { // We use `TestConfig` here otherwise ChainID will be empty, and // there is no other way to update it than using a config file @@ -78,7 +70,7 @@ func (cfg *InMemoryNodeConfig) validate() error { return fmt.Errorf("`TMConfig.RootDir` is required to locate `stdlibs` directory") } - if cfg.GenesisTxResultHandler == nil { + if cfg.GenesisTxHandler == nil { return fmt.Errorf("`GenesisTxHandler` is required but not provided") } @@ -95,21 +87,15 @@ func NewInMemoryNode(logger *slog.Logger, cfg *InMemoryNodeConfig) (*node.Node, evsw := events.NewEventSwitch() - if cfg.StdlibDir == "" { - cfg.StdlibDir = filepath.Join(cfg.TMConfig.RootDir, "gnovm", "stdlibs") - } - // initialize db if nil - if cfg.DB == nil { - cfg.DB = memdb.NewMemDB() - } - // Initialize the application with the provided options gnoApp, err := NewAppWithOptions(&AppOptions{ - Logger: logger, - MaxCycles: cfg.GenesisMaxVMCycles, - DB: cfg.DB, - EventSwitch: evsw, - InitChainerConfig: cfg.InitChainerConfig, + Logger: logger, + GnoRootDir: cfg.TMConfig.RootDir, + GenesisTxHandler: cfg.GenesisTxHandler, + MaxCycles: cfg.GenesisMaxVMCycles, + DB: memdb.NewMemDB(), + EventSwitch: evsw, + CacheStdlibLoad: true, }) if err != nil { return nil, fmt.Errorf("error initializing new app: %w", err) @@ -128,7 +114,7 @@ func NewInMemoryNode(logger *slog.Logger, cfg *InMemoryNodeConfig) (*node.Node, // Create genesis factory genProvider := func() (*bft.GenesisDoc, error) { return cfg.Genesis, nil } - dbProvider := func(*node.DBContext) (db.DB, error) { return cfg.DB, nil } + dbProvider := func(*node.DBContext) (db.DB, error) { return memdb.NewMemDB(), nil } // Generate p2p node identity nodekey := &p2p.NodeKey{PrivKey: ed25519.GenPrivKey()} diff --git a/gno.land/pkg/gnoland/ugnot/denom.go b/gno.land/pkg/gnoland/ugnot/denom.go deleted file mode 100644 index 734c8532398..00000000000 --- a/gno.land/pkg/gnoland/ugnot/denom.go +++ /dev/null @@ -1,11 +0,0 @@ -package ugnot - -import "strconv" - -// Denom is the denomination for ugnot, gno.land's native token. -const Denom = "ugnot" - -// ValueString converts `value` to a string, appends "ugnot", and returns it. -func ValueString(value int64) string { - return strconv.FormatInt(value, 10) + Denom -} diff --git a/gno.land/pkg/gnoweb/alias.go b/gno.land/pkg/gnoweb/alias.go deleted file mode 100644 index 7fb28d5cbc3..00000000000 --- a/gno.land/pkg/gnoweb/alias.go +++ /dev/null @@ -1,27 +0,0 @@ -package gnoweb - -// realm aliases -var Aliases = map[string]string{ - "/": "/r/gnoland/home", - "/about": "/r/gnoland/pages:p/about", - "/gnolang": "/r/gnoland/pages:p/gnolang", - "/ecosystem": "/r/gnoland/pages:p/ecosystem", - "/partners": "/r/gnoland/pages:p/partners", - "/testnets": "/r/gnoland/pages:p/testnets", - "/start": "/r/gnoland/pages:p/start", - "/license": "/r/gnoland/pages:p/license", - "/contribute": "/r/gnoland/pages:p/contribute", - "/events": "/r/gnoland/events", -} - -// http redirects -var Redirects = map[string]string{ - "/r/demo/boards:gnolang/6": "/r/demo/boards:gnolang/3", // XXX: temporary - "/blog": "/r/gnoland/blog", - "/gor": "/contribute", - "/game-of-realms": "/contribute", - "/grants": "/partners", - "/language": "/gnolang", - "/getting-started": "/start", - "/gophercon24": "https://docs.gno.land", -} diff --git a/gno.land/pkg/gnoweb/gnoweb.go b/gno.land/pkg/gnoweb/gnoweb.go index 5377ae6a420..b997de7840d 100644 --- a/gno.land/pkg/gnoweb/gnoweb.go +++ b/gno.land/pkg/gnoweb/gnoweb.go @@ -1,7 +1,6 @@ package gnoweb import ( - "bytes" "embed" "encoding/json" "errors" @@ -80,11 +79,34 @@ func MakeApp(logger *slog.Logger, cfg Config) gotuna.App { Static: static.EmbeddedStatic, } - for from, to := range Aliases { - app.Router.Handle(from, handlerRealmAlias(logger, app, &cfg, to)) + // realm aliases + aliases := map[string]string{ + "/": "/r/gnoland/home", + "/about": "/r/gnoland/pages:p/about", + "/gnolang": "/r/gnoland/pages:p/gnolang", + "/ecosystem": "/r/gnoland/pages:p/ecosystem", + "/partners": "/r/gnoland/pages:p/partners", + "/testnets": "/r/gnoland/pages:p/testnets", + "/start": "/r/gnoland/pages:p/start", + "/license": "/r/gnoland/pages:p/license", + "/game-of-realms": "/r/gnoland/pages:p/gor", // XXX: replace with gor realm + "/events": "/r/gnoland/events", } - for from, to := range Redirects { + for from, to := range aliases { + app.Router.Handle(from, handlerRealmAlias(logger, app, &cfg, to)) + } + // http redirects + redirects := map[string]string{ + "/r/demo/boards:gnolang/6": "/r/demo/boards:gnolang/3", // XXX: temporary + "/blog": "/r/gnoland/blog", + "/gor": "/game-of-realms", + "/grants": "/partners", + "/language": "/gnolang", + "/getting-started": "/start", + "/gophercon24": "https://docs.gno.land", + } + for from, to := range redirects { app.Router.Handle(from, handlerRedirect(logger, app, &cfg, to)) } // realm routes @@ -313,15 +335,6 @@ func handleRealmRender(logger *slog.Logger, app gotuna.App, cfg *Config, w http. return } } - - dirdata := []byte(rlmpath) - dirres, err := makeRequest(logger, cfg, qFileStr, dirdata) - if err != nil { - writeError(logger, w, err) - return - } - hasReadme := bytes.Contains(append(dirres.Data, '\n'), []byte("README.md\n")) - // linkify querystr. queryParts := strings.Split(querystr, "/") pathLinks := []pathLink{} @@ -341,7 +354,6 @@ func handleRealmRender(logger *slog.Logger, app gotuna.App, cfg *Config, w http. tmpl.Set("PathLinks", pathLinks) tmpl.Set("Contents", string(res.Data)) tmpl.Set("Config", cfg) - tmpl.Set("HasReadme", hasReadme) tmpl.Render(w, r, "realm_render.html", "funcs.html") } diff --git a/gno.land/pkg/gnoweb/gnoweb_test.go b/gno.land/pkg/gnoweb/gnoweb_test.go index 18df5ec2356..b266dc80a6a 100644 --- a/gno.land/pkg/gnoweb/gnoweb_test.go +++ b/gno.land/pkg/gnoweb/gnoweb_test.go @@ -38,9 +38,8 @@ func TestRoutes(t *testing.T) { {"/r/demo/deep/very/deep?help", ok, "exposed"}, {"/r/demo/deep/very/deep/", ok, "render.gno"}, {"/r/demo/deep/very/deep/render.gno", ok, "func Render("}, - {"/contribute", ok, "Game of Realms"}, - {"/game-of-realms", found, "/contribute"}, - {"/gor", found, "/contribute"}, + {"/game-of-realms", ok, "/r/gnoland/pages:p/gor"}, + {"/gor", found, "/game-of-realms"}, {"/blog", found, "/r/gnoland/blog"}, {"/404-not-found", notFound, "/404-not-found"}, {"/아스키문자가아닌경로", notFound, "/아스키문자가아닌경로"}, diff --git a/gno.land/pkg/gnoweb/static/js/renderer.js b/gno.land/pkg/gnoweb/static/js/renderer.js index 0aa6400633d..4937b5a5691 100644 --- a/gno.land/pkg/gnoweb/static/js/renderer.js +++ b/gno.land/pkg/gnoweb/static/js/renderer.js @@ -7,42 +7,27 @@ function renderUsernames(raw) { return raw.replace(/( |\n)@([_a-z0-9]{5,16})/, "$1[@$2](/r/demo/users:$2)"); } -function parseContent(source, isCode) { - if (isCode) { - const highlightedCode = hljs.highlightAuto(source).value; - const codeElement = document.createElement("code"); - codeElement.classList.add("hljs"); - codeElement.innerHTML = highlightedCode; - - const preElement = document.createElement("pre"); - preElement.appendChild(codeElement); - - return preElement; - } else { - const { markedHighlight } = globalThis.markedHighlight; - const { Marked } = globalThis.marked; - const markedInstance = new Marked( - markedHighlight({ - langPrefix: "language-", - highlight(code, lang, info) { - if (lang === "json") { - try { - code = JSON.stringify(JSON.parse(code), null, 2); - } catch { - console.error('Error: The provided JSON code is invalid.'); - } - } - const language = hljs.getLanguage(lang) ? lang : "plaintext"; - return hljs.highlight(code, { language }).value; - }, - }) - ); - markedInstance.setOptions({ gfm: true }); - const doc = new DOMParser().parseFromString(source, "text/html"); - const contents = doc.documentElement.textContent; - - return markedInstance.parse(contents); - } +function parseContent(source) { + const { markedHighlight } = globalThis.markedHighlight; + const { Marked } = globalThis.marked; + const markedInstance = new Marked( + markedHighlight({ + langPrefix: 'language-', + highlight(code, lang, info) { + if (lang === "json") { + try { + code = JSON.stringify(JSON.parse(code), null, 2); + } catch {} + } + const language = hljs.getLanguage(lang) ? lang : 'plaintext'; + return hljs.highlight(code, { language }).value; + } + }) + ); + markedInstance.setOptions({ gfm: true }); + const doc = new DOMParser().parseFromString(source, "text/html"); + const contents = doc.documentElement.textContent; + return markedInstance.parse(contents); } /* diff --git a/gno.land/pkg/gnoweb/views/funcs.html b/gno.land/pkg/gnoweb/views/funcs.html index d676fec9a69..a02f83144f8 100644 --- a/gno.land/pkg/gnoweb/views/funcs.html +++ b/gno.land/pkg/gnoweb/views/funcs.html @@ -15,7 +15,7 @@
  • Blog
  • Docs
  • Playground
  • -
  • Contribute
  • +
  • Game of Realms
  • @@ -144,11 +144,11 @@ -{{- end -}} +{{- end -}} {{- define "footer" -}}
    - {{ template "logo" }} + {{ template "logo" }}
    {{- end -}} @@ -160,20 +160,18 @@ diff --git a/gno.land/pkg/gnoweb/views/package_file.html b/gno.land/pkg/gnoweb/views/package_file.html index 43e7820b29f..42e1d0a28fc 100644 --- a/gno.land/pkg/gnoweb/views/package_file.html +++ b/gno.land/pkg/gnoweb/views/package_file.html @@ -11,13 +11,21 @@
    {{ .Data.DirPath }}/{{ .Data.FileName }}
    +
    - {{ .Data.FileContents }} +
    {{ .Data.FileContents }}
    {{ template "footer" }}
    {{ template "js" .}} + + {{- end -}} diff --git a/gno.land/pkg/gnoweb/views/realm_render.html b/gno.land/pkg/gnoweb/views/realm_render.html index 924ef2b414f..9a4507777a6 100644 --- a/gno.land/pkg/gnoweb/views/realm_render.html +++ b/gno.land/pkg/gnoweb/views/realm_render.html @@ -16,9 +16,6 @@ {{- end -}} - {{ if .Data.HasReadme }} - [readme] - {{ end }} [source] [help] diff --git a/gno.land/pkg/integration/doc.go b/gno.land/pkg/integration/doc.go index ef3ed9923da..2b6d24c23b8 100644 --- a/gno.land/pkg/integration/doc.go +++ b/gno.land/pkg/integration/doc.go @@ -8,12 +8,9 @@ // // Additional Command Overview: // -// 1. `gnoland [start|stop|restart]`: +// 1. `gnoland [start|stop]`: // - The gnoland node doesn't start automatically. This enables the user to do some // pre-configuration or pass custom arguments to the start command. -// - `gnoland restart` will simulate restarting a node, as in stopping and -// starting it again, recovering state from the persisted database data. -// - `gnoland start -non-validator` can be used to start a node as a non-validator node. // // 2. `gnokey`: // - Supports most of the common commands. diff --git a/gno.land/pkg/integration/testdata/gnoland.txtar b/gno.land/pkg/integration/testdata/gnoland.txtar index 78bdc9cae4e..c675e7578b6 100644 --- a/gno.land/pkg/integration/testdata/gnoland.txtar +++ b/gno.land/pkg/integration/testdata/gnoland.txtar @@ -28,7 +28,7 @@ cmp stderr gnoland-already-stop.stderr.golden -- gnoland-no-arguments.stdout.golden -- -- gnoland-no-arguments.stderr.golden -- -"gnoland" error: syntax: gnoland [start|stop|restart] +"gnoland" error: syntax: gnoland [start|stop] -- gnoland-start.stdout.golden -- node started successfully -- gnoland-start.stderr.golden -- diff --git a/gno.land/pkg/integration/testdata/restart.txtar b/gno.land/pkg/integration/testdata/restart.txtar deleted file mode 100644 index 8d50dd15814..00000000000 --- a/gno.land/pkg/integration/testdata/restart.txtar +++ /dev/null @@ -1,24 +0,0 @@ -# simple test for the `gnoland restart` command; -# should restart the gno.land node and recover state. - -loadpkg gno.land/r/demo/counter $WORK -gnoland start - -gnokey maketx call -pkgpath gno.land/r/demo/counter -func Incr -gas-fee 1000000ugnot -gas-wanted 100000 -broadcast -chainid tendermint_test test1 -stdout '\(1 int\)' - -gnoland restart - -gnokey maketx call -pkgpath gno.land/r/demo/counter -func Incr -gas-fee 1000000ugnot -gas-wanted 100000 -broadcast -chainid tendermint_test test1 -stdout '\(2 int\)' - --- counter.gno -- -package counter - -var counter int - -func Incr() int { - counter++ - return counter -} - diff --git a/gno.land/pkg/integration/testing_integration.go b/gno.land/pkg/integration/testing_integration.go index d3f55cfadf7..0462b0c7639 100644 --- a/gno.land/pkg/integration/testing_integration.go +++ b/gno.land/pkg/integration/testing_integration.go @@ -3,7 +3,6 @@ package integration import ( "context" "errors" - "flag" "fmt" "hash/crc32" "log/slog" @@ -14,7 +13,6 @@ import ( "testing" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/gno.land/pkg/keyscli" "github.com/gnolang/gno/gno.land/pkg/log" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" @@ -27,7 +25,6 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto/bip39" "github.com/gnolang/gno/tm2/pkg/crypto/keys" "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" - "github.com/gnolang/gno/tm2/pkg/db/memdb" tm2Log "github.com/gnolang/gno/tm2/pkg/log" "github.com/gnolang/gno/tm2/pkg/std" "github.com/rogpeppe/go-internal/testscript" @@ -74,7 +71,6 @@ func RunGnolandTestscripts(t *testing.T, txtarDir string) { type testNode struct { *node.Node - cfg *gnoland.InMemoryNodeConfig nGnoKeyExec uint // Counter for execution of gnokey. } @@ -155,7 +151,7 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params { Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){ "gnoland": func(ts *testscript.TestScript, neg bool, args []string) { if len(args) == 0 { - tsValidateError(ts, "gnoland", neg, fmt.Errorf("syntax: gnoland [start|stop|restart]")) + tsValidateError(ts, "gnoland", neg, fmt.Errorf("syntax: gnoland [start|stop]")) return } @@ -173,17 +169,10 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params { break } - // parse flags - fs := flag.NewFlagSet("start", flag.ContinueOnError) - nonVal := fs.Bool("non-validator", false, "set up node as a non-validator") - if err := fs.Parse(args); err != nil { - ts.Fatalf("unable to parse `gnoland start` flags: %s", err) - } - // get packages pkgs := ts.Value(envKeyPkgsLoader).(*pkgsLoader) // grab logger creator := crypto.MustAddressFromString(DefaultAccount_Address) // test1 - defaultFee := std.NewFee(50000, std.MustParseCoin(ugnot.ValueString(1000000))) + defaultFee := std.NewFee(50000, std.MustParseCoin("1000000ugnot")) pkgsTxs, err := pkgs.LoadPackages(creator, defaultFee, nil) if err != nil { ts.Fatalf("unable to load packages txs: %s", err) @@ -199,50 +188,16 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params { // setup genesis state cfg.Genesis.AppState = *genesis - if *nonVal { - // re-create cfg.Genesis.Validators with a throwaway pv, so we start as a - // non-validator. - pv := gnoland.NewMockedPrivValidator() - cfg.Genesis.Validators = []bft.GenesisValidator{ - { - Address: pv.GetPubKey().Address(), - PubKey: pv.GetPubKey(), - Power: 10, - Name: "none", - }, - } - } - cfg.DB = memdb.NewMemDB() // so it can be reused when restarting. n, remoteAddr := TestingInMemoryNode(t, logger, cfg) // Register cleanup - nodes[sid] = &testNode{Node: n, cfg: cfg} + nodes[sid] = &testNode{Node: n} // Add default environments ts.Setenv("RPC_ADDR", remoteAddr) fmt.Fprintln(ts.Stdout(), "node started successfully") - case "restart": - n, ok := nodes[sid] - if !ok { - err = fmt.Errorf("node must be started before being restarted") - break - } - - if stopErr := n.Stop(); stopErr != nil { - err = fmt.Errorf("error stopping node: %w", stopErr) - break - } - - // Create new node with same config. - newNode, newRemoteAddr := TestingInMemoryNode(t, logger, n.cfg) - - // Update testNode and environment variables. - n.Node = newNode - ts.Setenv("RPC_ADDR", newRemoteAddr) - - fmt.Fprintln(ts.Stdout(), "node restarted successfully") case "stop": n, ok := nodes[sid] if !ok { @@ -607,7 +562,7 @@ func createAccount(env envSetter, kb keys.Keybase, accountName string) (gnoland. return gnoland.Balance{ Address: address, - Amount: std.Coins{std.NewCoin(ugnot.Denom, 10e6)}, + Amount: std.Coins{std.NewCoin("ugnot", 10e6)}, }, nil } @@ -631,7 +586,7 @@ func createAccountFrom(env envSetter, kb keys.Keybase, accountName, mnemonic str return gnoland.Balance{ Address: address, - Amount: std.Coins{std.NewCoin(ugnot.Denom, 10e6)}, + Amount: std.Coins{std.NewCoin("ugnot", 10e6)}, }, nil } diff --git a/gno.land/pkg/integration/testing_node.go b/gno.land/pkg/integration/testing_node.go index 5e9e2272049..993386f6b04 100644 --- a/gno.land/pkg/integration/testing_node.go +++ b/gno.land/pkg/integration/testing_node.go @@ -3,17 +3,14 @@ package integration import ( "log/slog" "path/filepath" - "slices" "time" "github.com/gnolang/gno/gno.land/pkg/gnoland" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" tmcfg "github.com/gnolang/gno/tm2/pkg/bft/config" "github.com/gnolang/gno/tm2/pkg/bft/node" bft "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/crypto" - "github.com/gnolang/gno/tm2/pkg/db/memdb" "github.com/gnolang/gno/tm2/pkg/std" "github.com/stretchr/testify/require" ) @@ -33,19 +30,10 @@ func TestingInMemoryNode(t TestingTS, logger *slog.Logger, config *gnoland.InMem err = node.Start() require.NoError(t, err) - ourAddress := config.PrivValidator.GetPubKey().Address() - isValidator := slices.ContainsFunc(config.Genesis.Validators, func(val bft.GenesisValidator) bool { - return val.Address == ourAddress - }) - - // Wait for first block if we are a validator. - // If we are not a validator, we don't produce blocks, so node.Ready() hangs. - if isValidator { - select { - case <-node.Ready(): - case <-time.After(time.Second * 10): - require.FailNow(t, "timeout while waiting for the node to start") - } + select { + case <-node.Ready(): + case <-time.After(time.Second * 10): + require.FailNow(t, "timeout while waiting for the node to start") } return node, node.Config().RPC.ListenAddress @@ -83,14 +71,10 @@ func TestingMinimalNodeConfig(t TestingTS, gnoroot string) *gnoland.InMemoryNode genesis := DefaultTestingGenesisConfig(t, gnoroot, pv.GetPubKey(), tmconfig) return &gnoland.InMemoryNodeConfig{ - PrivValidator: pv, - Genesis: genesis, - TMConfig: tmconfig, - DB: memdb.NewMemDB(), - InitChainerConfig: gnoland.InitChainerConfig{ - GenesisTxResultHandler: gnoland.PanicOnFailingTxResultHandler, - CacheStdlibLoad: true, - }, + PrivValidator: pv, + Genesis: genesis, + TMConfig: tmconfig, + GenesisTxHandler: gnoland.PanicOnFailingTxHandler, } } @@ -118,7 +102,7 @@ func DefaultTestingGenesisConfig(t TestingTS, gnoroot string, self crypto.PubKey Balances: []gnoland.Balance{ { Address: crypto.MustAddressFromString(DefaultAccount_Address), - Amount: std.MustParseCoins(ugnot.ValueString(10000000000000)), + Amount: std.MustParseCoins("10000000000000ugnot"), }, }, Txs: []std.Tx{}, @@ -130,7 +114,7 @@ func DefaultTestingGenesisConfig(t TestingTS, gnoroot string, self crypto.PubKey func LoadDefaultPackages(t TestingTS, creator bft.Address, gnoroot string) []std.Tx { examplesDir := filepath.Join(gnoroot, "examples") - defaultFee := std.NewFee(50000, std.MustParseCoin(ugnot.ValueString(1000000))) + defaultFee := std.NewFee(50000, std.MustParseCoin("1000000ugnot")) txs, err := gnoland.LoadPackagesFromDir(examplesDir, creator, defaultFee) require.NoError(t, err) diff --git a/gno.land/pkg/keyscli/root.go b/gno.land/pkg/keyscli/root.go index 19513fc0de6..dc5a4f1f9af 100644 --- a/gno.land/pkg/keyscli/root.go +++ b/gno.land/pkg/keyscli/root.go @@ -17,7 +17,7 @@ func NewRootCmd(io commands.IO, base client.BaseOptions) *commands.Command { cmd := commands.NewCommand( commands.Metadata{ ShortUsage: " [flags] [...]", - LongHelp: "gno.land keychain & client", + LongHelp: "Manages private keys for the node", Options: []ff.Option{ ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(fftoml.Parser), diff --git a/gno.land/pkg/sdk/vm/common_test.go b/gno.land/pkg/sdk/vm/common_test.go index 43a8fe1fbec..6dd8050d6b6 100644 --- a/gno.land/pkg/sdk/vm/common_test.go +++ b/gno.land/pkg/sdk/vm/common_test.go @@ -38,7 +38,6 @@ func _setupTestEnv(cacheStdlibs bool) testEnv { baseCapKey := store.NewStoreKey("baseCapKey") iavlCapKey := store.NewStoreKey("iavlCapKey") - // Mount db store and iavlstore ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(baseCapKey, dbadapter.StoreConstructor, db) ms.MountStoreWithDB(iavlCapKey, iavl.StoreConstructor, db) @@ -47,18 +46,11 @@ func _setupTestEnv(cacheStdlibs bool) testEnv { ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.NewNoopLogger()) acck := authm.NewAccountKeeper(iavlCapKey, std.ProtoBaseAccount) bank := bankm.NewBankKeeper(acck) - vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank, 100_000_000) + stdlibsDir := filepath.Join("..", "..", "..", "..", "gnovm", "stdlibs") + vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank, stdlibsDir, 100_000_000) mcw := ms.MultiCacheWrap() - vmk.Initialize(log.NewNoopLogger(), mcw) - stdlibCtx := vmk.MakeGnoTransactionStore(ctx.WithMultiStore(mcw)) - stdlibsDir := filepath.Join("..", "..", "..", "..", "gnovm", "stdlibs") - if cacheStdlibs { - vmk.LoadStdlibCached(stdlibCtx, stdlibsDir) - } else { - vmk.LoadStdlib(stdlibCtx, stdlibsDir) - } - vmk.CommitGnoTransactionStore(stdlibCtx) + vmk.Initialize(log.NewNoopLogger(), mcw, cacheStdlibs) mcw.MultiWrite() return testEnv{ctx: ctx, vmk: vmk, bank: bank, acck: acck} diff --git a/gno.land/pkg/sdk/vm/errors.go b/gno.land/pkg/sdk/vm/errors.go index c8d6da98970..a0e71e08d14 100644 --- a/gno.land/pkg/sdk/vm/errors.go +++ b/gno.land/pkg/sdk/vm/errors.go @@ -16,7 +16,6 @@ func (abciError) AssertABCIError() {} // NOTE: these are meant to be used in conjunction with pkgs/errors. type ( InvalidPkgPathError struct{ abciError } - PkgExistError struct{ abciError } InvalidStmtError struct{ abciError } InvalidExprError struct{ abciError } UnauthorizedUserError struct{ abciError } @@ -27,7 +26,6 @@ type ( ) func (e InvalidPkgPathError) Error() string { return "invalid package path" } -func (e PkgExistError) Error() string { return "package already exists" } func (e InvalidStmtError) Error() string { return "invalid statement" } func (e InvalidExprError) Error() string { return "invalid expression" } func (e UnauthorizedUserError) Error() string { return "unauthorized user" } @@ -38,10 +36,6 @@ func (e TypeCheckError) Error() string { return bld.String() } -func ErrPkgAlreadyExists(msg string) error { - return errors.Wrap(PkgExistError{}, msg) -} - func ErrUnauthorizedUser(msg string) error { return errors.Wrap(UnauthorizedUserError{}, msg) } diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go index 4171b1cdbc3..66655994bd4 100644 --- a/gno.land/pkg/sdk/vm/gas_test.go +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -3,7 +3,6 @@ package vm import ( "testing" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" bft "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/sdk" @@ -27,9 +26,6 @@ func TestAddPkgDeliverTxInsuffGas(t *testing.T) { simulate := false tx.Fee.GasWanted = 3000 gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - // Has to be set up after gas meter in the context; so the stores are - // correctly wrapped in gas stores. - gctx = vmHandler.vm.MakeGnoTransactionStore(gctx) var res sdk.Result abort := false @@ -66,7 +62,6 @@ func TestAddPkgDeliverTx(t *testing.T) { simulate = false tx.Fee.GasWanted = 500000 gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gctx = vmHandler.vm.MakeGnoTransactionStore(gctx) msgs := tx.GetMsgs() res := vmHandler.Process(gctx, msgs[0]) gasDeliver := gctx.GasMeter().GasConsumed() @@ -88,7 +83,6 @@ func TestAddPkgDeliverTxFailed(t *testing.T) { simulate = false tx.Fee.GasWanted = 500000 gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gctx = vmHandler.vm.MakeGnoTransactionStore(gctx) msgs := tx.GetMsgs() res := vmHandler.Process(gctx, msgs[0]) gasDeliver := gctx.GasMeter().GasConsumed() @@ -108,7 +102,6 @@ func TestAddPkgDeliverTxFailedNoGas(t *testing.T) { simulate = false tx.Fee.GasWanted = 2230 gctx := auth.SetGasMeter(simulate, ctx, tx.Fee.GasWanted) - gctx = vmHandler.vm.MakeGnoTransactionStore(gctx) var res sdk.Result abort := false @@ -135,7 +128,7 @@ func TestAddPkgDeliverTxFailedNoGas(t *testing.T) { res = vmHandler.Process(gctx, msgs[0]) } -// Set up a test env for both a successful and a failed tx. +// Set up a test env for both a successful and a failed tx func setupAddPkg(success bool) (sdk.Context, sdk.Tx, vmHandler) { // setup env := setupTestEnv() @@ -147,7 +140,7 @@ func setupAddPkg(success bool) (sdk.Context, sdk.Tx, vmHandler) { addr := crypto.AddressFromPreimage([]byte("test1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(ugnot.ValueString(10000000))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) // success message var files []*std.MemFile if success { @@ -179,7 +172,7 @@ func Echo() UnknowType { // create messages and a transaction msg := NewMsgAddPackage(addr, pkgPath, files) msgs := []std.Msg{msg} - fee := std.NewFee(500000, std.MustParseCoin(ugnot.ValueString(1))) + fee := std.NewFee(500000, std.MustParseCoin("1ugnot")) tx := std.NewTx(msgs, fee, []std.Signature{}, "") return ctx, tx, vmHandler diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 365473b3e7a..934c4557dd0 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -34,8 +34,8 @@ import ( ) const ( - maxAllocTx = 500_000_000 - maxAllocQuery = 1_500_000_000 // higher limit for queries + maxAllocTx = 500 * 1000 * 1000 + maxAllocQuery = 1500 * 1000 * 1000 // higher limit for queries ) // vm.VMKeeperI defines a module interface that supports Gno @@ -45,20 +45,17 @@ type VMKeeperI interface { Call(ctx sdk.Context, msg MsgCall) (res string, err error) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res string, err error) Run(ctx sdk.Context, msg MsgRun) (res string, err error) - LoadStdlib(ctx sdk.Context, stdlibDir string) - LoadStdlibCached(ctx sdk.Context, stdlibDir string) - MakeGnoTransactionStore(ctx sdk.Context) sdk.Context - CommitGnoTransactionStore(ctx sdk.Context) } var _ VMKeeperI = &VMKeeper{} // VMKeeper holds all package code and store state. type VMKeeper struct { - baseKey store.StoreKey - iavlKey store.StoreKey - acck auth.AccountKeeper - bank bank.BankKeeper + baseKey store.StoreKey + iavlKey store.StoreKey + acck auth.AccountKeeper + bank bank.BankKeeper + stdlibsDir string // cached, the DeliverTx persistent state. gnoStore gno.Store @@ -72,15 +69,17 @@ func NewVMKeeper( iavlKey store.StoreKey, acck auth.AccountKeeper, bank bank.BankKeeper, + stdlibsDir string, maxCycles int64, ) *VMKeeper { // TODO: create an Options struct to avoid too many constructor parameters vmk := &VMKeeper{ - baseKey: baseKey, - iavlKey: iavlKey, - acck: acck, - bank: bank, - maxCycles: maxCycles, + baseKey: baseKey, + iavlKey: iavlKey, + acck: acck, + bank: bank, + stdlibsDir: stdlibsDir, + maxCycles: maxCycles, } return vmk } @@ -88,28 +87,69 @@ func NewVMKeeper( func (vm *VMKeeper) Initialize( logger *slog.Logger, ms store.MultiStore, + cacheStdlibLoad bool, ) { if vm.gnoStore != nil { panic("should not happen") } - baseStore := ms.GetStore(vm.baseKey) - iavlStore := ms.GetStore(vm.iavlKey) + baseSDKStore := ms.GetStore(vm.baseKey) + iavlSDKStore := ms.GetStore(vm.iavlKey) + if cacheStdlibLoad { + // Testing case (using the cache speeds up starting many nodes) + vm.gnoStore = cachedStdlibLoad(vm.stdlibsDir, baseSDKStore, iavlSDKStore) + } else { + // On-chain case + vm.gnoStore = uncachedPackageLoad(logger, vm.stdlibsDir, baseSDKStore, iavlSDKStore) + } +} + +func uncachedPackageLoad( + logger *slog.Logger, + stdlibsDir string, + baseStore, iavlStore store.Store, +) gno.Store { alloc := gno.NewAllocator(maxAllocTx) - vm.gnoStore = gno.NewStore(alloc, baseStore, iavlStore) - vm.gnoStore.SetNativeStore(stdlibs.NativeStore) + gnoStore := gno.NewStore(alloc, baseStore, iavlStore) + gnoStore.SetNativeStore(stdlibs.NativeStore) + if gnoStore.NumMemPackages() == 0 { + // No packages in the store; set up the stdlibs. + start := time.Now() - if vm.gnoStore.NumMemPackages() > 0 { + loadStdlib(stdlibsDir, gnoStore) + + // XXX Quick and dirty to make this function work on non-validator nodes + iter := iavlStore.Iterator(nil, nil) + for ; iter.Valid(); iter.Next() { + baseStore.Set(append(iavlBackupPrefix, iter.Key()...), iter.Value()) + } + iter.Close() + + logger.Debug("Standard libraries initialized", + "elapsed", time.Since(start)) + } else { // for now, all mem packages must be re-run after reboot. // TODO remove this, and generally solve for in-mem garbage collection // and memory management across many objects/types/nodes/packages. start := time.Now() + // XXX Quick and dirty to make this function work on non-validator nodes + if isStoreEmpty(iavlStore) { + iter := baseStore.Iterator(iavlBackupPrefix, nil) + for ; iter.Valid(); iter.Next() { + if !bytes.HasPrefix(iter.Key(), iavlBackupPrefix) { + break + } + iavlStore.Set(iter.Key()[len(iavlBackupPrefix):], iter.Value()) + } + iter.Close() + } + m2 := gno.NewMachineWithOptions( gno.MachineOptions{ PkgPath: "", Output: os.Stdout, // XXX - Store: vm.gnoStore, + Store: gnoStore, }) defer m2.Release() gno.DisableDebug() @@ -119,52 +159,57 @@ func (vm *VMKeeper) Initialize( logger.Debug("GnoVM packages preprocessed", "elapsed", time.Since(start)) } + return gnoStore } -type stdlibCache struct { - dir string - base store.Store - iavl store.Store - gno gno.Store -} +var iavlBackupPrefix = []byte("init_iavl_backup:") -var ( - cachedStdlibOnce sync.Once - cachedStdlib stdlibCache -) +func isStoreEmpty(st store.Store) bool { + iter := st.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + return false + } + return true +} -// LoadStdlib loads the Gno standard library into the given store. -func (vm *VMKeeper) LoadStdlibCached(ctx sdk.Context, stdlibDir string) { +func cachedStdlibLoad(stdlibsDir string, baseStore, iavlStore store.Store) gno.Store { cachedStdlibOnce.Do(func() { - cachedStdlib = stdlibCache{ - dir: stdlibDir, - base: dbadapter.StoreConstructor(memdb.NewMemDB(), types.StoreOptions{}), - iavl: dbadapter.StoreConstructor(memdb.NewMemDB(), types.StoreOptions{}), - } - - gs := gno.NewStore(nil, cachedStdlib.base, cachedStdlib.iavl) - gs.SetNativeStore(stdlibs.NativeStore) - loadStdlib(gs, stdlibDir) - cachedStdlib.gno = gs + cachedStdlibBase = memdb.NewMemDB() + cachedStdlibIavl = memdb.NewMemDB() + + cachedGnoStore = gno.NewStore(nil, + dbadapter.StoreConstructor(cachedStdlibBase, types.StoreOptions{}), + dbadapter.StoreConstructor(cachedStdlibIavl, types.StoreOptions{})) + cachedGnoStore.SetNativeStore(stdlibs.NativeStore) + loadStdlib(stdlibsDir, cachedGnoStore) }) - if stdlibDir != cachedStdlib.dir { - panic(fmt.Sprintf( - "cannot load cached stdlib: cached stdlib is in dir %q; wanted to load stdlib in dir %q", - cachedStdlib.dir, stdlibDir)) + itr := cachedStdlibBase.Iterator(nil, nil) + for ; itr.Valid(); itr.Next() { + baseStore.Set(itr.Key(), itr.Value()) } - gs := vm.getGnoTransactionStore(ctx) - gno.CopyFromCachedStore(gs, cachedStdlib.gno, cachedStdlib.base, cachedStdlib.iavl) -} + itr = cachedStdlibIavl.Iterator(nil, nil) + for ; itr.Valid(); itr.Next() { + iavlStore.Set(itr.Key(), itr.Value()) + } -// LoadStdlib loads the Gno standard library into the given store. -func (vm *VMKeeper) LoadStdlib(ctx sdk.Context, stdlibDir string) { - gs := vm.getGnoTransactionStore(ctx) - loadStdlib(gs, stdlibDir) + alloc := gno.NewAllocator(maxAllocTx) + gs := gno.NewStore(alloc, baseStore, iavlStore) + gs.SetNativeStore(stdlibs.NativeStore) + gno.CopyCachesFromStore(gs, cachedGnoStore) + return gs } -func loadStdlib(store gno.Store, stdlibDir string) { +var ( + cachedStdlibOnce sync.Once + cachedStdlibBase *memdb.MemDB + cachedStdlibIavl *memdb.MemDB + cachedGnoStore gno.Store +) + +func loadStdlib(stdlibsDir string, store gno.Store) { stdlibInitList := stdlibs.InitOrder() for _, lib := range stdlibInitList { if lib == "testing" { @@ -172,12 +217,12 @@ func loadStdlib(store gno.Store, stdlibDir string) { // like fmt and encoding/json continue } - loadStdlibPackage(lib, stdlibDir, store) + loadStdlibPackage(lib, stdlibsDir, store) } } -func loadStdlibPackage(pkgPath, stdlibDir string, store gno.Store) { - stdlibPath := filepath.Join(stdlibDir, pkgPath) +func loadStdlibPackage(pkgPath, stdlibsDir string, store gno.Store) { + stdlibPath := filepath.Join(stdlibsDir, pkgPath) if !osm.DirExists(stdlibPath) { // does not exist. panic(fmt.Sprintf("failed loading stdlib %q: does not exist", pkgPath)) @@ -198,29 +243,40 @@ func loadStdlibPackage(pkgPath, stdlibDir string, store gno.Store) { m.RunMemPackage(memPkg, true) } -type gnoStoreContextKeyType struct{} - -var gnoStoreContextKey gnoStoreContextKeyType - -func (vm *VMKeeper) newGnoTransactionStore(ctx sdk.Context) gno.TransactionStore { - base := ctx.Store(vm.baseKey) - iavl := ctx.Store(vm.iavlKey) - - return vm.gnoStore.BeginTransaction(base, iavl) -} - -func (vm *VMKeeper) MakeGnoTransactionStore(ctx sdk.Context) sdk.Context { - return ctx.WithValue(gnoStoreContextKey, vm.newGnoTransactionStore(ctx)) -} - -func (vm *VMKeeper) CommitGnoTransactionStore(ctx sdk.Context) { - vm.getGnoTransactionStore(ctx).Write() -} - -func (vm *VMKeeper) getGnoTransactionStore(ctx sdk.Context) gno.TransactionStore { - txStore := ctx.Value(gnoStoreContextKey).(gno.TransactionStore) - txStore.ClearObjectCache() - return txStore +func (vm *VMKeeper) getGnoStore(ctx sdk.Context) gno.Store { + // construct main store if nil. + if vm.gnoStore == nil { + panic("VMKeeper must first be initialized") + } + switch ctx.Mode() { + case sdk.RunTxModeDeliver: + // swap sdk store of existing store. + // this is needed due to e.g. gas wrappers. + baseSDKStore := ctx.Store(vm.baseKey) + iavlSDKStore := ctx.Store(vm.iavlKey) + vm.gnoStore.SwapStores(baseSDKStore, iavlSDKStore) + // clear object cache for every transaction. + // NOTE: this is inefficient, but simple. + // in the future, replace with more advanced caching strategy. + vm.gnoStore.ClearObjectCache() + return vm.gnoStore + case sdk.RunTxModeCheck: + // For query??? XXX Why not RunTxModeQuery? + simStore := vm.gnoStore.Fork() + baseSDKStore := ctx.Store(vm.baseKey) + iavlSDKStore := ctx.Store(vm.iavlKey) + simStore.SwapStores(baseSDKStore, iavlSDKStore) + return simStore + case sdk.RunTxModeSimulate: + // always make a new store for simulate for isolation. + simStore := vm.gnoStore.Fork() + baseSDKStore := ctx.Store(vm.baseKey) + iavlSDKStore := ctx.Store(vm.iavlKey) + simStore.SwapStores(baseSDKStore, iavlSDKStore) + return simStore + default: + panic("should not happen") + } } // Namespace can be either a user or crypto address. @@ -230,7 +286,7 @@ var reNamespace = regexp.MustCompile(`^gno.land/(?:r|p)/([\.~_a-zA-Z0-9]+)`) func (vm *VMKeeper) checkNamespacePermission(ctx sdk.Context, creator crypto.Address, pkgPath string) error { const sysUsersPkg = "gno.land/r/sys/users" - store := vm.getGnoTransactionStore(ctx) + store := vm.getGnoStore(ctx) match := reNamespace.FindStringSubmatch(pkgPath) switch len(match) { @@ -311,7 +367,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { pkgPath := msg.Package.Path memPkg := msg.Package deposit := msg.Deposit - gnostore := vm.getGnoTransactionStore(ctx) + gnostore := vm.getGnoStore(ctx) // Validate arguments. if creator.IsZero() { @@ -325,7 +381,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { return ErrInvalidPkgPath(err.Error()) } if pv := gnostore.GetPackage(pkgPath, false); pv != nil { - return ErrPkgAlreadyExists("package already exists: " + pkgPath) + return ErrInvalidPkgPath("package already exists: " + pkgPath) } if gno.ReGnoRunPath.MatchString(pkgPath) { return ErrInvalidPkgPath("reserved package name: " + pkgPath) @@ -408,7 +464,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { pkgPath := msg.PkgPath // to import fnc := msg.Func - gnostore := vm.getGnoTransactionStore(ctx) + gnostore := vm.getGnoStore(ctx) // Get the package and function type. pv := gnostore.GetPackage(pkgPath, false) pl := gno.PackageNodeLocation(pkgPath) @@ -481,15 +537,12 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { m.SetActivePackage(mpv) defer func() { if r := recover(); r != nil { - switch r := r.(type) { + switch r.(type) { case store.OutOfGasException: // panic in consumeGas() panic(r) - case gno.UnhandledPanicError: - err = errors.Wrap(fmt.Errorf("%v", r.Error()), "VM call panic: %s\nStacktrace: %s\n", - r.Error(), m.ExceptionsStacktrace()) default: - err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\nMachine State:%s\nStacktrace: %s\n", - r, m.String(), m.Stacktrace().String()) + err = errors.Wrap(fmt.Errorf("%v", r), "VM call panic: %v\n%s\n", + r, m.String()) return } } @@ -522,7 +575,7 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { caller := msg.Caller pkgAddr := caller - gnostore := vm.getGnoTransactionStore(ctx) + gnostore := vm.getGnoStore(ctx) send := msg.Send memPkg := msg.Package @@ -636,7 +689,7 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { // QueryFuncs returns public facing function signatures. func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionSignatures, err error) { - store := vm.newGnoTransactionStore(ctx) // throwaway (never committed) + store := vm.getGnoStore(ctx) // Ensure pkgPath is realm. if !gno.IsRealmPath(pkgPath) { err = ErrInvalidPkgPath(fmt.Sprintf( @@ -699,7 +752,7 @@ func (vm *VMKeeper) QueryFuncs(ctx sdk.Context, pkgPath string) (fsigs FunctionS // TODO: then, rename to "Eval". func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res string, err error) { alloc := gno.NewAllocator(maxAllocQuery) - gnostore := vm.newGnoTransactionStore(ctx) // throwaway (never committed) + gnostore := vm.getGnoStore(ctx) pkgAddr := gno.DerivePkgAddr(pkgPath) // Get Package. pv := gnostore.GetPackage(pkgPath, false) @@ -766,7 +819,7 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res // TODO: then, rename to "EvalString". func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string) (res string, err error) { alloc := gno.NewAllocator(maxAllocQuery) - gnostore := vm.newGnoTransactionStore(ctx) // throwaway (never committed) + gnostore := vm.getGnoStore(ctx) pkgAddr := gno.DerivePkgAddr(pkgPath) // Get Package. pv := gnostore.GetPackage(pkgPath, false) @@ -827,7 +880,7 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string } func (vm *VMKeeper) QueryFile(ctx sdk.Context, filepath string) (res string, err error) { - store := vm.newGnoTransactionStore(ctx) // throwaway (never committed) + store := vm.getGnoStore(ctx) dirpath, filename := std.SplitFilepath(filepath) if filename != "" { memFile := store.GetMemFile(dirpath, filename) diff --git a/gno.land/pkg/sdk/vm/keeper_test.go b/gno.land/pkg/sdk/vm/keeper_test.go index 9257da2ddaf..a86ca5e4a97 100644 --- a/gno.land/pkg/sdk/vm/keeper_test.go +++ b/gno.land/pkg/sdk/vm/keeper_test.go @@ -9,30 +9,22 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" - "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/tm2/pkg/crypto" - "github.com/gnolang/gno/tm2/pkg/db/memdb" - "github.com/gnolang/gno/tm2/pkg/log" "github.com/gnolang/gno/tm2/pkg/std" - "github.com/gnolang/gno/tm2/pkg/store/dbadapter" - "github.com/gnolang/gno/tm2/pkg/store/types" ) -var coinsString = ugnot.ValueString(10000000) - func TestVMKeeperAddPackage(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx + vmk := env.vmk // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) // Create test package. files := []*std.MemFile{ @@ -44,20 +36,20 @@ func Echo() string {return "hello world"}`, } pkgPath := "gno.land/r/test" msg1 := NewMsgAddPackage(addr, pkgPath, files) - assert.Nil(t, env.vmk.getGnoTransactionStore(ctx).GetPackage(pkgPath, false)) + assert.Nil(t, env.vmk.gnoStore.GetPackage(pkgPath, false)) err := env.vmk.AddPackage(ctx, msg1) assert.NoError(t, err) - assert.NotNil(t, env.vmk.getGnoTransactionStore(ctx).GetPackage(pkgPath, false)) + assert.NotNil(t, env.vmk.gnoStore.GetPackage(pkgPath, false)) err = env.vmk.AddPackage(ctx, msg1) assert.Error(t, err) - assert.True(t, errors.Is(err, PkgExistError{})) + assert.True(t, errors.Is(err, InvalidPkgPathError{})) // added package is formatted - store := env.vmk.getGnoTransactionStore(ctx) + store := vmk.getGnoStore(ctx) memFile := store.GetMemFile("gno.land/r/test", "test.gno") assert.NotNil(t, memFile) expected := `package test @@ -70,14 +62,14 @@ func Echo() string { return "hello world" } // Sending total send amount succeeds. func TestVMKeeperOrigSend1(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) // Create test package. files := []*std.MemFile{ @@ -104,7 +96,7 @@ func Echo(msg string) string { assert.NoError(t, err) // Run Echo function. - coins := std.MustParseCoins(coinsString) + coins := std.MustParseCoins("10000000ugnot") msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) res, err := env.vmk.Call(ctx, msg2) assert.NoError(t, err) @@ -115,14 +107,14 @@ func Echo(msg string) string { // Sending too much fails func TestVMKeeperOrigSend2(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) // Create test package. files := []*std.MemFile{ @@ -157,7 +149,7 @@ func GetAdmin() string { assert.NoError(t, err) // Run Echo function. - coins := std.MustParseCoins(ugnot.ValueString(11000000)) + coins := std.MustParseCoins("11000000ugnot") msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) res, err := env.vmk.Call(ctx, msg2) assert.Error(t, err) @@ -169,14 +161,14 @@ func GetAdmin() string { // Sending more than tx send fails. func TestVMKeeperOrigSend3(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) // Create test package. files := []*std.MemFile{ @@ -203,7 +195,7 @@ func Echo(msg string) string { assert.NoError(t, err) // Run Echo function. - coins := std.MustParseCoins(ugnot.ValueString(9000000)) + coins := std.MustParseCoins("9000000ugnot") msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) // XXX change this into an error and make sure error message is descriptive. _, err = env.vmk.Call(ctx, msg2) @@ -213,14 +205,14 @@ func Echo(msg string) string { // Sending realm package coins succeeds. func TestVMKeeperRealmSend1(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) // Create test package. files := []*std.MemFile{ @@ -247,7 +239,7 @@ func Echo(msg string) string { assert.NoError(t, err) // Run Echo function. - coins := std.MustParseCoins(coinsString) + coins := std.MustParseCoins("10000000ugnot") msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) res, err := env.vmk.Call(ctx, msg2) assert.NoError(t, err) @@ -257,14 +249,14 @@ func Echo(msg string) string { // Sending too much realm package coins fails. func TestVMKeeperRealmSend2(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) // Create test package. files := []*std.MemFile{ @@ -291,7 +283,7 @@ func Echo(msg string) string { assert.NoError(t, err) // Run Echo function. - coins := std.MustParseCoins(ugnot.ValueString(9000000)) + coins := std.MustParseCoins("9000000ugnot") msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world"}) // XXX change this into an error and make sure error message is descriptive. _, err = env.vmk.Call(ctx, msg2) @@ -301,14 +293,14 @@ func Echo(msg string) string { // Assign admin as OrigCaller on deploying the package. func TestVMKeeperOrigCallerInit(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) // Create test package. files := []*std.MemFile{ @@ -355,7 +347,7 @@ func GetAdmin() string { // Call Run without imports, without variables. func TestVMKeeperRunSimple(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) @@ -394,7 +386,7 @@ func TestVMKeeperRunImportStdlibsColdStdlibLoad(t *testing.T) { func testVMKeeperRunImportStdlibs(t *testing.T, env testEnv) { t.Helper() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) @@ -424,14 +416,14 @@ func main() { func TestNumberOfArgsError(t *testing.T) { env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + ctx := env.ctx // Give "addr1" some gnots. addr := crypto.AddressFromPreimage([]byte("addr1")) acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + env.bank.SetCoins(ctx, addr, std.MustParseCoins("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) // Create test package. files := []*std.MemFile{ @@ -450,7 +442,7 @@ func Echo(msg string) string { assert.NoError(t, err) // Call Echo function with wrong number of arguments - coins := std.MustParseCoins(ugnot.ValueString(1)) + coins := std.MustParseCoins("1ugnot") msg2 := NewMsgCall(addr, coins, pkgPath, "Echo", []string{"hello world", "extra arg"}) assert.PanicsWithValue( t, @@ -460,59 +452,3 @@ func Echo(msg string) string { }, ) } - -func TestVMKeeperReinitialize(t *testing.T) { - env := setupTestEnv() - ctx := env.vmk.MakeGnoTransactionStore(env.ctx) - - // Give "addr1" some gnots. - addr := crypto.AddressFromPreimage([]byte("addr1")) - acc := env.acck.NewAccountWithAddress(ctx, addr) - env.acck.SetAccount(ctx, acc) - env.bank.SetCoins(ctx, addr, std.MustParseCoins(coinsString)) - assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) - - // Create test package. - files := []*std.MemFile{ - {"init.gno", ` -package test - -func Echo(msg string) string { - return "echo:"+msg -}`}, - } - pkgPath := "gno.land/r/test" - msg1 := NewMsgAddPackage(addr, pkgPath, files) - err := env.vmk.AddPackage(ctx, msg1) - require.NoError(t, err) - - // Run Echo function. - msg2 := NewMsgCall(addr, nil, pkgPath, "Echo", []string{"hello world"}) - res, err := env.vmk.Call(ctx, msg2) - require.NoError(t, err) - assert.Equal(t, `("echo:hello world" string)`+"\n\n", res) - - // Clear out gnovm and reinitialize. - env.vmk.gnoStore = nil - mcw := env.ctx.MultiStore().MultiCacheWrap() - env.vmk.Initialize(log.NewNoopLogger(), mcw) - mcw.MultiWrite() - - // Run echo again, and it should still work. - res, err = env.vmk.Call(ctx, msg2) - require.NoError(t, err) - assert.Equal(t, `("echo:hello world" string)`+"\n\n", res) -} - -func Test_loadStdlibPackage(t *testing.T) { - mdb := memdb.NewMemDB() - cs := dbadapter.StoreConstructor(mdb, types.StoreOptions{}) - - gs := gnolang.NewStore(nil, cs, cs) - assert.PanicsWithValue(t, `failed loading stdlib "notfound": does not exist`, func() { - loadStdlibPackage("notfound", "./testdata", gs) - }) - assert.PanicsWithValue(t, `failed loading stdlib "emptystdlib": not a valid MemPackage`, func() { - loadStdlibPackage("emptystdlib", "./testdata", gs) - }) -} diff --git a/gno.land/pkg/sdk/vm/package.go b/gno.land/pkg/sdk/vm/package.go index 30dd116d4e3..e62a7b53928 100644 --- a/gno.land/pkg/sdk/vm/package.go +++ b/gno.land/pkg/sdk/vm/package.go @@ -18,7 +18,6 @@ var Package = amino.RegisterPackage(amino.NewPackage( // errors InvalidPkgPathError{}, "InvalidPkgPathError", - PkgExistError{}, "PkgExistError", InvalidStmtError{}, "InvalidStmtError", InvalidExprError{}, "InvalidExprError", TypeCheckError{}, "TypeCheckError", diff --git a/gno.land/pkg/sdk/vm/testdata/emptystdlib/README b/gno.land/pkg/sdk/vm/testdata/emptystdlib/README deleted file mode 100644 index e4454ed67f8..00000000000 --- a/gno.land/pkg/sdk/vm/testdata/emptystdlib/README +++ /dev/null @@ -1 +0,0 @@ -see keeper_test.go diff --git a/gno.land/pkg/sdk/vm/vm.proto b/gno.land/pkg/sdk/vm/vm.proto index e02226e1ae4..aa0be4f6e14 100644 --- a/gno.land/pkg/sdk/vm/vm.proto +++ b/gno.land/pkg/sdk/vm/vm.proto @@ -30,9 +30,6 @@ message m_addpkg { message InvalidPkgPathError { } -message PkgExistError { -} - message InvalidStmtError { } diff --git a/gnovm/cmd/gno/run.go b/gnovm/cmd/gno/run.go index cfbfe995a46..39306d59cb0 100644 --- a/gnovm/cmd/gno/run.go +++ b/gnovm/cmd/gno/run.go @@ -188,14 +188,8 @@ func listNonTestFiles(dir string) ([]string, error) { func runExpr(m *gno.Machine, expr string) { defer func() { if r := recover(); r != nil { - switch r := r.(type) { - case gno.UnhandledPanicError: - fmt.Printf("panic running expression %s: %v\nStacktrace: %s\n", - expr, r.Error(), m.ExceptionsStacktrace()) - default: - fmt.Printf("panic running expression %s: %v\nMachine State:%s\nStacktrace: %s\n", - expr, r, m.String(), m.Stacktrace().String()) - } + fmt.Printf("panic running expression %s: %v\n%s\n", + expr, r, m.String()) panic(r) } }() diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index df042038e43..6fef5eda834 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -223,12 +223,7 @@ func (alloc *Allocator) NewSlice(base Value, offset, length, maxcap int) *SliceV } } -// NewSliceFromList allocates a new slice with the underlying array value -// populated from `list`. This should not be called from areas in the codebase -// that are doing allocations with potentially large user provided values, e.g. -// `make()` and `append()`. Using `Alloc.NewListArray` can be used is most cases -// to allocate the space for the `TypedValue` list before doing the allocation -// in the go runtime -- see the `make()` code in uverse.go. +// NOTE: also allocates the underlying array from list. func (alloc *Allocator) NewSliceFromList(list []TypedValue) *SliceValue { alloc.AllocateSlice() alloc.AllocateListArray(int64(cap(list))) @@ -243,9 +238,7 @@ func (alloc *Allocator) NewSliceFromList(list []TypedValue) *SliceValue { } } -// NewSliceFromData allocates a new slice with the underlying data array -// value populated from `data`. See the doc for `NewSliceFromList` for -// correct usage notes. +// NOTE: also allocates the underlying array from data. func (alloc *Allocator) NewSliceFromData(data []byte) *SliceValue { alloc.AllocateSlice() alloc.AllocateDataArray(int64(cap(data))) diff --git a/gnovm/pkg/gnolang/debugger_test.go b/gnovm/pkg/gnolang/debugger_test.go index fe059ba9f56..10d7c5ce250 100644 --- a/gnovm/pkg/gnolang/debugger_test.go +++ b/gnovm/pkg/gnolang/debugger_test.go @@ -24,7 +24,7 @@ type writeNopCloser struct{ io.Writer } func (writeNopCloser) Close() error { return nil } // TODO (Marc): move evalTest to gnovm/tests package and remove code duplicates -func evalTest(debugAddr, in, file string) (out, err, stacktrace string) { +func evalTest(debugAddr, in, file string) (out, err string) { bout := bytes.NewBufferString("") berr := bytes.NewBufferString("") stdin := bytes.NewBufferString(in) @@ -40,7 +40,7 @@ func evalTest(debugAddr, in, file string) (out, err, stacktrace string) { if r := recover(); r != nil { err = fmt.Sprintf("%v", r) } - out = strings.TrimSuffix(out, "\n") + out = strings.TrimSpace(out) err = strings.TrimSpace(strings.ReplaceAll(err, "../../tests/files/", "files/")) }() @@ -58,18 +58,6 @@ func evalTest(debugAddr, in, file string) (out, err, stacktrace string) { }) defer m.Release() - defer func() { - if r := recover(); r != nil { - switch r.(type) { - case gnolang.UnhandledPanicError: - stacktrace = m.ExceptionsStacktrace() - default: - stacktrace = m.Stacktrace().String() - } - stacktrace = strings.TrimSpace(strings.ReplaceAll(stacktrace, "../../tests/files/", "files/")) - panic(r) - } - }() if debugAddr != "" { if e := m.Debugger.Serve(debugAddr); e != nil { @@ -81,7 +69,7 @@ func evalTest(debugAddr, in, file string) (out, err, stacktrace string) { m.RunFiles(f) ex, _ := gnolang.ParseExpr("main()") m.Eval(ex) - out, err, stacktrace = bout.String(), berr.String(), m.ExceptionsStacktrace() + out, err = bout.String(), berr.String() return } @@ -90,7 +78,7 @@ func runDebugTest(t *testing.T, targetPath string, tests []dtest) { for _, test := range tests { t.Run("", func(t *testing.T) { - out, err, _ := evalTest("", test.in, targetPath) + out, err := evalTest("", test.in, targetPath) t.Log("in:", test.in, "out:", out, "err:", err) if !strings.Contains(out, test.out) { t.Errorf("unexpected output\nwant\"%s\"\n got \"%s\"", test.out, out) @@ -206,7 +194,7 @@ func TestRemoteDebug(t *testing.T) { } func TestRemoteError(t *testing.T) { - _, err, _ := evalTest(":xxx", "", debugTarget) + _, err := evalTest(":xxx", "", debugTarget) t.Log("err:", err) if !strings.Contains(err, "tcp/xxx: unknown port") && !strings.Contains(err, "tcp/xxx: nodename nor servname provided, or not known") { diff --git a/gnovm/pkg/gnolang/eval_test.go b/gnovm/pkg/gnolang/eval_test.go index ba93dd00396..fdd8e0204d1 100644 --- a/gnovm/pkg/gnolang/eval_test.go +++ b/gnovm/pkg/gnolang/eval_test.go @@ -1,121 +1,62 @@ package gnolang_test import ( - "io/fs" "os" - "path/filepath" - "regexp" - "sort" + "path" "strings" "testing" ) func TestEvalFiles(t *testing.T) { dir := "../../tests/files" - err := fs.WalkDir(os.DirFS(dir), ".", func(path string, de fs.DirEntry, err error) error { - switch { - case err != nil: - return err - case path == "extern": - return fs.SkipDir - case de.IsDir(): - return nil - } - - fullPath := filepath.Join(dir, path) - wantOut, wantErr, wantStacktrace, ok := testData(fullPath) + files, err := os.ReadDir(dir) + if err != nil { + t.Fatal(err) + } + for _, f := range files { + wantOut, wantErr, ok := testData(dir, f) if !ok { - return nil + continue } - - t.Run(path, func(t *testing.T) { - out, err, stacktrace := evalTest("", "", fullPath) + t.Run(f.Name(), func(t *testing.T) { + out, err := evalTest("", "", path.Join(dir, f.Name())) if wantErr != "" && !strings.Contains(err, wantErr) || wantErr == "" && err != "" { t.Fatalf("unexpected error\nWant: %s\n Got: %s", wantErr, err) } - - if wantStacktrace != "" && !strings.Contains(stacktrace, wantStacktrace) { - t.Fatalf("unexpected stacktrace\nWant: %s\n Got: %s", wantStacktrace, stacktrace) - } if wantOut != "" && out != wantOut { t.Fatalf("unexpected output\nWant: %s\n Got: %s", wantOut, out) } }) - - return nil - }) - if err != nil { - t.Fatal(err) } } // testData returns the expected output and error string, and true if entry is valid. -func testData(name string) (testOut, testErr, testStacktrace string, ok bool) { +func testData(dir string, f os.DirEntry) (testOut, testErr string, ok bool) { + if f.IsDir() { + return "", "", false + } + name := path.Join(dir, f.Name()) if !strings.HasSuffix(name, ".gno") || strings.HasSuffix(name, "_long.gno") { - return + return "", "", false } buf, err := os.ReadFile(name) if err != nil { - return + return "", "", false } str := string(buf) if strings.Contains(str, "// PKGPATH:") { - return + return "", "", false } - res := commentFrom(str, []string{ - "// Output:", - "// Error:", - "// Stacktrace:", - }) - - return res[0], res[1], res[2], true + return commentFrom(str, "\n// Output:"), commentFrom(str, "\n// Error:"), true } -type directive struct { - delim string - res string - index int -} - -// (?m) makes ^ and $ match start/end of string -var reCommentPrefix = regexp.MustCompile("(?m)^//(?: |$)") - -// commentFrom returns the comments from s that are between the delimiters. -func commentFrom(s string, delims []string) []string { - directives := make([]directive, len(delims)) - directivesFound := make([]*directive, 0, len(delims)) - - for i, delim := range delims { - // must find delim isolated on one line - delim = "\n" + delim + "\n" - index := strings.Index(s, delim) - directives[i] = directive{delim: delim, index: index} - if index >= 0 { - directivesFound = append(directivesFound, &directives[i]) - } - } - sort.Slice(directivesFound, func(i, j int) bool { - return directivesFound[i].index < directivesFound[j].index - }) - - for i := range directivesFound { - next := len(s) - if i != len(directivesFound)-1 { - next = directivesFound[i+1].index - } - - parsed := reCommentPrefix.ReplaceAllLiteralString( - s[directivesFound[i].index+len(directivesFound[i].delim):next], - "") - directivesFound[i].res = strings.TrimSuffix(parsed, "\n") +// commentFrom returns the content from a trailing comment block in s starting with delim. +func commentFrom(s, delim string) string { + index := strings.Index(s, delim) + if index < 0 { + return "" } - - res := make([]string, len(directives)) - for i, d := range directives { - res[i] = d.res - } - - return res + return strings.TrimSpace(strings.ReplaceAll(s[index+len(delim):], "\n// ", "\n")) } diff --git a/gnovm/pkg/gnolang/frame.go b/gnovm/pkg/gnolang/frame.go index 2ac1027eb32..c808fc111b0 100644 --- a/gnovm/pkg/gnolang/frame.go +++ b/gnovm/pkg/gnolang/frame.go @@ -2,11 +2,8 @@ package gnolang import ( "fmt" - "strings" ) -const maxStacktraceSize = 128 - //---------------------------------------- // (runtime) Frame @@ -67,10 +64,6 @@ func (fr Frame) String() string { } } -func (fr *Frame) IsCall() bool { - return fr.Func != nil || fr.GoFunc != nil -} - func (fr *Frame) PushDefer(dfr Defer) { fr.Defers = append(fr.Defers, dfr) } @@ -99,119 +92,3 @@ type Defer struct { // a panic occurs and is decremented each time a panic is recovered. PanicScope uint } - -type StacktraceCall struct { - Stmt Stmt - Frame *Frame -} -type Stacktrace struct { - Calls []StacktraceCall - NumFramesElided int -} - -func (s Stacktrace) String() string { - var builder strings.Builder - - for i := 0; i < len(s.Calls); i++ { - if s.NumFramesElided > 0 && i == maxStacktraceSize/2 { - fmt.Fprintf(&builder, "...%d frame(s) elided...\n", s.NumFramesElided) - } - - call := s.Calls[i] - cx := call.Frame.Source.(*CallExpr) - switch { - case call.Frame.Func != nil && call.Frame.Func.IsNative(): - fmt.Fprintf(&builder, "%s\n", toExprTrace(cx)) - fmt.Fprintf(&builder, " gonative:%s.%s\n", call.Frame.Func.NativePkg, call.Frame.Func.NativeName) - case call.Frame.Func != nil: - fmt.Fprintf(&builder, "%s\n", toExprTrace(cx)) - fmt.Fprintf(&builder, " %s/%s:%d\n", call.Frame.Func.PkgPath, call.Frame.Func.FileName, call.Stmt.GetLine()) - case call.Frame.GoFunc != nil: - fmt.Fprintf(&builder, "%s\n", toExprTrace(cx)) - fmt.Fprintf(&builder, " gofunction:%s\n", call.Frame.GoFunc.Value.Type()) - default: - panic("StacktraceCall has a non-call Frame") - } - } - return builder.String() -} - -func toExprTrace(ex Expr) string { - switch ex := ex.(type) { - case *CallExpr: - s := make([]string, len(ex.Args)) - for i, arg := range ex.Args { - s[i] = toExprTrace(arg) - } - return fmt.Sprintf("%s(%s)", toExprTrace(ex.Func), strings.Join(s, ",")) - case *BinaryExpr: - return fmt.Sprintf("%s %s %s", toExprTrace(ex.Left), ex.Op.TokenString(), toExprTrace(ex.Right)) - case *UnaryExpr: - return fmt.Sprintf("%s%s", ex.Op.TokenString(), toExprTrace(ex.X)) - case *SelectorExpr: - return fmt.Sprintf("%s.%s", toExprTrace(ex.X), ex.Sel) - case *IndexExpr: - return fmt.Sprintf("%s[%s]", toExprTrace(ex.X), toExprTrace(ex.Index)) - case *StarExpr: - return fmt.Sprintf("*%s", toExprTrace(ex.X)) - case *RefExpr: - return fmt.Sprintf("&%s", toExprTrace(ex.X)) - case *CompositeLitExpr: - lenEl := len(ex.Elts) - if ex.Type == nil { - return fmt.Sprintf("", lenEl) - } - - return fmt.Sprintf("%s", toExprTrace(ex.Type), lenEl) - case *FuncLitExpr: - return fmt.Sprintf("%s{ ... }", toExprTrace(&ex.Type)) - case *TypeAssertExpr: - return fmt.Sprintf("%s.(%s)", toExprTrace(ex.X), toExprTrace(ex.Type)) - case *ConstExpr: - return toConstExpTrace(ex) - case *NameExpr, *BasicLitExpr, *SliceExpr: - return ex.String() - } - - return ex.String() -} - -func toConstExpTrace(cte *ConstExpr) string { - tv := cte.TypedValue - - switch bt := baseOf(tv.T).(type) { - case PrimitiveType: - switch bt { - case UntypedBoolType, BoolType: - return fmt.Sprintf("%t", tv.GetBool()) - case UntypedStringType, StringType: - return tv.GetString() - case IntType: - return fmt.Sprintf("%d", tv.GetInt()) - case Int8Type: - return fmt.Sprintf("%d", tv.GetInt8()) - case Int16Type: - return fmt.Sprintf("%d", tv.GetInt16()) - case UntypedRuneType, Int32Type: - return fmt.Sprintf("%d", tv.GetInt32()) - case Int64Type: - return fmt.Sprintf("%d", tv.GetInt64()) - case UintType: - return fmt.Sprintf("%d", tv.GetUint()) - case Uint8Type: - return fmt.Sprintf("%d", tv.GetUint8()) - case Uint16Type: - return fmt.Sprintf("%d", tv.GetUint16()) - case Uint32Type: - return fmt.Sprintf("%d", tv.GetUint32()) - case Uint64Type: - return fmt.Sprintf("%d", tv.GetUint64()) - case Float32Type: - return fmt.Sprintf("%v", tv.GetFloat32()) - case Float64Type: - return fmt.Sprintf("%v", tv.GetFloat64()) - } - } - - return tv.T.String() -} diff --git a/gnovm/pkg/gnolang/gno_test.go b/gnovm/pkg/gnolang/gno_test.go index 1f83303023c..54d808faefc 100644 --- a/gnovm/pkg/gnolang/gno_test.go +++ b/gnovm/pkg/gnolang/gno_test.go @@ -179,7 +179,7 @@ func BenchmarkIfStatement(b *testing.B) { func main() { for i:=0; i<10000; i++ { if i > 10 { - + } } }` @@ -356,7 +356,6 @@ func BenchmarkPreprocess(b *testing.B) { Inc("i"), ), )) - pn := NewPackageNode("hey", "gno.land/p/hey", nil) copies := make([]*FuncDecl, b.N) for i := 0; i < b.N; i++ { copies[i] = main.Copy().(*FuncDecl) @@ -364,8 +363,6 @@ func BenchmarkPreprocess(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - // initStaticBlocks is always performed before a Preprocess - initStaticBlocks(nil, pn, copies[i]) main = Preprocess(nil, pkg, copies[i]).(*FuncDecl) } } diff --git a/gnovm/pkg/gnolang/internal/txlog/txlog.go b/gnovm/pkg/gnolang/internal/txlog/txlog.go deleted file mode 100644 index cda11083672..00000000000 --- a/gnovm/pkg/gnolang/internal/txlog/txlog.go +++ /dev/null @@ -1,141 +0,0 @@ -// Package txlog is an internal package containing data structures that can -// function as "transaction logs" on top of a hash map (or other key/value -// data type implementing [Map]). -// -// A transaction log keeps track of the write operations performed in a -// transaction, so that they can be committed together, atomically, -// when calling [MapCommitter.Commit]. -package txlog - -// Map is a generic interface to a key/value map, like Go's builtin map. -type Map[K comparable, V any] interface { - Get(K) (V, bool) - Set(K, V) - Delete(K) - Iterate() func(yield func(K, V) bool) -} - -// MapCommitter is a Map which also implements a Commit() method, which writes -// to the underlying (parent) [Map]. -type MapCommitter[K comparable, V any] interface { - Map[K, V] - - // Commit writes the logged operations to the underlying map. - // After calling commit, the underlying tx log is cleared and the - // MapCommitter may be reused. - Commit() -} - -// GoMap is a simple implementation of [Map], which wraps the operations of -// Go's map builtin to implement [Map]. -type GoMap[K comparable, V any] map[K]V - -// Get implements [Map]. -func (m GoMap[K, V]) Get(k K) (V, bool) { - v, ok := m[k] - return v, ok -} - -// Set implements [Map]. -func (m GoMap[K, V]) Set(k K, v V) { - m[k] = v -} - -// Delete implements [Map]. -func (m GoMap[K, V]) Delete(k K) { - delete(m, k) -} - -// Iterate implements [Map]. -func (m GoMap[K, V]) Iterate() func(yield func(K, V) bool) { - return func(yield func(K, V) bool) { - for k, v := range m { - if !yield(k, v) { - return - } - } - } -} - -// Wrap wraps the map m into a data structure to keep a transaction log. -// To write data to m, use MapCommitter.Commit. -func Wrap[K comparable, V any](m Map[K, V]) MapCommitter[K, V] { - return &txLog[K, V]{ - source: m, - dirty: make(map[K]deletable[V]), - } -} - -type txLog[K comparable, V any] struct { - source Map[K, V] // read-only until Commit() - dirty map[K]deletable[V] // pending writes on source -} - -func (b *txLog[K, V]) Commit() { - // copy from b.dirty into b.source; clean b.dirty - for k, v := range b.dirty { - if v.deleted { - b.source.Delete(k) - } else { - b.source.Set(k, v.v) - } - } - b.dirty = make(map[K]deletable[V]) -} - -func (b txLog[K, V]) Get(k K) (V, bool) { - if bufValue, ok := b.dirty[k]; ok { - if bufValue.deleted { - var zeroV V - return zeroV, false - } - return bufValue.v, true - } - - return b.source.Get(k) -} - -func (b txLog[K, V]) Set(k K, v V) { - b.dirty[k] = deletable[V]{v: v} -} - -func (b txLog[K, V]) Delete(k K) { - b.dirty[k] = deletable[V]{deleted: true} -} - -func (b txLog[K, V]) Iterate() func(yield func(K, V) bool) { - return func(yield func(K, V) bool) { - // go through b.source; skip deleted values, and use updated values - // for those which exist in b.dirty. - b.source.Iterate()(func(k K, v V) bool { - if dirty, ok := b.dirty[k]; ok { - if dirty.deleted { - return true - } - return yield(k, dirty.v) - } - - // not in dirty - return yield(k, v) - }) - - // iterate over all "new" values (ie. exist in b.dirty but not b.source). - for k, v := range b.dirty { - if v.deleted { - continue - } - _, ok := b.source.Get(k) - if ok { - continue - } - if !yield(k, v.v) { - break - } - } - } -} - -type deletable[V any] struct { - v V - deleted bool -} diff --git a/gnovm/pkg/gnolang/internal/txlog/txlog_test.go b/gnovm/pkg/gnolang/internal/txlog/txlog_test.go deleted file mode 100644 index b0780fc8380..00000000000 --- a/gnovm/pkg/gnolang/internal/txlog/txlog_test.go +++ /dev/null @@ -1,553 +0,0 @@ -package txlog - -import ( - "fmt" - "maps" - "testing" - - "github.com/stretchr/testify/assert" -) - -func ExampleWrap() { - type User struct { - ID int - Name string - } - m := GoMap[int, User](map[int]User{ - 1: {ID: 1, Name: "alice"}, - 2: {ID: 2, Name: "bob"}, - }) - - // Wrap m in a transaction log. - txl := Wrap(m) - txl.Set(2, User{ID: 2, Name: "carl"}) - - // m will still have bob, while txl will have carl. - fmt.Println("m.Get(2):") - fmt.Println(m.Get(2)) - fmt.Println("txl.Get(2):") - fmt.Println(txl.Get(2)) - - // after txl.Commit(), the transaction log will be committed to m. - txl.Commit() - fmt.Println("--- commit ---") - fmt.Println("m.Get(2):") - fmt.Println(m.Get(2)) - fmt.Println("txl.Get(2):") - fmt.Println(txl.Get(2)) - - // Output: - // m.Get(2): - // {2 bob} true - // txl.Get(2): - // {2 carl} true - // --- commit --- - // m.Get(2): - // {2 carl} true - // txl.Get(2): - // {2 carl} true -} - -func Test_txLog(t *testing.T) { - t.Parallel() - - type Value = struct{} - - // Full "integration test" of the txLog + mapwrapper. - source := GoMap[int, *Value](map[int]*Value{}) - - // create 4 empty values (we'll just use the pointers) - vs := [...]*Value{ - {}, - {}, - {}, - {}, - } - source.Set(0, vs[0]) - source.Set(1, vs[1]) - source.Set(2, vs[2]) - - { - // Attempt getting, and deleting an item. - v, ok := source.Get(0) - assert.True(t, ok, "should be successful Get") - assert.True(t, vs[0] == v, "pointer returned should be ==") - - source.Delete(0) - v, ok = source.Get(0) - assert.False(t, ok, "should be unsuccessful Get") - assert.Nil(t, v, "pointer returned should be nil") - - verifyHashMapValues(t, source, map[int]*Value{1: vs[1], 2: vs[2]}) - } - - saved := maps.Clone(source) - txm := Wrap(source).(*txLog[int, *Value]) - - { - // Attempt getting, deleting an item on a buffered map; - // then creating a new one. - v, ok := txm.Get(1) - assert.True(t, ok, "should be successful Get") - assert.True(t, vs[1] == v, "pointer returned should be ==") - - txm.Delete(1) - v, ok = txm.Get(1) - assert.False(t, ok, "should be unsuccessful Get") - assert.Nil(t, v, "pointer returned should be nil") - - // Update an existing value to another value. - txm.Set(2, vs[0]) - v, ok = txm.Get(2) - assert.True(t, ok, "should be successful Get") - assert.True(t, vs[0] == v, "pointer returned should be ==") - - // Add a new value - txm.Set(3, vs[3]) - v, ok = txm.Get(3) - assert.True(t, ok, "should be successful Get") - assert.True(t, vs[3] == v, "pointer returned should be ==") - - // The original bufferedTxMap should still not know about the - // new value, and the internal "source" map should still be the - // same. - v, ok = source.Get(3) - assert.Nil(t, v) - assert.False(t, ok) - v, ok = source.Get(1) - assert.True(t, vs[1] == v) - assert.True(t, ok) - assert.Equal(t, saved, source) - assert.Equal(t, saved, txm.source) - - // double-check on the iterators. - verifyHashMapValues(t, source, map[int]*Value{1: vs[1], 2: vs[0]}) - verifyHashMapValues(t, txm, map[int]*Value{2: vs[2], 3: vs[3]}) - } - - { - // Using Commit() should cause txm's internal buffer to be cleared; - // and for all changes to show up on the source map. - txm.Commit() - assert.Empty(t, txm.dirty) - assert.Equal(t, source, txm.source) - assert.NotEqual(t, saved, source) - - v, ok := source.Get(3) - assert.True(t, vs[3] == v) - assert.True(t, ok) - v, ok = source.Get(1) - assert.Nil(t, v) - assert.False(t, ok) - - // double-check on the iterators. - verifyHashMapValues(t, source, map[int]*Value{2: vs[0], 3: vs[3]}) - verifyHashMapValues(t, txm, map[int]*Value{2: vs[0], 3: vs[3]}) - } -} - -func verifyHashMapValues(t *testing.T, m Map[int, *struct{}], expectedReadonly map[int]*struct{}) { - t.Helper() - - expected := maps.Clone(expectedReadonly) - m.Iterate()(func(k int, v *struct{}) bool { - ev, eok := expected[k] - _ = assert.True(t, eok, "mapping %d:%v should exist in expected map", k, v) && - assert.Equal(t, ev, v, "values should match") - delete(expected, k) - return true - }) - assert.Empty(t, expected, "(some) expected values not found in the Map") -} - -func Test_bufferedTxMap(t *testing.T) { - t.Parallel() - - type Value struct{} - - // Full "integration test" of the bufferedTxMap. - var m bufferedTxMap[int, *Value] - m.init() - - vs := [...]*Value{ - {}, - {}, - {}, - {}, - } - m.Set(0, vs[0]) - m.Set(1, vs[1]) - m.Set(2, vs[2]) - - { - // Attempt getting, and deleting an item. - v, ok := m.Get(0) - assert.True(t, ok, "should be successful Get") - assert.True(t, vs[0] == v, "pointer returned should be ==") - - m.Delete(0) - v, ok = m.Get(0) - assert.False(t, ok, "should be unsuccessful Get") - assert.Nil(t, v, "pointer returned should be nil") - } - - saved := maps.Clone(m.source) - bm := m.buffered() - - { - // Attempt getting, deleting an item on a buffered map; - // then creating a new one. - v, ok := bm.Get(1) - assert.True(t, ok, "should be successful Get") - assert.True(t, vs[1] == v, "pointer returned should be ==") - - bm.Delete(1) - v, ok = bm.Get(1) - assert.False(t, ok, "should be unsuccessful Get") - assert.Nil(t, v, "pointer returned should be nil") - - bm.Set(3, vs[3]) - v, ok = bm.Get(3) - assert.True(t, ok, "should be successful Get") - assert.True(t, vs[3] == v, "pointer returned should be ==") - - // The original bufferedTxMap should still not know about the - // new value, and the internal "source" map should still be the - // same. - v, ok = m.Get(3) - assert.Nil(t, v) - assert.False(t, ok) - v, ok = m.Get(1) - assert.True(t, vs[1] == v) - assert.True(t, ok) - assert.Equal(t, saved, m.source) - assert.Equal(t, saved, bm.source) - } - - { - // Using write() should cause bm's internal buffer to be cleared; - // and for all changes to show up on the source map. - bm.write() - assert.Empty(t, bm.dirty) - assert.Equal(t, m.source, bm.source) - assert.NotEqual(t, saved, m.source) - - v, ok := m.Get(3) - assert.True(t, vs[3] == v) - assert.True(t, ok) - v, ok = m.Get(1) - assert.Nil(t, v) - assert.False(t, ok) - } -} - -func Test_bufferedTxMap_initErr(t *testing.T) { - t.Parallel() - - var b bufferedTxMap[bool, bool] - b.init() - - assert.PanicsWithValue(t, "cannot init with a dirty buffer", func() { - buf := b.buffered() - buf.init() - }) -} - -func Test_bufferedTxMap_bufferedErr(t *testing.T) { - t.Parallel() - - var b bufferedTxMap[bool, bool] - b.init() - buf := b.buffered() - - assert.PanicsWithValue(t, "cannot stack multiple bufferedTxMap", func() { - buf.buffered() - }) -} - -// bufferedTxMap is a wrapper around the map type, supporting regular Get, Set -// and Delete operations. Additionally, it can create a "buffered" version of -// itself, which will keep track of all write (set and delete) operations to the -// map; so that they can all be atomically committed when calling "write". -type bufferedTxMap[K comparable, V any] struct { - source map[K]V - dirty map[K]deletable[V] -} - -// init should be called when creating the bufferedTxMap, in a non-buffered -// context. -func (b *bufferedTxMap[K, V]) init() { - if b.dirty != nil { - panic("cannot init with a dirty buffer") - } - b.source = make(map[K]V) -} - -// buffered creates a copy of b, which has a usable dirty map. -func (b bufferedTxMap[K, V]) buffered() bufferedTxMap[K, V] { - if b.dirty != nil { - panic("cannot stack multiple bufferedTxMap") - } - return bufferedTxMap[K, V]{ - source: b.source, - dirty: make(map[K]deletable[V]), - } -} - -// write commits the data in dirty to the map in source. -func (b *bufferedTxMap[K, V]) write() { - for k, v := range b.dirty { - if v.deleted { - delete(b.source, k) - } else { - b.source[k] = v.v - } - } - b.dirty = make(map[K]deletable[V]) -} - -func (b bufferedTxMap[K, V]) Get(k K) (V, bool) { - if b.dirty != nil { - if bufValue, ok := b.dirty[k]; ok { - if bufValue.deleted { - var zeroV V - return zeroV, false - } - return bufValue.v, true - } - } - v, ok := b.source[k] - return v, ok -} - -func (b bufferedTxMap[K, V]) Set(k K, v V) { - if b.dirty == nil { - b.source[k] = v - return - } - b.dirty[k] = deletable[V]{v: v} -} - -func (b bufferedTxMap[K, V]) Delete(k K) { - if b.dirty == nil { - delete(b.source, k) - return - } - b.dirty[k] = deletable[V]{deleted: true} -} - -func Benchmark_txLogRead(b *testing.B) { - const maxValues = (1 << 10) * 9 // must be multiple of 9 - - var ( - baseMap = make(map[int]int) // all values filled - wrapped = GoMap[int, int](baseMap) // wrapper around baseMap - stack1 = Wrap(wrapped) // n+1, n+4, n+7 values filled (n%9 == 0) - stack2 = Wrap(stack1) // n'th values filled (n%9 == 0) - ) - - for i := 0; i < maxValues; i++ { - baseMap[i] = i - switch i % 9 { - case 1, 4, 7: - stack1.Set(i, i+1_000_000) - case 0: - stack2.Set(i, i+10_000_000) - } - } - - var v int - var ok bool - _, _ = v, ok - - // through closure, so func calls have to go through "indirection". - runbench := func(b *testing.B, src Map[int, int]) { //nolint:thelper - for i := 0; i < b.N; i++ { - v, ok = src.Get(i % maxValues) - } - } - - b.Run("stack2", func(b *testing.B) { runbench(b, stack2) }) - b.Run("stack1", func(b *testing.B) { runbench(b, stack1) }) - b.Run("wrapped", func(b *testing.B) { runbench(b, wrapped) }) - b.Run("baseline", func(b *testing.B) { - for i := 0; i < b.N; i++ { - v, ok = baseMap[i%maxValues] - } - }) -} - -func Benchmark_txLogWrite(b *testing.B) { - // after this amount of values, the maps are re-initialized. - // you can tweak this to see how the benchmarks behave on a variety of - // values. - // NOTE: setting this too high will skew the benchmark in favour those which - // have a smaller N, as those with a higher N have to allocate more in a - // single map. - const maxValues = 1 << 15 // 32768 - - var v int - var ok bool - _, _ = v, ok - - b.Run("stack1", func(b *testing.B) { - src := GoMap[int, int](make(map[int]int)) - st := Wrap(src) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - k := i % maxValues - - st.Set(k, i) - // we use this assignment to prevent the compiler from optimizing - // out code, especially in the baseline case. - v, ok = st.Get(k) - - if k == maxValues-1 { - st = Wrap(src) - } - } - }) - b.Run("wrapped", func(b *testing.B) { - src := GoMap[int, int](make(map[int]int)) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - k := i % maxValues - - src.Set(k, i) - // we use this assignment to prevent the compiler from optimizing - // out code, especially in the baseline case. - v, ok = src.Get(k) - - if k == maxValues-1 { - src = GoMap[int, int](make(map[int]int)) - } - } - }) - b.Run("baseline", func(b *testing.B) { - // this serves to have a baseline value in the benchmark results - // for when we just use a map directly. - m := make(map[int]int) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - k := i % maxValues - - m[k] = i - v, ok = m[k] - - if k == maxValues-1 { - m = make(map[int]int) - } - } - }) -} - -func Benchmark_bufferedTxMapRead(b *testing.B) { - const maxValues = (1 << 10) * 9 // must be multiple of 9 - - var ( - baseMap = make(map[int]int) // all values filled - wrapped = bufferedTxMap[int, int]{source: baseMap} - stack1 = wrapped.buffered() // n, n+1, n+4, n+7 values filled (n%9 == 0) - // this test doesn't have stack2 as bufferedTxMap - // does not support stacking - ) - - for i := 0; i < maxValues; i++ { - baseMap[i] = i - switch i % 9 { - case 0, 1, 4, 7: - stack1.Set(i, i+1_000_000) - } - } - - var v int - var ok bool - _, _ = v, ok - - b.Run("stack1", func(b *testing.B) { - for i := 0; i < b.N; i++ { - // use assignment to avoid the compiler optimizing out the loops - v, ok = stack1.Get(i % maxValues) - } - }) - b.Run("wrapped", func(b *testing.B) { - for i := 0; i < b.N; i++ { - v, ok = wrapped.Get(i % maxValues) - } - }) - b.Run("baseline", func(b *testing.B) { - for i := 0; i < b.N; i++ { - v, ok = baseMap[i%maxValues] - } - }) -} - -func Benchmark_bufferedTxMapWrite(b *testing.B) { - // after this amount of values, the maps are re-initialized. - // you can tweak this to see how the benchmarks behave on a variety of - // values. - // NOTE: setting this too high will skew the benchmark in favour those which - // have a smaller N, as those with a higher N have to allocate more in a - // single map. - const maxValues = 1 << 15 // 32768 - - var v int - var ok bool - _, _ = v, ok - - b.Run("buffered", func(b *testing.B) { - var orig bufferedTxMap[int, int] - orig.init() - txm := orig.buffered() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - k := i % maxValues - - txm.Set(k, i) - // we use this assignment to prevent the compiler from optimizing - // out code, especially in the baseline case. - v, ok = txm.Get(k) - - if k == maxValues-1 { - txm = orig.buffered() - } - } - }) - b.Run("unbuffered", func(b *testing.B) { - var txm bufferedTxMap[int, int] - txm.init() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - k := i % maxValues - - txm.Set(k, i) - v, ok = txm.Get(k) - - if k == maxValues-1 { - txm.init() - } - } - }) - b.Run("baseline", func(b *testing.B) { - // this serves to have a baseline value in the benchmark results - // for when we just use a map directly. - m := make(map[int]int) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - k := i % maxValues - - m[k] = i - v, ok = m[k] - - if k == maxValues-1 { - m = make(map[int]int) - } - } - }) -} diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 718ee803fe1..850da3d3c0f 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -25,23 +25,12 @@ type Exception struct { // Frame is used to reference the frame a panic occurred in so that recover() knows if the // currently executing deferred function is able to recover from the panic. Frame *Frame - - Stacktrace Stacktrace } func (e Exception) Sprint(m *Machine) string { return e.Value.Sprint(m) } -// UnhandledPanicError represents an error thrown when a panic is not handled in the realm. -type UnhandledPanicError struct { - Descriptor string // Description of the unhandled panic. -} - -func (e UnhandledPanicError) Error() string { - return e.Descriptor -} - //---------------------------------------- // Machine @@ -468,43 +457,6 @@ func (m *Machine) TestFunc(t *testing.T, tv TypedValue) { }) } -// Stacktrace returns the stack trace of the machine. -// It collects the executions and frames from the machine's frames and statements. -func (m *Machine) Stacktrace() (stacktrace Stacktrace) { - if len(m.Frames) == 0 { - return - } - - calls := make([]StacktraceCall, 0, len(m.Stmts)) - nextStmtIndex := len(m.Stmts) - 1 - for i := len(m.Frames) - 1; i >= 0; i-- { - if m.Frames[i].IsCall() { - stm := m.Stmts[nextStmtIndex] - bs := stm.(*bodyStmt) - stm = bs.Body[bs.NextBodyIndex-1] - calls = append(calls, StacktraceCall{ - Stmt: stm, - Frame: m.Frames[i], - }) - } - // if the frame is a call, the next statement is the last statement of the frame. - nextStmtIndex = m.Frames[i].NumStmts - 1 - } - - // if the stacktrace is too long, we trim it down to maxStacktraceSize - if len(calls) > maxStacktraceSize { - const halfMax = maxStacktraceSize / 2 - - stacktrace.NumFramesElided = len(calls) - maxStacktraceSize - calls = append(calls[:halfMax], calls[len(calls)-halfMax:]...) - calls = calls[:len(calls):len(calls)] // makes remaining part of "calls" GC'able - } - - stacktrace.Calls = calls - - return -} - // in case of panic, inject location information to exception. func (m *Machine) injectLocOnPanic() { if r := recover(); r != nil { @@ -784,14 +736,8 @@ func (m *Machine) resavePackageValues(rlm *Realm) { func (m *Machine) RunFunc(fn Name) { defer func() { if r := recover(); r != nil { - switch r := r.(type) { - case UnhandledPanicError: - fmt.Printf("Machine.RunFunc(%q) panic: %s\nStacktrace: %s\n", - fn, r.Error(), m.ExceptionsStacktrace()) - default: - fmt.Printf("Machine.RunFunc(%q) panic: %v\nMachine State:%s\nStacktrace: %s\n", - fn, r, m.String(), m.Stacktrace().String()) - } + fmt.Printf("Machine.RunFunc(%q) panic: %v\n%s\n", + fn, r, m.String()) panic(r) } }() @@ -801,14 +747,8 @@ func (m *Machine) RunFunc(fn Name) { func (m *Machine) RunMain() { defer func() { if r := recover(); r != nil { - switch r := r.(type) { - case UnhandledPanicError: - fmt.Printf("Machine.RunMain() panic: %s\nStacktrace: %s\n", - r.Error(), m.ExceptionsStacktrace()) - default: - fmt.Printf("Machine.RunMain() panic: %v\nMachine State:%s\nStacktrace: %s\n", - r, m.String(), m.Stacktrace()) - } + fmt.Printf("Machine.RunMain() panic: %v\n%s\n", + r, m.String()) panic(r) } }() @@ -1666,11 +1606,11 @@ func (m *Machine) PopStmt() Stmt { } if bs, ok := s.(*bodyStmt); ok { return bs.PopActiveStmt() + } else { + // general case. + m.Stmts = m.Stmts[:numStmts-1] + return s } - - m.Stmts = m.Stmts[:numStmts-1] - - return s } func (m *Machine) ForcePopStmt() (s Stmt) { @@ -1915,7 +1855,6 @@ func (m *Machine) PopFrame() Frame { m.Printf("-F %#v\n", f) } m.Frames = m.Frames[:numFrames-1] - return *f } @@ -1935,7 +1874,8 @@ func (m *Machine) PopFrameAndReturn() { fr := m.PopFrame() fr.Popped = true if debug { - if !fr.IsCall() { + // TODO: optimize with fr.IsCall + if fr.Func == nil && fr.GoFunc == nil { panic("unexpected non-call (loop) frame") } } @@ -2011,7 +1951,8 @@ func (m *Machine) lastCallFrame(n int, mustBeFound bool) *Frame { } for i := len(m.Frames) - 1; i >= 0; i-- { fr := m.Frames[i] - if fr.IsCall() { + if fr.Func != nil || fr.GoFunc != nil { + // TODO: optimize with fr.IsCall if n == 1 { return fr } else { @@ -2032,7 +1973,8 @@ func (m *Machine) lastCallFrame(n int, mustBeFound bool) *Frame { func (m *Machine) PopUntilLastCallFrame() *Frame { for i := len(m.Frames) - 1; i >= 0; i-- { fr := m.Frames[i] - if fr.IsCall() { + if fr.Func != nil || fr.GoFunc != nil { + // TODO: optimize with fr.IsCall m.Frames = m.Frames[:i+1] return fr } @@ -2143,9 +2085,8 @@ func (m *Machine) Panic(ex TypedValue) { m.Exceptions = append( m.Exceptions, Exception{ - Value: ex, - Frame: m.MustLastCallFrame(1), - Stacktrace: m.Stacktrace(), + Value: ex, + Frame: m.MustLastCallFrame(1), }, ) @@ -2214,8 +2155,7 @@ func (m *Machine) String() string { builder.WriteString(" Blocks:\n") - for i := len(m.Blocks) - 1; i > 0; i-- { - b := m.Blocks[i] + for b := m.LastBlock(); b != nil; { gen := builder.Len()/3 + 1 gens := "@" // strings.Repeat("@", gen) @@ -2291,30 +2231,6 @@ func (m *Machine) String() string { return builder.String() } -func (m *Machine) ExceptionsStacktrace() string { - if len(m.Exceptions) == 0 { - return "" - } - - var builder strings.Builder - - ex := m.Exceptions[0] - builder.WriteString("panic: " + ex.Sprint(m) + "\n") - builder.WriteString(ex.Stacktrace.String()) - - switch { - case len(m.Exceptions) > 2: - fmt.Fprintf(&builder, "... %d panic(s) elided ...\n", len(m.Exceptions)-2) - fallthrough // to print last exception - case len(m.Exceptions) == 2: - ex = m.Exceptions[len(m.Exceptions)-1] - builder.WriteString("panic: " + ex.Sprint(m) + "\n") - builder.WriteString(ex.Stacktrace.String()) - } - - return builder.String() -} - //---------------------------------------- // utility diff --git a/gnovm/pkg/gnolang/misc.go b/gnovm/pkg/gnolang/misc.go index 7f7ce0b3a87..a05de8c74aa 100644 --- a/gnovm/pkg/gnolang/misc.go +++ b/gnovm/pkg/gnolang/misc.go @@ -150,10 +150,6 @@ func isReservedName(n Name) bool { // scans uverse static node for blocknames. (slow) func isUverseName(n Name) bool { - if n == "panic" { - // panic is not in uverse, as it is parsed as its own statement (PanicStmt) - return true - } uverseNames := UverseNode().GetBlockNames() for _, name := range uverseNames { if name == n { diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index b18ed157ca6..c578d2a3ec3 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -4,7 +4,6 @@ import ( "fmt" "go/parser" "go/token" - "math" "os" "path/filepath" "reflect" @@ -1803,7 +1802,7 @@ func (sb *StaticBlock) Define2(isConst bool, n Name, st Type, tv TypedValue) { if int(sb.NumNames) != len(sb.Names) { panic("StaticBlock.NumNames and len(.Names) mismatch") } - if sb.NumNames == math.MaxUint16 { + if (1<<16 - 1) < sb.NumNames { panic("too many variables in block") } if tv.T == nil && tv.V != nil { diff --git a/gnovm/pkg/gnolang/nodes_test.go b/gnovm/pkg/gnolang/nodes_test.go deleted file mode 100644 index 2c3a03d8c09..00000000000 --- a/gnovm/pkg/gnolang/nodes_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package gnolang_test - -import ( - "math" - "testing" - - "github.com/gnolang/gno/gnovm/pkg/gnolang" -) - -func TestStaticBlock_Define2_MaxNames(t *testing.T) { - defer func() { - if r := recover(); r != nil { - panicString, ok := r.(string) - if !ok { - t.Errorf("expected panic string, got %v", r) - } - - if panicString != "too many variables in block" { - t.Errorf("expected panic string to be 'too many variables in block', got '%s'", panicString) - } - - return - } - - // If it didn't panic, fail. - t.Errorf("expected panic when exceeding maximum number of names") - }() - - staticBlock := new(gnolang.StaticBlock) - staticBlock.NumNames = math.MaxUint16 - 1 - staticBlock.Names = make([]gnolang.Name, staticBlock.NumNames) - - // Adding one more is okay. - staticBlock.Define2(false, gnolang.Name("a"), gnolang.BoolType, gnolang.TypedValue{T: gnolang.BoolType}) - if staticBlock.NumNames != math.MaxUint16 { - t.Errorf("expected NumNames to be %d, got %d", math.MaxUint16, staticBlock.NumNames) - } - if len(staticBlock.Names) != math.MaxUint16 { - t.Errorf("expected len(Names) to be %d, got %d", math.MaxUint16, len(staticBlock.Names)) - } - - // This one should panic because the maximum number of names has been reached. - staticBlock.Define2(false, gnolang.Name("a"), gnolang.BoolType, gnolang.TypedValue{T: gnolang.BoolType}) -} diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index db3c1e5695c..0d4581377c2 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -79,6 +79,7 @@ func (m *Machine) doOpEql() { if debug { debugAssertEqualityTypes(lv.T, rv.T) } + // set result in lv. res := isEql(m.Store, lv, rv) lv.T = UntypedBoolType @@ -343,9 +344,6 @@ func isEql(store Store, lv, rv *TypedValue) bool { } else if rvu { return false } - if err := checkSame(lv.T, rv.T, ""); err != nil { - return false - } if lnt, ok := lv.T.(*NativeType); ok { if rnt, ok := rv.T.(*NativeType); ok { if lnt.Type != rnt.Type { diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 15531ec610d..5479ee6d5ae 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -427,9 +427,7 @@ func (m *Machine) doOpPanic2() { for i, ex := range m.Exceptions { exs[i] = ex.Sprint(m) } - panic(UnhandledPanicError{ - Descriptor: strings.Join(exs, "\n\t"), - }) + panic(strings.Join(exs, "\n\t")) } m.PushOp(OpPanic2) m.PushOp(OpReturnCallDefers) // XXX rename, not return? diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 8ff0b5bd538..36130ccbf4d 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -194,13 +194,8 @@ func (m *Machine) doOpRef() { nv.Value = rv2 } } - // when obtaining a pointer of the databyte type, use the ElemType of databyte - elt := xv.TV.T - if elt == DataByteType { - elt = xv.TV.V.(DataByteValue).ElemType - } m.PushValue(TypedValue{ - T: m.Alloc.NewType(&PointerType{Elt: elt}), + T: m.Alloc.NewType(&PointerType{Elt: xv.TV.T}), V: xv, }) } diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 9168fc6f7c1..5a710723b86 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -45,12 +45,11 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { // skip declarations already predefined // (e.g. through recursion for a // dependent) - continue + } else { + // recursively predefine dependencies. + d2, _ := predefineNow(store, fn, d) + fn.Decls[i] = d2 } - - // recursively predefine dependencies. - d2, _ := predefineNow(store, fn, d) - fn.Decls[i] = d2 } } } @@ -64,12 +63,11 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { // skip declarations already predefined // (e.g. through recursion for a // dependent) - continue + } else { + // recursively predefine dependencies. + d2, _ := predefineNow(store, fn, d) + fn.Decls[i] = d2 } - - // recursively predefine dependencies. - d2, _ := predefineNow(store, fn, d) - fn.Decls[i] = d2 } } } @@ -83,12 +81,11 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { // skip declarations already predefined // (e.g. through recursion for a // dependent) - continue + } else { + // recursively predefine dependencies. + d2, _ := predefineNow(store, fn, d) + fn.Decls[i] = d2 } - - // recursively predefine dependencies. - d2, _ := predefineNow(store, fn, d) - fn.Decls[i] = d2 } } } @@ -100,36 +97,11 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { if d.GetAttribute(ATTR_PREDEFINED) == true { // skip declarations already predefined (e.g. // through recursion for a dependent) - continue - } - - if vd, ok := d.(*ValueDecl); ok && len(vd.NameExprs) > 1 && len(vd.Values) == len(vd.NameExprs) { - split := make([]Decl, len(vd.NameExprs)) - - for j := 0; j < len(vd.NameExprs); j++ { - base := vd.Copy().(*ValueDecl) - base.NameExprs = NameExprs{NameExpr{ - Attributes: base.NameExprs[j].Attributes, - Path: base.NameExprs[j].Path, - Name: base.NameExprs[j].Name, - }} - - if j < len(base.Values) { - base.Values = Exprs{base.Values[j].Copy().(Expr)} - } - - split[j], _ = predefineNow(store, fn, base) - } - - fn.Decls = append(fn.Decls[:i], append(split, fn.Decls[i+1:]...)...) //nolint:makezero - i += len(vd.NameExprs) - continue + } else { + // recursively predefine dependencies. + d2, _ := predefineNow(store, fn, d) + fn.Decls[i] = d2 } - - // recursively predefine dependencies. - d2, _ := predefineNow(store, fn, d) - - fn.Decls[i] = d2 } } } @@ -1235,9 +1207,6 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { "incompatible types in binary expression: %v %v %v", lt.TypeID(), n.Op, rt.TypeID())) } - // convert untyped to typed - checkOrConvertType(store, last, &n.Left, defaultTypeOf(lt), false) - checkOrConvertType(store, last, &n.Right, defaultTypeOf(rt), false) } else { // left untyped, right typed checkOrConvertType(store, last, &n.Left, rt, false) } @@ -1534,13 +1503,6 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { checkOrConvertIntegerKind(store, last, n.High) checkOrConvertIntegerKind(store, last, n.Max) - // if n.X is untyped, convert to corresponding type - t := evalStaticTypeOf(store, last, n.X) - if isUntyped(t) { - dt := defaultTypeOf(t) - checkOrConvertType(store, last, &n.X, dt, false) - } - // TRANS_LEAVE ----------------------- case *TypeAssertExpr: if n.Type == nil { @@ -2201,42 +2163,13 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { numNames := len(n.NameExprs) sts := make([]Type, numNames) // static types tvs := make([]TypedValue, numNames) - if numNames > 1 && len(n.Values) == 1 { - // Special cases if one of the following: - // - `var a, b, c T = f()` - // - `var a, b = n.(T)` - // - `var a, b = n[i], where n is a map` - - var tuple *tupleType - valueExpr := n.Values[0] - valueType := evalStaticTypeOfRaw(store, last, valueExpr) - - switch expr := valueExpr.(type) { - case *CallExpr: - tuple = valueType.(*tupleType) - case *TypeAssertExpr, *IndexExpr: - tuple = &tupleType{Elts: []Type{valueType, BoolType}} - if ex, ok := expr.(*TypeAssertExpr); ok { - ex.HasOK = true - break - } - expr.(*IndexExpr).HasOK = true - default: - panic(fmt.Sprintf("unexpected ValueDecl value expression type %T", expr)) - } - - if rLen := len(tuple.Elts); rLen != numNames { - panic( - fmt.Sprintf( - "assignment mismatch: %d variable(s) but %s returns %d value(s)", - numNames, - valueExpr.String(), - rLen, - ), - ) + // special case if `var a, b, c T? = f()` form. + cx := n.Values[0].(*CallExpr) + tt := evalStaticTypeOfRaw(store, last, cx).(*tupleType) + if rLen := len(tt.Elts); rLen != numNames { + panic(fmt.Sprintf("assignment mismatch: %d variable(s) but %s returns %d value(s)", numNames, cx.Func.String(), rLen)) } - if n.Type != nil { // only a single type can be specified. nt := evalStaticType(store, last, n.Type) @@ -2248,7 +2181,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { } else { // set types as return types. for i := 0; i < numNames; i++ { - et := tuple.Elts[i] + et := tt.Elts[i] sts[i] = et tvs[i] = anyValue(et) } @@ -2485,7 +2418,7 @@ func evalStaticType(store Store, last BlockNode, x Expr) Type { // See comment in evalStaticTypeOfRaw. if store != nil && pn.PkgPath != uversePkgPath { pv := pn.NewPackage() // temporary - store = store.BeginTransaction(nil, nil) + store = store.Fork() store.SetCachePackage(pv) } m := NewMachine(pn.PkgPath, store) @@ -2559,7 +2492,7 @@ func evalStaticTypeOfRaw(store Store, last BlockNode, x Expr) (t Type) { // yet predefined this time around. if store != nil && pn.PkgPath != uversePkgPath { pv := pn.NewPackage() // temporary - store = store.BeginTransaction(nil, nil) + store = store.Fork() store.SetCachePackage(pv) } m := NewMachine(pn.PkgPath, store) @@ -2861,10 +2794,8 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative // push t into bx.Left checkOrConvertType(store, last, &bx.Left, t, autoNative) return - case EQL, LSS, GTR, NEQ, LEQ, GEQ: - // do nothing - default: - // do nothing + // case EQL, LSS, GTR, NEQ, LEQ, GEQ: + // default: } } } @@ -2975,92 +2906,6 @@ func convertConst(store Store, last BlockNode, cx *ConstExpr, t Type) { } } -func assertTypeDeclNoCycle(store Store, last BlockNode, td *TypeDecl, stack *[]Name) { - assertTypeDeclNoCycle2(store, last, td.Type, stack, false, td.IsAlias) -} - -func assertTypeDeclNoCycle2(store Store, last BlockNode, x Expr, stack *[]Name, indirect bool, isAlias bool) { - if x == nil { - panic("unexpected nil expression when checking for type declaration cycles") - } - - var lastX Expr - defer func() { - if _, ok := lastX.(*NameExpr); ok { - // pop stack - *stack = (*stack)[:len(*stack)-1] - } - }() - - switch cx := x.(type) { - case *NameExpr: - var msg string - - // Function to build the error message - buildMessage := func() string { - for j := 0; j < len(*stack); j++ { - msg += fmt.Sprintf("%s -> ", (*stack)[j]) - } - return msg + string(cx.Name) // Append the current name last - } - - // Check for existence of cx.Name in stack - findCycle := func() { - for _, n := range *stack { - if n == cx.Name { - msg = buildMessage() - panic(fmt.Sprintf("invalid recursive type: %s", msg)) - } - } - } - - if indirect && !isAlias { - *stack = (*stack)[:0] - } else { - findCycle() - *stack = append(*stack, cx.Name) - lastX = cx - } - - return - case *SelectorExpr: - assertTypeDeclNoCycle2(store, last, cx.X, stack, indirect, isAlias) - case *StarExpr: - assertTypeDeclNoCycle2(store, last, cx.X, stack, true, isAlias) - case *FieldTypeExpr: - assertTypeDeclNoCycle2(store, last, cx.Type, stack, indirect, isAlias) - case *ArrayTypeExpr: - if cx.Len != nil { - assertTypeDeclNoCycle2(store, last, cx.Len, stack, indirect, isAlias) - } - assertTypeDeclNoCycle2(store, last, cx.Elt, stack, indirect, isAlias) - case *SliceTypeExpr: - assertTypeDeclNoCycle2(store, last, cx.Elt, stack, true, isAlias) - case *InterfaceTypeExpr: - for i := range cx.Methods { - assertTypeDeclNoCycle2(store, last, &cx.Methods[i], stack, indirect, isAlias) - } - case *ChanTypeExpr: - assertTypeDeclNoCycle2(store, last, cx.Value, stack, true, isAlias) - case *FuncTypeExpr: - for i := range cx.Params { - assertTypeDeclNoCycle2(store, last, &cx.Params[i], stack, true, isAlias) - } - for i := range cx.Results { - assertTypeDeclNoCycle2(store, last, &cx.Results[i], stack, true, isAlias) - } - case *MapTypeExpr: - assertTypeDeclNoCycle2(store, last, cx.Key, stack, true, isAlias) - assertTypeDeclNoCycle2(store, last, cx.Value, stack, true, isAlias) - case *StructTypeExpr: - for i := range cx.Fields { - assertTypeDeclNoCycle2(store, last, &cx.Fields[i], stack, indirect, isAlias) - } - default: - } - return -} - // Returns any names not yet defined nor predefined in expr. These happen // upon transcribe:enter from the top, so value paths cannot be used. If no // names are un and x is TypeExpr, evalStaticType(store,last, x) must not @@ -3352,11 +3197,11 @@ func predefineNow(store Store, last BlockNode, d Decl) (Decl, bool) { } } }() - stack := &[]Name{} - return predefineNow2(store, last, d, stack) + m := make(map[Name]struct{}) + return predefineNow2(store, last, d, m) } -func predefineNow2(store Store, last BlockNode, d Decl, stack *[]Name) (Decl, bool) { +func predefineNow2(store Store, last BlockNode, d Decl, m map[Name]struct{}) (Decl, bool) { pkg := packageOf(last) // pre-register d.GetName() to detect circular definition. for _, dn := range d.GetDeclNames() { @@ -3364,24 +3209,15 @@ func predefineNow2(store Store, last BlockNode, d Decl, stack *[]Name) (Decl, bo panic(fmt.Sprintf( "builtin identifiers cannot be shadowed: %s", dn)) } - *stack = append(*stack, dn) - } - - // check type decl cycle - if td, ok := d.(*TypeDecl); ok { - // recursively check - assertTypeDeclNoCycle(store, last, td, stack) + m[dn] = struct{}{} } - // recursively predefine dependencies. for { un := tryPredefine(store, last, d) if un != "" { // check circularity. - for _, n := range *stack { - if n == un { - panic(fmt.Sprintf("constant definition loop with %s", un)) - } + if _, ok := m[un]; ok { + panic(fmt.Sprintf("constant definition loop with %s", un)) } // look up dependency declaration from fileset. file, decl := pkg.FileSet.GetDeclFor(un) @@ -3390,7 +3226,7 @@ func predefineNow2(store Store, last BlockNode, d Decl, stack *[]Name) (Decl, bo panic("all types from files in file-set should have already been predefined") } // predefine dependency (recursive). - *decl, _ = predefineNow2(store, file, *decl, stack) + *decl, _ = predefineNow2(store, file, *decl, m) } else { break } diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index 8a1743ddf53..038f4ba894b 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -2,16 +2,17 @@ package gnolang import ( "fmt" + "maps" "reflect" "slices" "strconv" "strings" - "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/txlog" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/colors" "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/store" + "github.com/gnolang/gno/tm2/pkg/store/types" "github.com/gnolang/gno/tm2/pkg/store/utils" stringz "github.com/gnolang/gno/tm2/pkg/strings" ) @@ -31,12 +32,8 @@ type PackageInjector func(store Store, pn *PackageNode) // NativeStore is a function which can retrieve native bodies of native functions. type NativeStore func(pkgName string, name Name) func(m *Machine) -// Store is the central interface that specifies the communications between the -// GnoVM and the underlying data store; currently, generally the Gno.land -// blockchain, or the file system. type Store interface { // STABLE - BeginTransaction(baseStore, iavlStore store.Store) TransactionStore SetPackageGetter(PackageGetter) GetPackage(pkgPath string, isImport bool) *PackageValue SetCachePackage(*PackageValue) @@ -65,7 +62,9 @@ type Store interface { GetMemPackage(path string) *std.MemPackage GetMemFile(path string, name string) *std.MemFile IterMemPackage() <-chan *std.MemPackage - ClearObjectCache() // run before processing a message + ClearObjectCache() // for each delivertx. + Fork() Store // for checktx, simulate, and queries. + SwapStores(baseStore, iavlStore store.Store) // for gas wrappers. SetPackageInjector(PackageInjector) // for natives SetNativeStore(NativeStore) // for "new" natives XXX GetNative(pkgPath string, name Name) func(m *Machine) // for "new" natives XXX @@ -74,33 +73,20 @@ type Store interface { LogSwitchRealm(rlmpath string) // to mark change of realm boundaries ClearCache() Print() -} - -// TransactionStore is a store where the operations modifying the underlying store's -// caches are temporarily held in a buffer, and then executed together after -// executing Write. -type TransactionStore interface { - Store - - // Write commits the current buffered transaction data to the underlying store. - // It also clears the current buffer of the transaction. Write() + Flush() } +// Used to keep track of in-mem objects during tx. type defaultStore struct { - // underlying stores used to keep data - baseStore store.Store // for objects, types, nodes - iavlStore store.Store // for escaped object hashes - - // transaction-scoped - cacheObjects map[ObjectID]Object // this is a real cache, reset with every transaction. - cacheTypes txlog.Map[TypeID, Type] // this re-uses the parent store's. - cacheNodes txlog.Map[Location, BlockNode] // until BlockNode persistence is implemented, this is an actual store. - alloc *Allocator // for accounting for cached items - - // store configuration; cannot be modified in a transaction - pkgGetter PackageGetter // non-realm packages - cacheNativeTypes map[reflect.Type]Type // reflect doc: reflect.Type are comparable + alloc *Allocator // for accounting for cached items + pkgGetter PackageGetter // non-realm packages + cacheObjects map[ObjectID]Object + cacheTypes map[TypeID]Type + cacheNodes map[Location]BlockNode + cacheNativeTypes map[reflect.Type]Type // go spec: reflect.Type are comparable + baseStore store.Store // for objects, types, nodes + iavlStore store.Store // for escaped object hashes pkgInjector PackageInjector // for injecting natives nativeStore NativeStore // for injecting natives go2gnoStrict bool // if true, native->gno type conversion must be registered. @@ -112,119 +98,28 @@ type defaultStore struct { func NewStore(alloc *Allocator, baseStore, iavlStore store.Store) *defaultStore { ds := &defaultStore{ - baseStore: baseStore, - iavlStore: iavlStore, - alloc: alloc, - - // cacheObjects is set; objects in the store will be copied over for any transaction. - cacheObjects: make(map[ObjectID]Object), - cacheTypes: txlog.GoMap[TypeID, Type](map[TypeID]Type{}), - cacheNodes: txlog.GoMap[Location, BlockNode](map[Location]BlockNode{}), - - // store configuration + alloc: alloc, pkgGetter: nil, + cacheObjects: make(map[ObjectID]Object), + cacheTypes: make(map[TypeID]Type), + cacheNodes: make(map[Location]BlockNode), cacheNativeTypes: make(map[reflect.Type]Type), - pkgInjector: nil, - nativeStore: nil, + baseStore: baseStore, + iavlStore: iavlStore, go2gnoStrict: true, } InitStoreCaches(ds) return ds } -// If nil baseStore and iavlStore, the baseStores are re-used. -func (ds *defaultStore) BeginTransaction(baseStore, iavlStore store.Store) TransactionStore { - if baseStore == nil { - baseStore = ds.baseStore - } - if iavlStore == nil { - iavlStore = ds.iavlStore - } - ds2 := &defaultStore{ - // underlying stores - baseStore: baseStore, - iavlStore: iavlStore, - - // transaction-scoped - cacheObjects: make(map[ObjectID]Object), - cacheTypes: txlog.Wrap(ds.cacheTypes), - cacheNodes: txlog.Wrap(ds.cacheNodes), - alloc: ds.alloc.Fork().Reset(), - - // store configuration - pkgGetter: ds.pkgGetter, - cacheNativeTypes: ds.cacheNativeTypes, - pkgInjector: ds.pkgInjector, - nativeStore: ds.nativeStore, - go2gnoStrict: ds.go2gnoStrict, - - // transient - current: nil, - opslog: nil, - } - ds2.SetCachePackage(Uverse()) - - return transactionStore{ds2} -} - -type transactionStore struct{ *defaultStore } - -func (t transactionStore) Write() { - t.cacheTypes.(txlog.MapCommitter[TypeID, Type]).Commit() - t.cacheNodes.(txlog.MapCommitter[Location, BlockNode]).Commit() -} - -func (transactionStore) SetPackageGetter(pg PackageGetter) { - panic("SetPackageGetter may not be called in a transaction store") -} - -func (transactionStore) ClearCache() { - panic("ClearCache may not be called in a transaction store") -} - -// XXX: we should block Go2GnoType, because it uses a global cache map; -// but it's called during preprocess and thus breaks some testing code. -// let's wait until we remove Go2Gno entirely. -// https://github.com/gnolang/gno/issues/1361 -// func (transactionStore) Go2GnoType(reflect.Type) Type { -// panic("Go2GnoType may not be called in a transaction store") -// } - -func (transactionStore) SetPackageInjector(inj PackageInjector) { - panic("SetPackageInjector may not be called in a transaction store") -} - -func (transactionStore) SetNativeStore(ns NativeStore) { - panic("SetNativeStore may not be called in a transaction store") -} - -func (transactionStore) SetStrictGo2GnoMapping(strict bool) { - panic("SetStrictGo2GnoMapping may not be called in a transaction store") -} - // CopyCachesFromStore allows to copy a store's internal object, type and // BlockNode cache into the dst store. // This is mostly useful for testing, where many stores have to be initialized. -func CopyFromCachedStore(destStore, cachedStore Store, cachedBase, cachedIavl store.Store) { - ds, ss := destStore.(transactionStore), cachedStore.(*defaultStore) - - iter := cachedBase.Iterator(nil, nil) - for ; iter.Valid(); iter.Next() { - ds.baseStore.Set(iter.Key(), iter.Value()) - } - iter = cachedIavl.Iterator(nil, nil) - for ; iter.Valid(); iter.Next() { - ds.iavlStore.Set(iter.Key(), iter.Value()) - } - - ss.cacheTypes.Iterate()(func(k TypeID, v Type) bool { - ds.cacheTypes.Set(k, v) - return true - }) - ss.cacheNodes.Iterate()(func(k Location, v BlockNode) bool { - ds.cacheNodes.Set(k, v) - return true - }) +func CopyCachesFromStore(dst, src Store) { + ds, ss := dst.(*defaultStore), src.(*defaultStore) + ds.cacheObjects = maps.Clone(ss.cacheObjects) + ds.cacheTypes = maps.Clone(ss.cacheTypes) + ds.cacheNodes = maps.Clone(ss.cacheNodes) } func (ds *defaultStore) GetAllocator() *Allocator { @@ -504,6 +399,7 @@ func (ds *defaultStore) DelObject(oo Object) { func (ds *defaultStore) GetType(tid TypeID) Type { tt := ds.GetTypeSafe(tid) if tt == nil { + ds.Print() panic(fmt.Sprintf("unexpected type with id %s", tid.String())) } return tt @@ -511,7 +407,7 @@ func (ds *defaultStore) GetType(tid TypeID) Type { func (ds *defaultStore) GetTypeSafe(tid TypeID) Type { // check cache. - if tt, exists := ds.cacheTypes.Get(tid); exists { + if tt, exists := ds.cacheTypes[tid]; exists { return tt } // check backend. @@ -528,7 +424,7 @@ func (ds *defaultStore) GetTypeSafe(tid TypeID) Type { } } // set in cache. - ds.cacheTypes.Set(tid, tt) + ds.cacheTypes[tid] = tt // after setting in cache, fill tt. fillType(ds, tt) return tt @@ -539,7 +435,7 @@ func (ds *defaultStore) GetTypeSafe(tid TypeID) Type { func (ds *defaultStore) SetCacheType(tt Type) { tid := tt.TypeID() - if tt2, exists := ds.cacheTypes.Get(tid); exists { + if tt2, exists := ds.cacheTypes[tid]; exists { if tt != tt2 { // NOTE: not sure why this would happen. panic("should not happen") @@ -547,14 +443,14 @@ func (ds *defaultStore) SetCacheType(tt Type) { // already set. } } else { - ds.cacheTypes.Set(tid, tt) + ds.cacheTypes[tid] = tt } } func (ds *defaultStore) SetType(tt Type) { tid := tt.TypeID() // return if tid already known. - if tt2, exists := ds.cacheTypes.Get(tid); exists { + if tt2, exists := ds.cacheTypes[tid]; exists { if tt != tt2 { // this can happen for a variety of reasons. // TODO classify them and optimize. @@ -569,7 +465,7 @@ func (ds *defaultStore) SetType(tt Type) { ds.baseStore.Set([]byte(key), bz) } // save type to cache. - ds.cacheTypes.Set(tid, tt) + ds.cacheTypes[tid] = tt } func (ds *defaultStore) GetBlockNode(loc Location) BlockNode { @@ -582,7 +478,7 @@ func (ds *defaultStore) GetBlockNode(loc Location) BlockNode { func (ds *defaultStore) GetBlockNodeSafe(loc Location) BlockNode { // check cache. - if bn, exists := ds.cacheNodes.Get(loc); exists { + if bn, exists := ds.cacheNodes[loc]; exists { return bn } // check backend. @@ -598,7 +494,7 @@ func (ds *defaultStore) GetBlockNodeSafe(loc Location) BlockNode { loc, bn.GetLocation())) } } - ds.cacheNodes.Set(loc, bn) + ds.cacheNodes[loc] = bn return bn } } @@ -617,7 +513,7 @@ func (ds *defaultStore) SetBlockNode(bn BlockNode) { // ds.backend.Set([]byte(key), bz) } // save node to cache. - ds.cacheNodes.Set(loc, bn) + ds.cacheNodes[loc] = bn // XXX duplicate? // XXX } @@ -686,7 +582,6 @@ func (ds *defaultStore) getMemPackage(path string, isRetry bool) *std.MemPackage } return nil } - var memPkg *std.MemPackage amino.MustUnmarshal(bz, &memPkg) return memPkg @@ -742,6 +637,47 @@ func (ds *defaultStore) ClearObjectCache() { ds.SetCachePackage(Uverse()) } +// Unstable. +// This function is used to handle queries and checktx transactions. +func (ds *defaultStore) Fork() Store { + ds2 := &defaultStore{ + alloc: ds.alloc.Fork().Reset(), + + // Re-initialize caches. Some are cloned for speed. + cacheObjects: make(map[ObjectID]Object), + cacheTypes: maps.Clone(ds.cacheTypes), + // XXX: This is bad to say the least (ds.cacheNodes is shared with a + // child Store); however, cacheNodes is _not_ a cache, but a proper + // data store instead. SetBlockNode does not write anything to + // the underlying baseStore, and cloning this map makes everything run + // 4x slower, so here we are, copying the reference. + cacheNodes: ds.cacheNodes, + cacheNativeTypes: maps.Clone(ds.cacheNativeTypes), + + // baseStore and iavlStore should generally be changed using SwapStores. + baseStore: ds.baseStore, + iavlStore: ds.iavlStore, + + // native injections / store "config" + pkgGetter: ds.pkgGetter, + pkgInjector: ds.pkgInjector, + nativeStore: ds.nativeStore, + go2gnoStrict: ds.go2gnoStrict, + + // reset opslog and current. + opslog: nil, + current: nil, + } + ds2.SetCachePackage(Uverse()) + return ds2 +} + +// TODO: consider a better/faster/simpler way of achieving the overall same goal? +func (ds *defaultStore) SwapStores(baseStore, iavlStore store.Store) { + ds.baseStore = baseStore + ds.iavlStore = iavlStore +} + func (ds *defaultStore) SetPackageInjector(inj PackageInjector) { ds.pkgInjector = inj } @@ -757,6 +693,18 @@ func (ds *defaultStore) GetNative(pkgPath string, name Name) func(m *Machine) { return nil } +// Writes one level of cache to store. +func (ds *defaultStore) Write() { + ds.baseStore.(types.Writer).Write() + ds.iavlStore.(types.Writer).Write() +} + +// Flush cached writes to disk. +func (ds *defaultStore) Flush() { + ds.baseStore.(types.Flusher).Flush() + ds.iavlStore.(types.Flusher).Flush() +} + // ---------------------------------------- // StoreOp @@ -827,8 +775,8 @@ func (ds *defaultStore) LogSwitchRealm(rlmpath string) { func (ds *defaultStore) ClearCache() { ds.cacheObjects = make(map[ObjectID]Object) - ds.cacheTypes = txlog.GoMap[TypeID, Type](map[TypeID]Type{}) - ds.cacheNodes = txlog.GoMap[Location, BlockNode](map[Location]BlockNode{}) + ds.cacheTypes = make(map[TypeID]Type) + ds.cacheNodes = make(map[Location]BlockNode) ds.cacheNativeTypes = make(map[reflect.Type]Type) // restore builtin types to cache. InitStoreCaches(ds) @@ -844,18 +792,16 @@ func (ds *defaultStore) Print() { utils.Print(ds.iavlStore) fmt.Println(colors.Yellow("//----------------------------------------")) fmt.Println(colors.Green("defaultStore:cacheTypes...")) - ds.cacheTypes.Iterate()(func(tid TypeID, typ Type) bool { + for tid, typ := range ds.cacheTypes { fmt.Printf("- %v: %v\n", tid, stringz.TrimN(fmt.Sprintf("%v", typ), 50)) - return true - }) + } fmt.Println(colors.Yellow("//----------------------------------------")) fmt.Println(colors.Green("defaultStore:cacheNodes...")) - ds.cacheNodes.Iterate()(func(loc Location, bn BlockNode) bool { + for loc, bn := range ds.cacheNodes { fmt.Printf("- %v: %v\n", loc, stringz.TrimN(fmt.Sprintf("%v", bn), 50)) - return true - }) + } fmt.Println(colors.Red("//----------------------------------------")) } diff --git a/gnovm/pkg/gnolang/store_test.go b/gnovm/pkg/gnolang/store_test.go deleted file mode 100644 index 8114291d1b6..00000000000 --- a/gnovm/pkg/gnolang/store_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package gnolang - -import ( - "io" - "testing" - - "github.com/gnolang/gno/tm2/pkg/db/memdb" - "github.com/gnolang/gno/tm2/pkg/std" - "github.com/gnolang/gno/tm2/pkg/store/dbadapter" - storetypes "github.com/gnolang/gno/tm2/pkg/store/types" - "github.com/stretchr/testify/assert" -) - -func TestTransactionStore(t *testing.T) { - db := memdb.NewMemDB() - tm2Store := dbadapter.StoreConstructor(db, storetypes.StoreOptions{}) - - st := NewStore(nil, tm2Store, tm2Store) - wrappedTm2Store := tm2Store.CacheWrap() - txSt := st.BeginTransaction(wrappedTm2Store, wrappedTm2Store) - m := NewMachineWithOptions(MachineOptions{ - PkgPath: "hello", - Store: txSt, - Output: io.Discard, - }) - _, pv := m.RunMemPackage(&std.MemPackage{ - Name: "hello", - Path: "hello", - Files: []*std.MemFile{ - {Name: "hello.gno", Body: "package hello; func main() { println(A(11)); }; type A int"}, - }, - }, true) - m.SetActivePackage(pv) - m.RunMain() - - // mem package should only exist in txSt - // (check both memPackage and types - one is stored directly in the db, - // the other uses txlog) - assert.Nil(t, st.GetMemPackage("hello")) - assert.NotNil(t, txSt.GetMemPackage("hello")) - assert.PanicsWithValue(t, "unexpected type with id hello.A", func() { st.GetType("hello.A") }) - assert.NotNil(t, txSt.GetType("hello.A")) - - // use write on the stores - txSt.Write() - wrappedTm2Store.Write() - - // mem package should exist and be ==. - res := st.GetMemPackage("hello") - assert.NotNil(t, res) - assert.Equal(t, txSt.GetMemPackage("hello"), res) - helloA := st.GetType("hello.A") - assert.NotNil(t, helloA) - assert.Equal(t, txSt.GetType("hello.A"), helloA) -} - -func TestTransactionStore_blockedMethods(t *testing.T) { - // These methods should panic as they modify store settings, which should - // only be changed in the root store. - assert.Panics(t, func() { transactionStore{}.SetPackageGetter(nil) }) - assert.Panics(t, func() { transactionStore{}.ClearCache() }) - assert.Panics(t, func() { transactionStore{}.SetPackageInjector(nil) }) - assert.Panics(t, func() { transactionStore{}.SetNativeStore(nil) }) - assert.Panics(t, func() { transactionStore{}.SetStrictGo2GnoMapping(false) }) -} - -func TestCopyFromCachedStore(t *testing.T) { - // Create cached store, with a type and a mempackage. - c1 := memdb.NewMemDB() - c1s := dbadapter.StoreConstructor(c1, storetypes.StoreOptions{}) - c2 := memdb.NewMemDB() - c2s := dbadapter.StoreConstructor(c2, storetypes.StoreOptions{}) - cachedStore := NewStore(nil, c1s, c2s) - cachedStore.SetType(&DeclaredType{ - PkgPath: "io", - Name: "Reader", - Base: BoolType, - }) - cachedStore.AddMemPackage(&std.MemPackage{ - Name: "math", - Path: "math", - Files: []*std.MemFile{ - {Name: "math.gno", Body: "package math"}, - }, - }) - - // Create dest store and copy. - d1, d2 := memdb.NewMemDB(), memdb.NewMemDB() - d1s := dbadapter.StoreConstructor(d1, storetypes.StoreOptions{}) - d2s := dbadapter.StoreConstructor(d2, storetypes.StoreOptions{}) - destStore := NewStore(nil, d1s, d2s) - destStoreTx := destStore.BeginTransaction(nil, nil) // CopyFromCachedStore requires a tx store. - CopyFromCachedStore(destStoreTx, cachedStore, c1s, c2s) - destStoreTx.Write() - - assert.Equal(t, c1, d1, "cached baseStore and dest baseStore should match") - assert.Equal(t, c2, d2, "cached iavlStore and dest iavlStore should match") - assert.Equal(t, cachedStore.cacheTypes, destStore.cacheTypes, "cacheTypes should match") -} diff --git a/gnovm/pkg/gnolang/uverse.go b/gnovm/pkg/gnolang/uverse.go index d62d4228d68..880a75396ca 100644 --- a/gnovm/pkg/gnolang/uverse.go +++ b/gnovm/pkg/gnolang/uverse.go @@ -193,32 +193,32 @@ func UverseNode() *PackageNode { return } else if arg0Type.Elem().Kind() == Uint8Kind { // append(nil, *SliceValue) new data bytes --- - arrayValue := m.Alloc.NewDataArray(arg1Length) + data := make([]byte, arg1Length) if arg1Base.Data == nil { copyListToData( - arrayValue.Data[:arg1Length], + data[:arg1Length], arg1Base.List[arg1Offset:arg1EndIndex]) } else { copy( - arrayValue.Data[:arg1Length], + data[:arg1Length], arg1Base.Data[arg1Offset:arg1EndIndex]) } m.PushValue(TypedValue{ T: arg0Type, - V: m.Alloc.NewSlice(arrayValue, 0, arg1Length, arg1Length), + V: m.Alloc.NewSliceFromData(data), }) return } else { // append(nil, *SliceValue) new list --------- - arrayValue := m.Alloc.NewListArray(arg1Length) - if arg1Length > 0 { + list := make([]TypedValue, arg1Length) + if 0 < arg1Length { for i := 0; i < arg1Length; i++ { - arrayValue.List[i] = arg1Base.List[arg1Offset+i].unrefCopy(m.Alloc, m.Store) + list[i] = arg1Base.List[arg1Offset+i].unrefCopy(m.Alloc, m.Store) } } m.PushValue(TypedValue{ T: arg0Type, - V: m.Alloc.NewSlice(arrayValue, 0, arg1Length, arg1Length), + V: m.Alloc.NewSliceFromList(list), }) return } @@ -236,27 +236,27 @@ func UverseNode() *PackageNode { return } else if arg0Type.Elem().Kind() == Uint8Kind { // append(nil, *NativeValue) new data bytes -- - arrayValue := m.Alloc.NewDataArray(arg1NativeValueLength) + data := make([]byte, arg1NativeValueLength) copyNativeToData( - arrayValue.Data[:arg1NativeValueLength], + data[:arg1NativeValueLength], arg1NativeValue, arg1NativeValueLength) m.PushValue(TypedValue{ T: arg0Type, - V: m.Alloc.NewSlice(arrayValue, 0, arg1NativeValueLength, arg1NativeValueLength), + V: m.Alloc.NewSliceFromData(data), }) return } else { // append(nil, *NativeValue) new list -------- - arrayValue := m.Alloc.NewListArray(arg1NativeValueLength) - if arg1NativeValueLength > 0 { + list := make([]TypedValue, arg1NativeValueLength) + if 0 < arg1NativeValueLength { copyNativeToList( m.Alloc, - arrayValue.List[:arg1NativeValueLength], + list[:arg1NativeValueLength], arg1NativeValue, arg1NativeValueLength) } m.PushValue(TypedValue{ T: arg0Type, - V: m.Alloc.NewSlice(arrayValue, 0, arg1NativeValueLength, arg1NativeValueLength), + V: m.Alloc.NewSliceFromList(list), }) return } @@ -344,57 +344,55 @@ func UverseNode() *PackageNode { } } else if arg0Type.Elem().Kind() == Uint8Kind { // append(*SliceValue, *SliceValue) new data bytes --- - newLength := arg0Length + arg1Length - arrayValue := m.Alloc.NewDataArray(newLength) + data := make([]byte, arg0Length+arg1Length) if 0 < arg0Length { if arg0Base.Data == nil { copyListToData( - arrayValue.Data[:arg0Length], + data[:arg0Length], arg0Base.List[arg0Offset:arg0Offset+arg0Length]) } else { copy( - arrayValue.Data[:arg0Length], + data[:arg0Length], arg0Base.Data[arg0Offset:arg0Offset+arg0Length]) } } if 0 < arg1Length { if arg1Base.Data == nil { copyListToData( - arrayValue.Data[arg0Length:newLength], + data[arg0Length:arg0Length+arg1Length], arg1Base.List[arg1Offset:arg1Offset+arg1Length]) } else { copy( - arrayValue.Data[arg0Length:newLength], + data[arg0Length:arg0Length+arg1Length], arg1Base.Data[arg1Offset:arg1Offset+arg1Length]) } } m.PushValue(TypedValue{ T: arg0Type, - V: m.Alloc.NewSlice(arrayValue, 0, newLength, newLength), + V: m.Alloc.NewSliceFromData(data), }) return } else { // append(*SliceValue, *SliceValue) new list --------- - arrayLen := arg0Length + arg1Length - arrayValue := m.Alloc.NewListArray(arrayLen) - if arg0Length > 0 { + list := make([]TypedValue, arg0Length+arg1Length) + if 0 < arg0Length { if arg0Base.Data == nil { for i := 0; i < arg0Length; i++ { - arrayValue.List[i] = arg0Base.List[arg0Offset+i].unrefCopy(m.Alloc, m.Store) + list[i] = arg0Base.List[arg0Offset+i].unrefCopy(m.Alloc, m.Store) } } else { panic("should not happen") } } - if arg1Length > 0 { + if 0 < arg1Length { if arg1Base.Data == nil { for i := 0; i < arg1Length; i++ { - arrayValue.List[arg0Length+i] = arg1Base.List[arg1Offset+i].unrefCopy(m.Alloc, m.Store) + list[arg0Length+i] = arg1Base.List[arg1Offset+i].unrefCopy(m.Alloc, m.Store) } } else { copyDataToList( - arrayValue.List[arg0Length:arg0Length+arg1Length], + list[arg0Length:arg0Length+arg1Length], arg1Base.Data[arg1Offset:arg1Offset+arg1Length], arg1Type.Elem(), ) @@ -402,7 +400,7 @@ func UverseNode() *PackageNode { } m.PushValue(TypedValue{ T: arg0Type, - V: m.Alloc.NewSlice(arrayValue, 0, arrayLen, arrayLen), + V: m.Alloc.NewSliceFromList(list), }) return } @@ -443,47 +441,46 @@ func UverseNode() *PackageNode { } } else if arg0Type.Elem().Kind() == Uint8Kind { // append(*SliceValue, *NativeValue) new data bytes -- - newLength := arg0Length + arg1NativeValueLength - arrayValue := m.Alloc.NewDataArray(newLength) + data := make([]byte, arg0Length+arg1NativeValueLength) if 0 < arg0Length { if arg0Base.Data == nil { copyListToData( - arrayValue.Data[:arg0Length], + data[:arg0Length], arg0Base.List[arg0Offset:arg0Offset+arg0Length]) } else { copy( - arrayValue.Data[:arg0Length], + data[:arg0Length], arg0Base.Data[arg0Offset:arg0Offset+arg0Length]) } } if 0 < arg1NativeValueLength { copyNativeToData( - arrayValue.Data[arg0Length:newLength], + data[arg0Length:arg0Length+arg1NativeValueLength], arg1NativeValue, arg1NativeValueLength) } m.PushValue(TypedValue{ T: arg0Type, - V: m.Alloc.NewSlice(arrayValue, 0, newLength, newLength), + V: m.Alloc.NewSliceFromData(data), }) return } else { // append(*SliceValue, *NativeValue) new list -------- listLen := arg0Length + arg1NativeValueLength - arrayValue := m.Alloc.NewListArray(listLen) + list := make([]TypedValue, listLen) if 0 < arg0Length { for i := 0; i < listLen; i++ { - arrayValue.List[i] = arg0Base.List[arg0Offset+i].unrefCopy(m.Alloc, m.Store) + list[i] = arg0Base.List[arg0Offset+i].unrefCopy(m.Alloc, m.Store) } } if 0 < arg1NativeValueLength { copyNativeToList( m.Alloc, - arrayValue.List[arg0Length:listLen], + list[arg0Length:listLen], arg1NativeValue, arg1NativeValueLength) } m.PushValue(TypedValue{ T: arg0Type, - V: m.Alloc.NewSlice(arrayValue, 0, listLen, listLen), + V: m.Alloc.NewSliceFromList(list), }) return } @@ -782,25 +779,25 @@ func UverseNode() *PackageNode { lv := vargs.TV.GetPointerAtIndexInt(m.Store, 0).Deref() li := lv.ConvertGetInt() if et.Kind() == Uint8Kind { - arrayValue := m.Alloc.NewDataArray(li) + data := make([]byte, li) m.PushValue(TypedValue{ T: tt, - V: m.Alloc.NewSlice(arrayValue, 0, li, li), + V: m.Alloc.NewSliceFromData(data), }) return } else { - arrayValue := m.Alloc.NewListArray(li) + list := make([]TypedValue, li) if et.Kind() == InterfaceKind { // leave as is } else { // init zero elements with concrete type. for i := 0; i < li; i++ { - arrayValue.List[i] = defaultTypedValue(m.Alloc, et) + list[i] = defaultTypedValue(m.Alloc, et) } } m.PushValue(TypedValue{ T: tt, - V: m.Alloc.NewSlice(arrayValue, 0, li, li), + V: m.Alloc.NewSliceFromList(list), }) return } @@ -810,37 +807,30 @@ func UverseNode() *PackageNode { cv := vargs.TV.GetPointerAtIndexInt(m.Store, 1).Deref() ci := cv.ConvertGetInt() if et.Kind() == Uint8Kind { - arrayValue := m.Alloc.NewDataArray(ci) + data := make([]byte, li, ci) m.PushValue(TypedValue{ T: tt, - V: m.Alloc.NewSlice(arrayValue, 0, li, ci), + V: m.Alloc.NewSliceFromData(data), }) return } else { - arrayValue := m.Alloc.NewListArray(ci) + list := make([]TypedValue, li, ci) if et := bt.Elem(); et.Kind() == InterfaceKind { // leave as is } else { - // Initialize all elements within capacity with default - // type values. These need to be initialized because future - // slice operations could get messy otherwise. Simple capacity - // expansions like `a = a[:cap(a)]` would make it trivial to - // initialize zero values at the time of the slice operation. - // But sequences of operations like: - // a := make([]int, 1, 10) - // a = a[7:cap(a)] - // a = a[3:5] - // - // require a bit more work to handle correctly, requiring that - // all new TypedValue slice elements be checked to ensure they have - // a value for every slice operation, which is not desirable. + // init zero elements with concrete type. + // the elements beyond len l within cap c + // must also be initialized, for a future + // slice operation may refer to them. + // XXX can this be removed? + list2 := list[:ci] for i := 0; i < ci; i++ { - arrayValue.List[i] = defaultTypedValue(m.Alloc, et) + list2[i] = defaultTypedValue(m.Alloc, et) } } m.PushValue(TypedValue{ T: tt, - V: m.Alloc.NewSlice(arrayValue, 0, li, ci), + V: m.Alloc.NewSliceFromList(list), }) return } @@ -938,7 +928,17 @@ func UverseNode() *PackageNode { return }, ) - // NOTE: panic is its own statement type, and is not defined as a function. + defNative("panic", + Flds( // params + "err", AnyT(), // args[0] + ), + nil, // results + func(m *Machine) { + arg0 := m.LastBlock().GetParams1() + xv := arg0.Deref() + panic(xv.Sprint(m)) + }, + ) defNative("print", Flds( // params "xs", Vrd(AnyT()), // args[0] diff --git a/gnovm/pkg/gnolang/uverse_test.go b/gnovm/pkg/gnolang/uverse_test.go index 76961b70ccb..7a6c0567e45 100644 --- a/gnovm/pkg/gnolang/uverse_test.go +++ b/gnovm/pkg/gnolang/uverse_test.go @@ -4,14 +4,14 @@ import ( "testing" ) -type uverseTestCases struct { +type printlnTestCases struct { name string code string expected string } func TestIssue1337PrintNilSliceAsUndefined(t *testing.T) { - test := []uverseTestCases{ + test := []printlnTestCases{ { name: "print empty slice", code: `package test diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index bbf77bf19c7..5da7c15bb05 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -2125,18 +2125,13 @@ func (tv *TypedValue) GetLength() int { switch bt := baseOf(tv.T).(type) { case PrimitiveType: if bt != StringType { - panic(fmt.Sprintf("unexpected type for len(): %s", tv.T.String())) + panic("should not happen") } return 0 case *ArrayType: return bt.Len case *SliceType: return 0 - case *PointerType: - if at, ok := bt.Elt.(*ArrayType); ok { - return at.Len - } - panic(fmt.Sprintf("unexpected type for len(): %s", tv.T.String())) default: panic(fmt.Sprintf( "unexpected type for len(): %s", @@ -2154,11 +2149,6 @@ func (tv *TypedValue) GetLength() int { return cv.GetLength() case *NativeValue: return cv.Value.Len() - case PointerValue: - if av, ok := cv.TV.V.(*ArrayValue); ok { - return av.GetLength() - } - panic(fmt.Sprintf("unexpected type for len(): %s", tv.T.String())) default: panic(fmt.Sprintf("unexpected type for len(): %s", tv.T.String())) @@ -2167,34 +2157,27 @@ func (tv *TypedValue) GetLength() int { func (tv *TypedValue) GetCapacity() int { if tv.V == nil { - // assert acceptable type. - switch bt := baseOf(tv.T).(type) { - // strings have no capacity. - case *ArrayType: - return bt.Len - case *SliceType: - return 0 - case *PointerType: - if at, ok := bt.Elt.(*ArrayType); ok { - return at.Len + if debug { + // assert acceptable type. + switch baseOf(tv.T).(type) { + // strings have no capacity. + case *ArrayType: + case *SliceType: + default: + panic("should not happen") } - panic(fmt.Sprintf("unexpected type for cap(): %s", tv.T.String())) - default: - panic(fmt.Sprintf("unexpected type for cap(): %s", tv.T.String())) } + return 0 } switch cv := tv.V.(type) { + case StringValue: + return len(string(cv)) case *ArrayValue: return cv.GetCapacity() case *SliceValue: return cv.GetCapacity() case *NativeValue: return cv.Value.Cap() - case PointerValue: - if av, ok := cv.TV.V.(*ArrayValue); ok { - return av.GetCapacity() - } - panic(fmt.Sprintf("unexpected type for cap(): %s", tv.T.String())) default: panic(fmt.Sprintf("unexpected type for cap(): %s", tv.T.String())) @@ -2217,13 +2200,13 @@ func (tv *TypedValue) GetSlice(alloc *Allocator, low, high int) TypedValue { "invalid slice index %d > %d", low, high)) } + if tv.GetCapacity() < high { + panic(fmt.Sprintf( + "slice bounds out of range [%d:%d] with capacity %d", + low, high, tv.GetCapacity())) + } switch t := baseOf(tv.T).(type) { case PrimitiveType: - if tv.GetLength() < high { - panic(fmt.Sprintf( - "slice bounds out of range [%d:%d] with string length %d", - low, high, tv.GetLength())) - } if t == StringType || t == UntypedStringType { return TypedValue{ T: tv.T, @@ -2232,11 +2215,6 @@ func (tv *TypedValue) GetSlice(alloc *Allocator, low, high int) TypedValue { } panic("non-string primitive type cannot be sliced") case *ArrayType: - if tv.GetLength() < high { - panic(fmt.Sprintf( - "slice bounds out of range [%d:%d] with array length %d", - low, high, tv.GetLength())) - } av := tv.V.(*ArrayValue) st := alloc.NewType(&SliceType{ Elt: t.Elt, @@ -2252,11 +2230,6 @@ func (tv *TypedValue) GetSlice(alloc *Allocator, low, high int) TypedValue { ), } case *SliceType: - if tv.GetCapacity() < high { - panic(fmt.Sprintf( - "slice bounds out of range [%d:%d] with capacity %d", - low, high, tv.GetCapacity())) - } if tv.V == nil { if low != 0 || high != 0 { panic("nil slice index out of range") diff --git a/gnovm/pkg/gnolang/values_string.go b/gnovm/pkg/gnolang/values_string.go index a414f440e4e..204fab62c86 100644 --- a/gnovm/pkg/gnolang/values_string.go +++ b/gnovm/pkg/gnolang/values_string.go @@ -170,9 +170,6 @@ func (fv *FuncValue) String() string { if fv.Type == nil { return fmt.Sprintf("incomplete-func ?%s(?)?", name) } - if name == "" { - return fmt.Sprintf("%s{...}", fv.Type.String()) - } return name } diff --git a/gnovm/pkg/gnolang/values_test.go b/gnovm/pkg/gnolang/values_test.go deleted file mode 100644 index ce6edd0a2f9..00000000000 --- a/gnovm/pkg/gnolang/values_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package gnolang - -import ( - "fmt" - "testing" -) - -type mockTypedValueStruct struct { - field int -} - -func (m *mockTypedValueStruct) assertValue() {} - -func (m *mockTypedValueStruct) String() string { - return fmt.Sprintf("MockTypedValueStruct(%d)", m.field) -} - -func TestGetLengthPanic(t *testing.T) { - tests := []struct { - name string - tv TypedValue - expected string - }{ - { - name: "NonArrayPointer", - tv: TypedValue{ - T: &PointerType{Elt: &StructType{}}, - V: PointerValue{ - TV: &TypedValue{ - T: &StructType{}, - V: &mockTypedValueStruct{field: 42}, - }, - }, - }, - expected: "unexpected type for len(): *struct{}", - }, - { - name: "UnexpectedType", - tv: TypedValue{ - T: &StructType{}, - V: &mockTypedValueStruct{field: 42}, - }, - expected: "unexpected type for len(): struct{}", - }, - { - name: "UnexpectedPointerType", - tv: TypedValue{ - T: &PointerType{Elt: &StructType{}}, - V: nil, - }, - expected: "unexpected type for len(): *struct{}", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("the code did not panic") - } else { - if r != tt.expected { - t.Errorf("expected panic message to be %q, got %q", tt.expected, r) - } - } - }() - - tt.tv.GetLength() - }) - } -} diff --git a/gnovm/stdlibs/math/all_test.gno b/gnovm/stdlibs/math/all_test.gno deleted file mode 100644 index a138123b5ab..00000000000 --- a/gnovm/stdlibs/math/all_test.gno +++ /dev/null @@ -1,4027 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math_test - -import ( - "fmt" - "math" - "testing" -) - -// XXX: The dot import for "math" is replaced to a normal import. -// As such, all calls to export math functions are prefixed with math (as opposed -// to the original all_test.gno). - -var vf = []float64{ - 4.9790119248836735e+00, - 7.7388724745781045e+00, - -2.7688005719200159e-01, - -5.0106036182710749e+00, - 9.6362937071984173e+00, - 2.9263772392439646e+00, - 5.2290834314593066e+00, - 2.7279399104360102e+00, - 1.8253080916808550e+00, - -8.6859247685756013e+00, -} - -// The expected results below were computed by the high precision calculators -// at https://keisan.casio.com/. More exact input values (array vf[], above) -// were obtained by printing them with "%.26f". The answers were calculated -// to 26 digits (by using the "Digit number" drop-down control of each -// calculator). -var acos = []float64{ - 1.0496193546107222142571536e+00, - 6.8584012813664425171660692e-01, - 1.5984878714577160325521819e+00, - 2.0956199361475859327461799e+00, - 2.7053008467824138592616927e-01, - 1.2738121680361776018155625e+00, - 1.0205369421140629186287407e+00, - 1.2945003481781246062157835e+00, - 1.3872364345374451433846657e+00, - 2.6231510803970463967294145e+00, -} - -var acosh = []float64{ - 2.4743347004159012494457618e+00, - 2.8576385344292769649802701e+00, - 7.2796961502981066190593175e-01, - 2.4796794418831451156471977e+00, - 3.0552020742306061857212962e+00, - 2.044238592688586588942468e+00, - 2.5158701513104513595766636e+00, - 1.99050839282411638174299e+00, - 1.6988625798424034227205445e+00, - 2.9611454842470387925531875e+00, -} - -var asin = []float64{ - 5.2117697218417440497416805e-01, - 8.8495619865825236751471477e-01, - -02.769154466281941332086016e-02, - -5.2482360935268931351485822e-01, - 1.3002662421166552333051524e+00, - 2.9698415875871901741575922e-01, - 5.5025938468083370060258102e-01, - 2.7629597861677201301553823e-01, - 1.83559892257451475846656e-01, - -1.0523547536021497774980928e+00, -} - -var asinh = []float64{ - 2.3083139124923523427628243e+00, - 2.743551594301593620039021e+00, - -2.7345908534880091229413487e-01, - -2.3145157644718338650499085e+00, - 2.9613652154015058521951083e+00, - 1.7949041616585821933067568e+00, - 2.3564032905983506405561554e+00, - 1.7287118790768438878045346e+00, - 1.3626658083714826013073193e+00, - -2.8581483626513914445234004e+00, -} - -var atan = []float64{ - 1.372590262129621651920085e+00, - 1.442290609645298083020664e+00, - -2.7011324359471758245192595e-01, - -1.3738077684543379452781531e+00, - 1.4673921193587666049154681e+00, - 1.2415173565870168649117764e+00, - 1.3818396865615168979966498e+00, - 1.2194305844639670701091426e+00, - 1.0696031952318783760193244e+00, - -1.4561721938838084990898679e+00, -} - -var atanh = []float64{ - 5.4651163712251938116878204e-01, - 1.0299474112843111224914709e+00, - -2.7695084420740135145234906e-02, - -5.5072096119207195480202529e-01, - 1.9943940993171843235906642e+00, - 3.01448604578089708203017e-01, - 5.8033427206942188834370595e-01, - 2.7987997499441511013958297e-01, - 1.8459947964298794318714228e-01, - -1.3273186910532645867272502e+00, -} - -var atan2 = []float64{ - 1.1088291730037004444527075e+00, - 9.1218183188715804018797795e-01, - 1.5984772603216203736068915e+00, - 2.0352918654092086637227327e+00, - 8.0391819139044720267356014e-01, - 1.2861075249894661588866752e+00, - 1.0889904479131695712182587e+00, - 1.3044821793397925293797357e+00, - 1.3902530903455392306872261e+00, - 2.2859857424479142655411058e+00, -} - -var cbrt = []float64{ - 1.7075799841925094446722675e+00, - 1.9779982212970353936691498e+00, - -6.5177429017779910853339447e-01, - -1.7111838886544019873338113e+00, - 2.1279920909827937423960472e+00, - 1.4303536770460741452312367e+00, - 1.7357021059106154902341052e+00, - 1.3972633462554328350552916e+00, - 1.2221149580905388454977636e+00, - -2.0556003730500069110343596e+00, -} - -var ceil = []float64{ - 5.0000000000000000e+00, - 8.0000000000000000e+00, - math.Copysign(0, -1), - -5.0000000000000000e+00, - 1.0000000000000000e+01, - 3.0000000000000000e+00, - 6.0000000000000000e+00, - 3.0000000000000000e+00, - 2.0000000000000000e+00, - -8.0000000000000000e+00, -} - -var copysign = []float64{ - -4.9790119248836735e+00, - -7.7388724745781045e+00, - -2.7688005719200159e-01, - -5.0106036182710749e+00, - -9.6362937071984173e+00, - -2.9263772392439646e+00, - -5.2290834314593066e+00, - -2.7279399104360102e+00, - -1.8253080916808550e+00, - -8.6859247685756013e+00, -} - -var cos = []float64{ - 2.634752140995199110787593e-01, - 1.148551260848219865642039e-01, - 9.6191297325640768154550453e-01, - 2.938141150061714816890637e-01, - -9.777138189897924126294461e-01, - -9.7693041344303219127199518e-01, - 4.940088096948647263961162e-01, - -9.1565869021018925545016502e-01, - -2.517729313893103197176091e-01, - -7.39241351595676573201918e-01, -} - -// Results for 100000 * math.Pi + vf[i] -var cosLarge = []float64{ - 2.634752141185559426744e-01, - 1.14855126055543100712e-01, - 9.61912973266488928113e-01, - 2.9381411499556122552e-01, - -9.777138189880161924641e-01, - -9.76930413445147608049e-01, - 4.940088097314976789841e-01, - -9.15658690217517835002e-01, - -2.51772931436786954751e-01, - -7.3924135157173099849e-01, -} - -var cosh = []float64{ - 7.2668796942212842775517446e+01, - 1.1479413465659254502011135e+03, - 1.0385767908766418550935495e+00, - 7.5000957789658051428857788e+01, - 7.655246669605357888468613e+03, - 9.3567491758321272072888257e+00, - 9.331351599270605471131735e+01, - 7.6833430994624643209296404e+00, - 3.1829371625150718153881164e+00, - 2.9595059261916188501640911e+03, -} - -var erf = []float64{ - 5.1865354817738701906913566e-01, - 7.2623875834137295116929844e-01, - -3.123458688281309990629839e-02, - -5.2143121110253302920437013e-01, - 8.2704742671312902508629582e-01, - 3.2101767558376376743993945e-01, - 5.403990312223245516066252e-01, - 3.0034702916738588551174831e-01, - 2.0369924417882241241559589e-01, - -7.8069386968009226729944677e-01, -} - -var erfc = []float64{ - 4.8134645182261298093086434e-01, - 2.7376124165862704883070156e-01, - 1.0312345868828130999062984e+00, - 1.5214312111025330292043701e+00, - 1.7295257328687097491370418e-01, - 6.7898232441623623256006055e-01, - 4.596009687776754483933748e-01, - 6.9965297083261411448825169e-01, - 7.9630075582117758758440411e-01, - 1.7806938696800922672994468e+00, -} - -var erfinv = []float64{ - 4.746037673358033586786350696e-01, - 8.559054432692110956388764172e-01, - -2.45427830571707336251331946e-02, - -4.78116683518973366268905506e-01, - 1.479804430319470983648120853e+00, - 2.654485787128896161882650211e-01, - 5.027444534221520197823192493e-01, - 2.466703532707627818954585670e-01, - 1.632011465103005426240343116e-01, - -1.06672334642196900710000389e+00, -} - -var exp = []float64{ - 1.4533071302642137507696589e+02, - 2.2958822575694449002537581e+03, - 7.5814542574851666582042306e-01, - 6.6668778421791005061482264e-03, - 1.5310493273896033740861206e+04, - 1.8659907517999328638667732e+01, - 1.8662167355098714543942057e+02, - 1.5301332413189378961665788e+01, - 6.2047063430646876349125085e+00, - 1.6894712385826521111610438e-04, -} - -var expm1 = []float64{ - 5.105047796122957327384770212e-02, - 8.046199708567344080562675439e-02, - -2.764970978891639815187418703e-03, - -4.8871434888875355394330300273e-02, - 1.0115864277221467777117227494e-01, - 2.969616407795910726014621657e-02, - 5.368214487944892300914037972e-02, - 2.765488851131274068067445335e-02, - 1.842068661871398836913874273e-02, - -8.3193870863553801814961137573e-02, -} - -var expm1Large = []float64{ - 4.2031418113550844e+21, - 4.0690789717473863e+33, - -0.9372627915981363e+00, - -1.0, - 7.077694784145933e+41, - 5.117936223839153e+12, - 5.124137759001189e+22, - 7.03546003972584e+11, - 8.456921800389698e+07, - -1.0, -} - -var exp2 = []float64{ - 3.1537839463286288034313104e+01, - 2.1361549283756232296144849e+02, - 8.2537402562185562902577219e-01, - 3.1021158628740294833424229e-02, - 7.9581744110252191462569661e+02, - 7.6019905892596359262696423e+00, - 3.7506882048388096973183084e+01, - 6.6250893439173561733216375e+00, - 3.5438267900243941544605339e+00, - 2.4281533133513300984289196e-03, -} - -var fabs = []float64{ - 4.9790119248836735e+00, - 7.7388724745781045e+00, - 2.7688005719200159e-01, - 5.0106036182710749e+00, - 9.6362937071984173e+00, - 2.9263772392439646e+00, - 5.2290834314593066e+00, - 2.7279399104360102e+00, - 1.8253080916808550e+00, - 8.6859247685756013e+00, -} - -var fdim = []float64{ - 4.9790119248836735e+00, - 7.7388724745781045e+00, - 0.0000000000000000e+00, - 0.0000000000000000e+00, - 9.6362937071984173e+00, - 2.9263772392439646e+00, - 5.2290834314593066e+00, - 2.7279399104360102e+00, - 1.8253080916808550e+00, - 0.0000000000000000e+00, -} - -var floor = []float64{ - 4.0000000000000000e+00, - 7.0000000000000000e+00, - -1.0000000000000000e+00, - -6.0000000000000000e+00, - 9.0000000000000000e+00, - 2.0000000000000000e+00, - 5.0000000000000000e+00, - 2.0000000000000000e+00, - 1.0000000000000000e+00, - -9.0000000000000000e+00, -} - -var fmod = []float64{ - 4.197615023265299782906368e-02, - 2.261127525421895434476482e+00, - 3.231794108794261433104108e-02, - 4.989396381728925078391512e+00, - 3.637062928015826201999516e-01, - 1.220868282268106064236690e+00, - 4.770916568540693347699744e+00, - 1.816180268691969246219742e+00, - 8.734595415957246977711748e-01, - 1.314075231424398637614104e+00, -} - -type fi struct { - f float64 - i int -} - -var frexp = []fi{ - {6.2237649061045918750e-01, 3}, - {9.6735905932226306250e-01, 3}, - {-5.5376011438400318000e-01, -1}, - {-6.2632545228388436250e-01, 3}, - {6.02268356699901081250e-01, 4}, - {7.3159430981099115000e-01, 2}, - {6.5363542893241332500e-01, 3}, - {6.8198497760900255000e-01, 2}, - {9.1265404584042750000e-01, 1}, - {-5.4287029803597508250e-01, 4}, -} - -var gamma = []float64{ - 2.3254348370739963835386613898e+01, - 2.991153837155317076427529816e+03, - -4.561154336726758060575129109e+00, - 7.719403468842639065959210984e-01, - 1.6111876618855418534325755566e+05, - 1.8706575145216421164173224946e+00, - 3.4082787447257502836734201635e+01, - 1.579733951448952054898583387e+00, - 9.3834586598354592860187267089e-01, - -2.093995902923148389186189429e-05, -} - -var j0 = []float64{ - -1.8444682230601672018219338e-01, - 2.27353668906331975435892e-01, - 9.809259936157051116270273e-01, - -1.741170131426226587841181e-01, - -2.1389448451144143352039069e-01, - -2.340905848928038763337414e-01, - -1.0029099691890912094586326e-01, - -1.5466726714884328135358907e-01, - 3.252650187653420388714693e-01, - -8.72218484409407250005360235e-03, -} - -var j1 = []float64{ - -3.251526395295203422162967e-01, - 1.893581711430515718062564e-01, - -1.3711761352467242914491514e-01, - 3.287486536269617297529617e-01, - 1.3133899188830978473849215e-01, - 3.660243417832986825301766e-01, - -3.4436769271848174665420672e-01, - 4.329481396640773768835036e-01, - 5.8181350531954794639333955e-01, - -2.7030574577733036112996607e-01, -} - -var j2 = []float64{ - 5.3837518920137802565192769e-02, - -1.7841678003393207281244667e-01, - 9.521746934916464142495821e-03, - 4.28958355470987397983072e-02, - 2.4115371837854494725492872e-01, - 4.842458532394520316844449e-01, - -3.142145220618633390125946e-02, - 4.720849184745124761189957e-01, - 3.122312022520957042957497e-01, - 7.096213118930231185707277e-02, -} - -var jM3 = []float64{ - -3.684042080996403091021151e-01, - 2.8157665936340887268092661e-01, - 4.401005480841948348343589e-04, - 3.629926999056814081597135e-01, - 3.123672198825455192489266e-02, - -2.958805510589623607540455e-01, - -3.2033177696533233403289416e-01, - -2.592737332129663376736604e-01, - -1.0241334641061485092351251e-01, - -2.3762660886100206491674503e-01, -} - -var lgamma = []fi{ - {3.146492141244545774319734e+00, 1}, - {8.003414490659126375852113e+00, 1}, - {1.517575735509779707488106e+00, -1}, - {-2.588480028182145853558748e-01, 1}, - {1.1989897050205555002007985e+01, 1}, - {6.262899811091257519386906e-01, 1}, - {3.5287924899091566764846037e+00, 1}, - {4.5725644770161182299423372e-01, 1}, - {-6.363667087767961257654854e-02, 1}, - {-1.077385130910300066425564e+01, -1}, -} - -var log = []float64{ - 1.605231462693062999102599e+00, - 2.0462560018708770653153909e+00, - -1.2841708730962657801275038e+00, - 1.6115563905281545116286206e+00, - 2.2655365644872016636317461e+00, - 1.0737652208918379856272735e+00, - 1.6542360106073546632707956e+00, - 1.0035467127723465801264487e+00, - 6.0174879014578057187016475e-01, - 2.161703872847352815363655e+00, -} - -var logb = []float64{ - 2.0000000000000000e+00, - 2.0000000000000000e+00, - -2.0000000000000000e+00, - 2.0000000000000000e+00, - 3.0000000000000000e+00, - 1.0000000000000000e+00, - 2.0000000000000000e+00, - 1.0000000000000000e+00, - 0.0000000000000000e+00, - 3.0000000000000000e+00, -} - -var log10 = []float64{ - 6.9714316642508290997617083e-01, - 8.886776901739320576279124e-01, - -5.5770832400658929815908236e-01, - 6.998900476822994346229723e-01, - 9.8391002850684232013281033e-01, - 4.6633031029295153334285302e-01, - 7.1842557117242328821552533e-01, - 4.3583479968917773161304553e-01, - 2.6133617905227038228626834e-01, - 9.3881606348649405716214241e-01, -} - -var log1p = []float64{ - 4.8590257759797794104158205e-02, - 7.4540265965225865330849141e-02, - -2.7726407903942672823234024e-03, - -5.1404917651627649094953380e-02, - 9.1998280672258624681335010e-02, - 2.8843762576593352865894824e-02, - 5.0969534581863707268992645e-02, - 2.6913947602193238458458594e-02, - 1.8088493239630770262045333e-02, - -9.0865245631588989681559268e-02, -} - -var log2 = []float64{ - 2.3158594707062190618898251e+00, - 2.9521233862883917703341018e+00, - -1.8526669502700329984917062e+00, - 2.3249844127278861543568029e+00, - 3.268478366538305087466309e+00, - 1.5491157592596970278166492e+00, - 2.3865580889631732407886495e+00, - 1.447811865817085365540347e+00, - 8.6813999540425116282815557e-01, - 3.118679457227342224364709e+00, -} - -var modf = [][2]float64{ - {4.0000000000000000e+00, 9.7901192488367350108546816e-01}, - {7.0000000000000000e+00, 7.3887247457810456552351752e-01}, - {math.Copysign(0, -1), -2.7688005719200159404635997e-01}, - {-5.0000000000000000e+00, -1.060361827107492160848778e-02}, - {9.0000000000000000e+00, 6.3629370719841737980004837e-01}, - {2.0000000000000000e+00, 9.2637723924396464525443662e-01}, - {5.0000000000000000e+00, 2.2908343145930665230025625e-01}, - {2.0000000000000000e+00, 7.2793991043601025126008608e-01}, - {1.0000000000000000e+00, 8.2530809168085506044576505e-01}, - {-8.0000000000000000e+00, -6.8592476857560136238589621e-01}, -} - -var nextafter32 = []float32{ - 4.979012489318848e+00, - 7.738873004913330e+00, - -2.768800258636475e-01, - -5.010602951049805e+00, - 9.636294364929199e+00, - 2.926377534866333e+00, - 5.229084014892578e+00, - 2.727940082550049e+00, - 1.825308203697205e+00, - -8.685923576354980e+00, -} - -var nextafter64 = []float64{ - 4.97901192488367438926388786e+00, - 7.73887247457810545370193722e+00, - -2.7688005719200153853520874e-01, - -5.01060361827107403343006808e+00, - 9.63629370719841915615688777e+00, - 2.92637723924396508934364647e+00, - 5.22908343145930754047867595e+00, - 2.72793991043601069534929593e+00, - 1.82530809168085528249036997e+00, - -8.68592476857559958602905681e+00, -} - -var pow = []float64{ - 9.5282232631648411840742957e+04, - 5.4811599352999901232411871e+07, - 5.2859121715894396531132279e-01, - 9.7587991957286474464259698e-06, - 4.328064329346044846740467e+09, - 8.4406761805034547437659092e+02, - 1.6946633276191194947742146e+05, - 5.3449040147551939075312879e+02, - 6.688182138451414936380374e+01, - 2.0609869004248742886827439e-09, -} - -var remainder = []float64{ - 4.197615023265299782906368e-02, - 2.261127525421895434476482e+00, - 3.231794108794261433104108e-02, - -2.120723654214984321697556e-02, - 3.637062928015826201999516e-01, - 1.220868282268106064236690e+00, - -4.581668629186133046005125e-01, - -9.117596417440410050403443e-01, - 8.734595415957246977711748e-01, - 1.314075231424398637614104e+00, -} - -var round = []float64{ - 5, - 8, - math.Copysign(0, -1), - -5, - 10, - 3, - 5, - 3, - 2, - -9, -} - -var signbit = []bool{ - false, - false, - true, - true, - false, - false, - false, - false, - false, - true, -} - -var sin = []float64{ - -9.6466616586009283766724726e-01, - 9.9338225271646545763467022e-01, - -2.7335587039794393342449301e-01, - 9.5586257685042792878173752e-01, - -2.099421066779969164496634e-01, - 2.135578780799860532750616e-01, - -8.694568971167362743327708e-01, - 4.019566681155577786649878e-01, - 9.6778633541687993721617774e-01, - -6.734405869050344734943028e-01, -} - -// Results for 100000 * math.Pi + vf[i] -var sinLarge = []float64{ - -9.646661658548936063912e-01, - 9.933822527198506903752e-01, - -2.7335587036246899796e-01, - 9.55862576853689321268e-01, - -2.099421066862688873691e-01, - 2.13557878070308981163e-01, - -8.694568970959221300497e-01, - 4.01956668098863248917e-01, - 9.67786335404528727927e-01, - -6.7344058693131973066e-01, -} - -var sinh = []float64{ - 7.2661916084208532301448439e+01, - 1.1479409110035194500526446e+03, - -2.8043136512812518927312641e-01, - -7.499429091181587232835164e+01, - 7.6552466042906758523925934e+03, - 9.3031583421672014313789064e+00, - 9.330815755828109072810322e+01, - 7.6179893137269146407361477e+00, - 3.021769180549615819524392e+00, - -2.95950575724449499189888e+03, -} - -var sqrt = []float64{ - 2.2313699659365484748756904e+00, - 2.7818829009464263511285458e+00, - 5.2619393496314796848143251e-01, - 2.2384377628763938724244104e+00, - 3.1042380236055381099288487e+00, - 1.7106657298385224403917771e+00, - 2.286718922705479046148059e+00, - 1.6516476350711159636222979e+00, - 1.3510396336454586262419247e+00, - 2.9471892997524949215723329e+00, -} - -var tan = []float64{ - -3.661316565040227801781974e+00, - 8.64900232648597589369854e+00, - -2.8417941955033612725238097e-01, - 3.253290185974728640827156e+00, - 2.147275640380293804770778e-01, - -2.18600910711067004921551e-01, - -1.760002817872367935518928e+00, - -4.389808914752818126249079e-01, - -3.843885560201130679995041e+00, - 9.10988793377685105753416e-01, -} - -// Results for 100000 * math.Pi + vf[i] -var tanLarge = []float64{ - -3.66131656475596512705e+00, - 8.6490023287202547927e+00, - -2.841794195104782406e-01, - 3.2532901861033120983e+00, - 2.14727564046880001365e-01, - -2.18600910700688062874e-01, - -1.760002817699722747043e+00, - -4.38980891453536115952e-01, - -3.84388555942723509071e+00, - 9.1098879344275101051e-01, -} - -var tanh = []float64{ - 9.9990531206936338549262119e-01, - 9.9999962057085294197613294e-01, - -2.7001505097318677233756845e-01, - -9.9991110943061718603541401e-01, - 9.9999999146798465745022007e-01, - 9.9427249436125236705001048e-01, - 9.9994257600983138572705076e-01, - 9.9149409509772875982054701e-01, - 9.4936501296239685514466577e-01, - -9.9999994291374030946055701e-01, -} - -var trunc = []float64{ - 4.0000000000000000e+00, - 7.0000000000000000e+00, - math.Copysign(0, -1), - -5.0000000000000000e+00, - 9.0000000000000000e+00, - 2.0000000000000000e+00, - 5.0000000000000000e+00, - 2.0000000000000000e+00, - 1.0000000000000000e+00, - -8.0000000000000000e+00, -} - -var y0 = []float64{ - -3.053399153780788357534855e-01, - 1.7437227649515231515503649e-01, - -8.6221781263678836910392572e-01, - -3.100664880987498407872839e-01, - 1.422200649300982280645377e-01, - 4.000004067997901144239363e-01, - -3.3340749753099352392332536e-01, - 4.5399790746668954555205502e-01, - 4.8290004112497761007536522e-01, - 2.7036697826604756229601611e-01, -} - -var y1 = []float64{ - 0.15494213737457922210218611, - -0.2165955142081145245075746, - -2.4644949631241895201032829, - 0.1442740489541836405154505, - 0.2215379960518984777080163, - 0.3038800915160754150565448, - 0.0691107642452362383808547, - 0.2380116417809914424860165, - -0.20849492979459761009678934, - 0.0242503179793232308250804, -} - -var y2 = []float64{ - 0.3675780219390303613394936, - -0.23034826393250119879267257, - -16.939677983817727205631397, - 0.367653980523052152867791, - -0.0962401471767804440353136, - -0.1923169356184851105200523, - 0.35984072054267882391843766, - -0.2794987252299739821654982, - -0.7113490692587462579757954, - -0.2647831587821263302087457, -} - -var yM3 = []float64{ - -0.14035984421094849100895341, - -0.097535139617792072703973, - 242.25775994555580176377379, - -0.1492267014802818619511046, - 0.26148702629155918694500469, - 0.56675383593895176530394248, - -0.206150264009006981070575, - 0.64784284687568332737963658, - 1.3503631555901938037008443, - 0.1461869756579956803341844, -} - -// arguments and expected results for special cases -var vfacosSC = []float64{ - -math.Pi, - 1, - math.Pi, - math.NaN(), -} - -var acosSC = []float64{ - math.NaN(), - 0, - math.NaN(), - math.NaN(), -} - -var vfacoshSC = []float64{ - math.Inf(-1), - 0.5, - 1, - math.Inf(1), - math.NaN(), -} - -var acoshSC = []float64{ - math.NaN(), - math.NaN(), - 0, - math.Inf(1), - math.NaN(), -} - -var vfasinSC = []float64{ - -math.Pi, - math.Copysign(0, -1), - 0, - math.Pi, - math.NaN(), -} - -var asinSC = []float64{ - math.NaN(), - math.Copysign(0, -1), - 0, - math.NaN(), - math.NaN(), -} - -var vfasinhSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var asinhSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var vfatanSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var atanSC = []float64{ - -math.Pi / 2, - math.Copysign(0, -1), - 0, - math.Pi / 2, - math.NaN(), -} - -var vfatanhSC = []float64{ - math.Inf(-1), - -math.Pi, - -1, - math.Copysign(0, -1), - 0, - 1, - math.Pi, - math.Inf(1), - math.NaN(), -} - -var atanhSC = []float64{ - math.NaN(), - math.NaN(), - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), - math.NaN(), - math.NaN(), -} - -var vfatan2SC = [][2]float64{ - {math.Inf(-1), math.Inf(-1)}, - {math.Inf(-1), -math.Pi}, - {math.Inf(-1), 0}, - {math.Inf(-1), +math.Pi}, - {math.Inf(-1), math.Inf(1)}, - {math.Inf(-1), math.NaN()}, - {-math.Pi, math.Inf(-1)}, - {-math.Pi, 0}, - {-math.Pi, math.Inf(1)}, - {-math.Pi, math.NaN()}, - {math.Copysign(0, -1), math.Inf(-1)}, - {math.Copysign(0, -1), -math.Pi}, - {math.Copysign(0, -1), math.Copysign(0, -1)}, - {math.Copysign(0, -1), 0}, - {math.Copysign(0, -1), +math.Pi}, - {math.Copysign(0, -1), math.Inf(1)}, - {math.Copysign(0, -1), math.NaN()}, - {0, math.Inf(-1)}, - {0, -math.Pi}, - {0, math.Copysign(0, -1)}, - {0, 0}, - {0, +math.Pi}, - {0, math.Inf(1)}, - {0, math.NaN()}, - {+math.Pi, math.Inf(-1)}, - {+math.Pi, 0}, - {+math.Pi, math.Inf(1)}, - {1.0, math.Inf(1)}, - {-1.0, math.Inf(1)}, - {+math.Pi, math.NaN()}, - {math.Inf(1), math.Inf(-1)}, - {math.Inf(1), -math.Pi}, - {math.Inf(1), 0}, - {math.Inf(1), +math.Pi}, - {math.Inf(1), math.Inf(1)}, - {math.Inf(1), math.NaN()}, - {math.NaN(), math.NaN()}, -} - -var atan2SC = []float64{ - // https://github.com/gnolang/gno/issues/1152 - -3.0 * math.Pi / 4, // atan2(-Inf, -Inf) - -math.Pi / 2, // atan2(-Inf, -math.Pi) - -math.Pi / 2, // atan2(-Inf, +0) - -math.Pi / 2, // atan2(-Inf, +math.Pi) - -math.Pi / 4, // atan2(-Inf, +Inf) - math.NaN(), // atan2(-Inf, NaN) - -math.Pi, // atan2(-math.Pi, -Inf) - -math.Pi / 2, // atan2(-math.Pi, +0) - math.Copysign(0, -1), // atan2(-math.Pi, Inf) - math.NaN(), // atan2(-math.Pi, NaN) - -math.Pi, // atan2(-0, -Inf) - -math.Pi, // atan2(-0, -math.Pi) - -math.Pi, // atan2(-0, -0) - math.Copysign(0, -1), // atan2(-0, +0) - math.Copysign(0, -1), // atan2(-0, +math.Pi) - math.Copysign(0, -1), // atan2(-0, +Inf) - math.NaN(), // atan2(-0, NaN) - math.Pi, // atan2(+0, -Inf) - math.Pi, // atan2(+0, -math.Pi) - math.Pi, // atan2(+0, -0) - 0, // atan2(+0, +0) - 0, // atan2(+0, +math.Pi) - 0, // atan2(+0, +Inf) - math.NaN(), // atan2(+0, NaN) - math.Pi, // atan2(+math.Pi, -Inf) - math.Pi / 2, // atan2(+math.Pi, +0) - 0, // atan2(+math.Pi, +Inf) - 0, // atan2(+1, +Inf) - math.Copysign(0, -1), // atan2(-1, +Inf) - math.NaN(), // atan2(+math.Pi, NaN) - 3 * math.Pi / 4, // atan2(+Inf, -Inf) - math.Pi / 2, // atan2(+Inf, -math.Pi) - math.Pi / 2, // atan2(+Inf, +0) - math.Pi / 2, // atan2(+Inf, +math.Pi) - math.Pi / 4, // atan2(+Inf, +Inf) - math.NaN(), // atan2(+Inf, NaN) - math.NaN(), // atan2(NaN, NaN) -} - -var vfcbrtSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var cbrtSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var vfceilSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var ceilSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var vfcopysignSC = []float64{ - math.Inf(-1), - math.Inf(1), - math.NaN(), -} - -var copysignSC = []float64{ - math.Inf(-1), - math.Inf(-1), - math.NaN(), -} - -var vfcosSC = []float64{ - math.Inf(-1), - math.Inf(1), - math.NaN(), -} - -var cosSC = []float64{ - math.NaN(), - math.NaN(), - math.NaN(), -} - -var vfcoshSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var coshSC = []float64{ - math.Inf(1), - 1, - 1, - math.Inf(1), - math.NaN(), -} - -var vferfSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), - -1000, - 1000, -} - -var erfSC = []float64{ - -1, - math.Copysign(0, -1), - 0, - 1, - math.NaN(), - -1, - 1, -} - -var vferfcSC = []float64{ - math.Inf(-1), - math.Inf(1), - math.NaN(), - -1000, - 1000, -} - -var erfcSC = []float64{ - 2, - 0, - math.NaN(), - 2, - 0, -} - -var vferfinvSC = []float64{ - 1, - -1, - 0, - math.Inf(-1), - math.Inf(1), - math.NaN(), -} - -var erfinvSC = []float64{ - math.Inf(+1), - math.Inf(-1), - 0, - math.NaN(), - math.NaN(), - math.NaN(), -} - -var vferfcinvSC = []float64{ - 0, - 2, - 1, - math.Inf(1), - math.Inf(-1), - math.NaN(), -} - -var erfcinvSC = []float64{ - math.Inf(+1), - math.Inf(-1), - 0, - math.NaN(), - math.NaN(), - math.NaN(), -} - -var vfexpSC = []float64{ - math.Inf(-1), - -2000, - 2000, - math.Inf(1), - math.NaN(), - // smallest float64 that overflows math.Exp(x) - 7.097827128933841e+02, - // Issue 18912 - 1.48852223e+09, - 1.4885222e+09, - 1, - // near zero - 3.725290298461915e-09, - // denormal - -740, -} - -var expSC = []float64{ - 0, - 0, - math.Inf(1), - math.Inf(1), - math.NaN(), - math.Inf(1), - math.Inf(1), - math.Inf(1), - 2.718281828459045, - 1.0000000037252903, - 4.2e-322, -} - -var vfexp2SC = []float64{ - math.Inf(-1), - -2000, - 2000, - math.Inf(1), - math.NaN(), - // smallest float64 that overflows math.Exp2(x) - 1024, - // near underflow - -1.07399999999999e+03, - // near zero - 3.725290298461915e-09, -} - -var exp2SC = []float64{ - 0, - 0, - math.Inf(1), - math.Inf(1), - math.NaN(), - math.Inf(1), - 5e-324, - 1.0000000025821745, -} - -var vfexpm1SC = []float64{ - math.Inf(-1), - -710, - math.Copysign(0, -1), - 0, - 710, - math.Inf(1), - math.NaN(), -} - -var expm1SC = []float64{ - -1, - -1, - math.Copysign(0, -1), - 0, - math.Inf(1), - math.Inf(1), - math.NaN(), -} - -var vffabsSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var fabsSC = []float64{ - math.Inf(1), - 0, - 0, - math.Inf(1), - math.NaN(), -} - -var vffdimSC = [][2]float64{ - {math.Inf(-1), math.Inf(-1)}, - {math.Inf(-1), math.Inf(1)}, - {math.Inf(-1), math.NaN()}, - {math.Copysign(0, -1), math.Copysign(0, -1)}, - {math.Copysign(0, -1), 0}, - {0, math.Copysign(0, -1)}, - {0, 0}, - {math.Inf(1), math.Inf(-1)}, - {math.Inf(1), math.Inf(1)}, - {math.Inf(1), math.NaN()}, - {math.NaN(), math.Inf(-1)}, - {math.NaN(), math.Copysign(0, -1)}, - {math.NaN(), 0}, - {math.NaN(), math.Inf(1)}, - {math.NaN(), math.NaN()}, -} - -var ( - nan = math.Float64frombits(0xFFF8000000000000) // SSE2 DIVSD 0/0 - vffdim2SC = [][2]float64{ - {math.Inf(-1), math.Inf(-1)}, - {math.Inf(-1), math.Inf(1)}, - {math.Inf(-1), nan}, - {math.Copysign(0, -1), math.Copysign(0, -1)}, - {math.Copysign(0, -1), 0}, - {0, math.Copysign(0, -1)}, - {0, 0}, - {math.Inf(1), math.Inf(-1)}, - {math.Inf(1), math.Inf(1)}, - {math.Inf(1), nan}, - {nan, math.Inf(-1)}, - {nan, math.Copysign(0, -1)}, - {nan, 0}, - {nan, math.Inf(1)}, - {nan, nan}, - } -) - -var fdimSC = []float64{ - math.NaN(), - 0, - math.NaN(), - 0, - 0, - 0, - 0, - math.Inf(1), - math.NaN(), - math.NaN(), - math.NaN(), - math.NaN(), - math.NaN(), - math.NaN(), - math.NaN(), -} - -var fmaxSC = []float64{ - math.Inf(-1), - math.Inf(1), - math.NaN(), - math.Copysign(0, -1), - 0, - 0, - 0, - math.Inf(1), - math.Inf(1), - math.Inf(1), - math.NaN(), - math.NaN(), - math.NaN(), - math.Inf(1), - math.NaN(), -} - -var fminSC = []float64{ - math.Inf(-1), - math.Inf(-1), - math.Inf(-1), - math.Copysign(0, -1), - math.Copysign(0, -1), - math.Copysign(0, -1), - 0, - math.Inf(-1), - math.Inf(1), - math.NaN(), - math.Inf(-1), - math.NaN(), - math.NaN(), - math.NaN(), - math.NaN(), -} - -var vffmodSC = [][2]float64{ - {math.Inf(-1), math.Inf(-1)}, - {math.Inf(-1), -math.Pi}, - {math.Inf(-1), 0}, - {math.Inf(-1), math.Pi}, - {math.Inf(-1), math.Inf(1)}, - {math.Inf(-1), math.NaN()}, - {-math.Pi, math.Inf(-1)}, - {-math.Pi, 0}, - {-math.Pi, math.Inf(1)}, - {-math.Pi, math.NaN()}, - {math.Copysign(0, -1), math.Inf(-1)}, - {math.Copysign(0, -1), 0}, - {math.Copysign(0, -1), math.Inf(1)}, - {math.Copysign(0, -1), math.NaN()}, - {0, math.Inf(-1)}, - {0, 0}, - {0, math.Inf(1)}, - {0, math.NaN()}, - {math.Pi, math.Inf(-1)}, - {math.Pi, 0}, - {math.Pi, math.Inf(1)}, - {math.Pi, math.NaN()}, - {math.Inf(1), math.Inf(-1)}, - {math.Inf(1), -math.Pi}, - {math.Inf(1), 0}, - {math.Inf(1), math.Pi}, - {math.Inf(1), math.Inf(1)}, - {math.Inf(1), math.NaN()}, - {math.NaN(), math.Inf(-1)}, - {math.NaN(), -math.Pi}, - {math.NaN(), 0}, - {math.NaN(), math.Pi}, - {math.NaN(), math.Inf(1)}, - {math.NaN(), math.NaN()}, -} - -var fmodSC = []float64{ - math.NaN(), // fmod(-Inf, -Inf) - math.NaN(), // fmod(-Inf, -math.Pi) - math.NaN(), // fmod(-Inf, 0) - math.NaN(), // fmod(-Inf, math.Pi) - math.NaN(), // fmod(-Inf, +Inf) - math.NaN(), // fmod(-Inf, NaN) - -math.Pi, // fmod(-math.Pi, -Inf) - math.NaN(), // fmod(-math.Pi, 0) - -math.Pi, // fmod(-math.Pi, +Inf) - math.NaN(), // fmod(-math.Pi, NaN) - math.Copysign(0, -1), // fmod(-0, -Inf) - math.NaN(), // fmod(-0, 0) - math.Copysign(0, -1), // fmod(-0, Inf) - math.NaN(), // fmod(-0, NaN) - 0, // fmod(0, -Inf) - math.NaN(), // fmod(0, 0) - 0, // fmod(0, +Inf) - math.NaN(), // fmod(0, NaN) - math.Pi, // fmod(math.Pi, -Inf) - math.NaN(), // fmod(math.Pi, 0) - math.Pi, // fmod(math.Pi, +Inf) - math.NaN(), // fmod(math.Pi, NaN) - math.NaN(), // fmod(+Inf, -Inf) - math.NaN(), // fmod(+Inf, -math.Pi) - math.NaN(), // fmod(+Inf, 0) - math.NaN(), // fmod(+Inf, math.Pi) - math.NaN(), // fmod(+Inf, +Inf) - math.NaN(), // fmod(+Inf, NaN) - math.NaN(), // fmod(NaN, -Inf) - math.NaN(), // fmod(NaN, -math.Pi) - math.NaN(), // fmod(NaN, 0) - math.NaN(), // fmod(NaN, math.Pi) - math.NaN(), // fmod(NaN, +Inf) - math.NaN(), // fmod(NaN, NaN) -} - -var vffrexpSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var frexpSC = []fi{ - {math.Inf(-1), 0}, - {math.Copysign(0, -1), 0}, - {0, 0}, - {math.Inf(1), 0}, - {math.NaN(), 0}, -} - -var vfgamma = [][2]float64{ - {math.Inf(1), math.Inf(1)}, - {math.Inf(-1), math.NaN()}, - {0, math.Inf(1)}, - {math.Copysign(0, -1), math.Inf(-1)}, - {math.NaN(), math.NaN()}, - {-1, math.NaN()}, - {-2, math.NaN()}, - {-3, math.NaN()}, - {-1e16, math.NaN()}, - {-1e300, math.NaN()}, - {1.7e308, math.Inf(1)}, - - // Test inputs inspired by Python test suite. - // Outputs computed at high precision by PARI/GP. - // If recomputing table entries, be careful to use - // high-precision (%.1000g) formatting of the float64 inputs. - // For example, -2.0000000000000004 is the float64 with exact value - // -2.00000000000000044408920985626161695, and - // gamma(-2.0000000000000004) = -1249999999999999.5386078562728167651513, while - // gamma(-2.00000000000000044408920985626161695) = -1125899906826907.2044875028130093136826. - // Thus the table lists -1.1258999068426235e+15 as the answer. - {0.5, 1.772453850905516}, - {1.5, 0.886226925452758}, - {2.5, 1.329340388179137}, - {3.5, 3.3233509704478426}, - {-0.5, -3.544907701811032}, - {-1.5, 2.363271801207355}, - {-2.5, -0.9453087204829419}, - {-3.5, 0.2700882058522691}, - {0.1, 9.51350769866873}, - {0.01, 99.4325851191506}, - {1e-08, 9.999999942278434e+07}, - {1e-16, 1e+16}, - {0.001, 999.4237724845955}, - {1e-16, 1e+16}, - {1e-308, 1e+308}, - {5.6e-309, 1.7857142857142864e+308}, - {5.5e-309, math.Inf(1)}, - {1e-309, math.Inf(1)}, - {1e-323, math.Inf(1)}, - {5e-324, math.Inf(1)}, - {-0.1, -10.686287021193193}, - {-0.01, -100.58719796441078}, - {-1e-08, -1.0000000057721567e+08}, - {-1e-16, -1e+16}, - {-0.001, -1000.5782056293586}, - {-1e-16, -1e+16}, - {-1e-308, -1e+308}, - {-5.6e-309, -1.7857142857142864e+308}, - {-5.5e-309, math.Inf(-1)}, - {-1e-309, math.Inf(-1)}, - {-1e-323, math.Inf(-1)}, - {-5e-324, math.Inf(-1)}, - {-0.9999999999999999, -9.007199254740992e+15}, - {-1.0000000000000002, 4.5035996273704955e+15}, - {-1.9999999999999998, 2.2517998136852485e+15}, - {-2.0000000000000004, -1.1258999068426235e+15}, - {-100.00000000000001, -7.540083334883109e-145}, - {-99.99999999999999, 7.540083334884096e-145}, - {17, 2.0922789888e+13}, - {171, 7.257415615307999e+306}, - {171.6, 1.5858969096672565e+308}, - {171.624, 1.7942117599248104e+308}, - {171.625, math.Inf(1)}, - {172, math.Inf(1)}, - {2000, math.Inf(1)}, - {-100.5, -3.3536908198076787e-159}, - {-160.5, -5.255546447007829e-286}, - {-170.5, -3.3127395215386074e-308}, - {-171.5, 1.9316265431712e-310}, - {-176.5, -1.196e-321}, - {-177.5, 5e-324}, - {-178.5, math.Copysign(0, -1)}, - {-179.5, 0}, - {-201.0001, 0}, - {-202.9999, math.Copysign(0, -1)}, - {-1000.5, math.Copysign(0, -1)}, - {-1.0000000003e+09, math.Copysign(0, -1)}, - {-4.5035996273704955e+15, 0}, - {-63.349078729022985, 4.177797167776188e-88}, - {-127.45117632943295, 1.183111089623681e-214}, -} - -var vfhypotSC = [][2]float64{ - {math.Inf(-1), math.Inf(-1)}, - {math.Inf(-1), 0}, - {math.Inf(-1), math.Inf(1)}, - {math.Inf(-1), math.NaN()}, - {math.Copysign(0, -1), math.Copysign(0, -1)}, - {math.Copysign(0, -1), 0}, - {0, math.Copysign(0, -1)}, - {0, 0}, // +0, +0 - {0, math.Inf(-1)}, - {0, math.Inf(1)}, - {0, math.NaN()}, - {math.Inf(1), math.Inf(-1)}, - {math.Inf(1), 0}, - {math.Inf(1), math.Inf(1)}, - {math.Inf(1), math.NaN()}, - {math.NaN(), math.Inf(-1)}, - {math.NaN(), 0}, - {math.NaN(), math.Inf(1)}, - {math.NaN(), math.NaN()}, -} - -var hypotSC = []float64{ - math.Inf(1), - math.Inf(1), - math.Inf(1), - math.Inf(1), - 0, - 0, - 0, - 0, - math.Inf(1), - math.Inf(1), - math.NaN(), - math.Inf(1), - math.Inf(1), - math.Inf(1), - math.Inf(1), - math.Inf(1), - math.NaN(), - math.Inf(1), - math.NaN(), -} - -var ilogbSC = []int{ - math.MaxInt32, - math.MinInt32, - math.MaxInt32, - math.MaxInt32, -} - -var vfj0SC = []float64{ - math.Inf(-1), - 0, - math.Inf(1), - math.NaN(), -} - -var j0SC = []float64{ - 0, - 1, - 0, - math.NaN(), -} - -var j1SC = []float64{ - 0, - 0, - 0, - math.NaN(), -} - -var j2SC = []float64{ - 0, - 0, - 0, - math.NaN(), -} - -var jM3SC = []float64{ - 0, - 0, - 0, - math.NaN(), -} - -var vfldexpSC = []fi{ - {0, 0}, - {0, -1075}, - {0, 1024}, - {math.Copysign(0, -1), 0}, - {math.Copysign(0, -1), -1075}, - {math.Copysign(0, -1), 1024}, - {math.Inf(1), 0}, - {math.Inf(1), -1024}, - {math.Inf(-1), 0}, - {math.Inf(-1), -1024}, - {math.NaN(), -1024}, - // XXX: changed to use constant values instead of unsafe.Sizeof(0) - {10, int(1) << (uint64(7) * 8)}, - {10, -(int(1) << (uint64(7) * 8))}, -} - -var ldexpSC = []float64{ - 0, - 0, - 0, - math.Copysign(0, -1), - math.Copysign(0, -1), - math.Copysign(0, -1), - math.Inf(1), - math.Inf(1), - math.Inf(-1), - math.Inf(-1), - math.NaN(), - math.Inf(1), - 0, -} - -var vflgammaSC = []float64{ - math.Inf(-1), - -3, - 0, - 1, - 2, - math.Inf(1), - math.NaN(), -} - -var lgammaSC = []fi{ - {math.Inf(-1), 1}, - {math.Inf(1), 1}, - {math.Inf(1), 1}, - {0, 1}, - {0, 1}, - {math.Inf(1), 1}, - {math.NaN(), 1}, -} - -var vflogSC = []float64{ - math.Inf(-1), - -math.Pi, - math.Copysign(0, -1), - 0, - 1, - math.Inf(1), - math.NaN(), -} - -var logSC = []float64{ - math.NaN(), - math.NaN(), - math.Inf(-1), - math.Inf(-1), - 0, - math.Inf(1), - math.NaN(), -} - -var vflogbSC = []float64{ - math.Inf(-1), - 0, - math.Inf(1), - math.NaN(), -} - -var logbSC = []float64{ - math.Inf(1), - math.Inf(-1), - math.Inf(1), - math.NaN(), -} - -var vflog1pSC = []float64{ - math.Inf(-1), - -math.Pi, - -1, - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), - 4503599627370496.5, // Issue #29488 -} - -var log1pSC = []float64{ - math.NaN(), - math.NaN(), - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), - 36.04365338911715, // Issue #29488 -} - -var vfmodfSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - math.Inf(1), - math.NaN(), -} - -var modfSC = [][2]float64{ - {math.Inf(-1), math.NaN()}, // [2]float64{math.Copysign(0, -1), math.Inf(-1)}, - {math.Copysign(0, -1), math.Copysign(0, -1)}, - {math.Inf(1), math.NaN()}, // [2]float64{0, math.Inf(1)}, - {math.NaN(), math.NaN()}, -} - -var vfnextafter32SC = [][2]float32{ - {0, 0}, - {0, float32(math.Copysign(0, -1))}, - {0, -1}, - {0, float32(math.NaN())}, - {float32(math.Copysign(0, -1)), 1}, - {float32(math.Copysign(0, -1)), 0}, - {float32(math.Copysign(0, -1)), float32(math.Copysign(0, -1))}, - {float32(math.Copysign(0, -1)), -1}, - {float32(math.NaN()), 0}, - {float32(math.NaN()), float32(math.NaN())}, -} - -var nextafter32SC = []float32{ - 0, - 0, - -1.401298464e-45, // math.Float32frombits(0x80000001) - float32(math.NaN()), - 1.401298464e-45, // math.Float32frombits(0x00000001) - float32(math.Copysign(0, -1)), - float32(math.Copysign(0, -1)), - -1.401298464e-45, // math.Float32frombits(0x80000001) - float32(math.NaN()), - float32(math.NaN()), -} - -var vfnextafter64SC = [][2]float64{ - {0, 0}, - {0, math.Copysign(0, -1)}, - {0, -1}, - {0, math.NaN()}, - {math.Copysign(0, -1), 1}, - {math.Copysign(0, -1), 0}, - {math.Copysign(0, -1), math.Copysign(0, -1)}, - {math.Copysign(0, -1), -1}, - {math.NaN(), 0}, - {math.NaN(), math.NaN()}, -} - -var nextafter64SC = []float64{ - 0, - 0, - -4.9406564584124654418e-324, // math.Float64frombits(0x8000000000000001) - math.NaN(), - 4.9406564584124654418e-324, // math.Float64frombits(0x0000000000000001) - math.Copysign(0, -1), - math.Copysign(0, -1), - -4.9406564584124654418e-324, // math.Float64frombits(0x8000000000000001) - math.NaN(), - math.NaN(), -} - -var vfpowSC = [][2]float64{ - {math.Inf(-1), -math.Pi}, - {math.Inf(-1), -3}, - {math.Inf(-1), math.Copysign(0, -1)}, - {math.Inf(-1), 0}, - {math.Inf(-1), 1}, - {math.Inf(-1), 3}, - {math.Inf(-1), math.Pi}, - {math.Inf(-1), 0.5}, - {math.Inf(-1), math.NaN()}, - - {-math.Pi, math.Inf(-1)}, - {-math.Pi, -math.Pi}, - {-math.Pi, math.Copysign(0, -1)}, - {-math.Pi, 0}, - {-math.Pi, 1}, - {-math.Pi, math.Pi}, - {-math.Pi, math.Inf(1)}, - {-math.Pi, math.NaN()}, - - {-1, math.Inf(-1)}, - {-1, math.Inf(1)}, - {-1, math.NaN()}, - {-0.5, math.Inf(-1)}, - {-0.5, math.Inf(1)}, - {math.Copysign(0, -1), math.Inf(-1)}, - {math.Copysign(0, -1), -math.Pi}, - {math.Copysign(0, -1), -0.5}, - {math.Copysign(0, -1), -3}, - {math.Copysign(0, -1), 3}, - {math.Copysign(0, -1), math.Pi}, - {math.Copysign(0, -1), 0.5}, - {math.Copysign(0, -1), math.Inf(1)}, - - {0, math.Inf(-1)}, - {0, -math.Pi}, - {0, -3}, - {0, math.Copysign(0, -1)}, - {0, 0}, - {0, 3}, - {0, math.Pi}, - {0, math.Inf(1)}, - {0, math.NaN()}, - - {0.5, math.Inf(-1)}, - {0.5, math.Inf(1)}, - {1, math.Inf(-1)}, - {1, math.Inf(1)}, - {1, math.NaN()}, - - {math.Pi, math.Inf(-1)}, - {math.Pi, math.Copysign(0, -1)}, - {math.Pi, 0}, - {math.Pi, 1}, - {math.Pi, math.Inf(1)}, - {math.Pi, math.NaN()}, - {math.Inf(1), -math.Pi}, - {math.Inf(1), math.Copysign(0, -1)}, - {math.Inf(1), 0}, - {math.Inf(1), 1}, - {math.Inf(1), math.Pi}, - {math.Inf(1), math.NaN()}, - {math.NaN(), -math.Pi}, - {math.NaN(), math.Copysign(0, -1)}, - {math.NaN(), 0}, - {math.NaN(), 1}, - {math.NaN(), math.Pi}, - {math.NaN(), math.NaN()}, - - // Issue #7394 overflow checks - {2, float64(1 << 32)}, - {2, -float64(1 << 32)}, - {-2, float64(1<<32 + 1)}, - {0.5, float64(1 << 45)}, - {0.5, -float64(1 << 45)}, - // https://github.com/gnolang/gno/issues/1085 - {math.Nextafter(1, 2), float1Shift63}, - {math.Nextafter(1, -2), float1Shift63}, - {math.Nextafter(-1, 2), float1Shift63}, - {math.Nextafter(-1, -2), float1Shift63}, - - // Issue #57465 - {math.Copysign(0, -1), 1e19}, - {math.Copysign(0, -1), -1e19}, - {math.Copysign(0, -1), 1<<53 - 1}, - {math.Copysign(0, -1), -(1<<53 - 1)}, -} - -const float1Shift63 float64 = 1 << 63 - -var powSC = []float64{ - 0, // pow(-Inf, -math.Pi) - math.Copysign(0, -1), // pow(-Inf, -3) - 1, // pow(-Inf, -0) - 1, // pow(-Inf, +0) - math.Inf(-1), // pow(-Inf, 1) - math.Inf(-1), // pow(-Inf, 3) - math.Inf(1), // pow(-Inf, math.Pi) - math.Inf(1), // pow(-Inf, 0.5) - math.NaN(), // pow(-Inf, NaN) - 0, // pow(-math.Pi, -Inf) - math.NaN(), // pow(-math.Pi, -math.Pi) - 1, // pow(-math.Pi, -0) - 1, // pow(-math.Pi, +0) - -math.Pi, // pow(-math.Pi, 1) - math.NaN(), // pow(-math.Pi, math.Pi) - math.Inf(1), // pow(-math.Pi, +Inf) - math.NaN(), // pow(-math.Pi, NaN) - 1, // pow(-1, -Inf) IEEE 754-2008 - 1, // pow(-1, +Inf) IEEE 754-2008 - math.NaN(), // pow(-1, NaN) - math.Inf(1), // pow(-1/2, -Inf) - 0, // pow(-1/2, +Inf) - math.Inf(1), // pow(-0, -Inf) - math.Inf(1), // pow(-0, -math.Pi) - math.Inf(1), // pow(-0, -0.5) - math.Inf(-1), // pow(-0, -3) IEEE 754-2008 - math.Copysign(0, -1), // pow(-0, 3) IEEE 754-2008 - 0, // pow(-0, +math.Pi) - 0, // pow(-0, 0.5) - 0, // pow(-0, +Inf) - math.Inf(1), // pow(+0, -Inf) - math.Inf(1), // pow(+0, -math.Pi) - math.Inf(1), // pow(+0, -3) - 1, // pow(+0, -0) - 1, // pow(+0, +0) - 0, // pow(+0, 3) - 0, // pow(+0, +math.Pi) - 0, // pow(+0, +Inf) - math.NaN(), // pow(+0, NaN) - math.Inf(1), // pow(1/2, -Inf) - 0, // pow(1/2, +Inf) - 1, // pow(1, -Inf) IEEE 754-2008 - 1, // pow(1, +Inf) IEEE 754-2008 - 1, // pow(1, NaN) IEEE 754-2008 - 0, // pow(+math.Pi, -Inf) - 1, // pow(+math.Pi, -0) - 1, // pow(+math.Pi, +0) - math.Pi, // pow(+math.Pi, 1) - math.Inf(1), // pow(+math.Pi, +Inf) - math.NaN(), // pow(+math.Pi, NaN) - 0, // pow(+Inf, -math.Pi) - 1, // pow(+Inf, -0) - 1, // pow(+Inf, +0) - math.Inf(1), // pow(+Inf, 1) - math.Inf(1), // pow(+Inf, math.Pi) - math.NaN(), // pow(+Inf, NaN) - math.NaN(), // pow(NaN, -math.Pi) - 1, // pow(NaN, -0) - 1, // pow(NaN, +0) - math.NaN(), // pow(NaN, 1) - math.NaN(), // pow(NaN, +math.Pi) - math.NaN(), // pow(NaN, NaN) - - // Issue #7394 overflow checks - math.Inf(1), // pow(2, float64(1 << 32)) - 0, // pow(2, -float64(1 << 32)) - math.Inf(-1), // pow(-2, float64(1<<32 + 1)) - 0, // pow(1/2, float64(1 << 45)) - math.Inf(1), // pow(1/2, -float64(1 << 45)) - math.Inf(1), // pow(math.Nextafter(1, 2), float64(1 << 63)) - 0, // pow(math.Nextafter(1, -2), float64(1 << 63)) - 0, // pow(math.Nextafter(-1, 2), float64(1 << 63)) - math.Inf(1), // pow(math.Nextafter(-1, -2), float64(1 << 63)) - - // Issue #57465 - 0, // pow(-0, 1e19) - math.Inf(1), // pow(-0, -1e19) - math.Copysign(0, -1), // pow(-0, 1<<53 -1) - math.Inf(-1), // pow(-0, -(1<<53 -1)) -} - -var vfpow10SC = []int{ - math.MinInt32, - -324, - -323, - -50, - -22, - -1, - 0, - 1, - 22, - 50, - 100, - 200, - 308, - 309, - math.MaxInt32, -} - -var pow10SC = []float64{ - 0, // pow10(math.MinInt32) - 0, // pow10(-324) - 1.0e-323, // pow10(-323) - 1.0e-50, // pow10(-50) - 1.0e-22, // pow10(-22) - 1.0e-1, // pow10(-1) - 1.0e0, // pow10(0) - 1.0e1, // pow10(1) - 1.0e22, // pow10(22) - 1.0e50, // pow10(50) - 1.0e100, // pow10(100) - 1.0e200, // pow10(200) - 1.0e308, // pow10(308) - math.Inf(1), // pow10(309) - math.Inf(1), // pow10(math.MaxInt32) -} - -var vfroundSC = [][2]float64{ - {0, 0}, - {1.390671161567e-309, 0}, // denormal - {0.49999999999999994, 0}, // 0.5-epsilon - {0.5, 1}, - {0.5000000000000001, 1}, // 0.5+epsilon - {-1.5, -2}, - {-2.5, -3}, - {math.NaN(), math.NaN()}, - {math.Inf(1), math.Inf(1)}, - {2251799813685249.5, 2251799813685250}, // 1 bit fraction - {2251799813685250.5, 2251799813685251}, - {4503599627370495.5, 4503599627370496}, // 1 bit fraction, rounding to 0 bit fraction - {4503599627370497, 4503599627370497}, // large integer -} - -var vfroundEvenSC = [][2]float64{ - {0, 0}, - {1.390671161567e-309, 0}, // denormal - {0.49999999999999994, 0}, // 0.5-epsilon - {0.5, 0}, - {0.5000000000000001, 1}, // 0.5+epsilon - {-1.5, -2}, - {-2.5, -2}, - {math.NaN(), math.NaN()}, - {math.Inf(1), math.Inf(1)}, - {2251799813685249.5, 2251799813685250}, // 1 bit fraction - {2251799813685250.5, 2251799813685250}, - {4503599627370495.5, 4503599627370496}, // 1 bit fraction, rounding to 0 bit fraction - {4503599627370497, 4503599627370497}, // large integer -} - -var vfsignbitSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var signbitSC = []bool{ - true, - true, - false, - false, - false, -} - -var vfsinSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var sinSC = []float64{ - math.NaN(), - math.Copysign(0, -1), - 0, - math.NaN(), - math.NaN(), -} - -var vfsinhSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var sinhSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var vfsqrtSC = []float64{ - math.Inf(-1), - -math.Pi, - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), - math.Float64frombits(2), // subnormal; see https://golang.org/issue/13013 -} - -var sqrtSC = []float64{ - math.NaN(), - math.NaN(), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), - 3.1434555694052576e-162, -} - -var vftanhSC = []float64{ - math.Inf(-1), - math.Copysign(0, -1), - 0, - math.Inf(1), - math.NaN(), -} - -var tanhSC = []float64{ - -1, - math.Copysign(0, -1), - 0, - 1, - math.NaN(), -} - -var vfy0SC = []float64{ - math.Inf(-1), - 0, - math.Inf(1), - math.NaN(), - -1, -} - -var y0SC = []float64{ - math.NaN(), - math.Inf(-1), - 0, - math.NaN(), - math.NaN(), -} - -var y1SC = []float64{ - math.NaN(), - math.Inf(-1), - 0, - math.NaN(), - math.NaN(), -} - -var y2SC = []float64{ - math.NaN(), - math.Inf(-1), - 0, - math.NaN(), - math.NaN(), -} - -var yM3SC = []float64{ - math.NaN(), - math.Inf(1), - 0, - math.NaN(), - math.NaN(), -} - -// arguments and expected results for boundary cases -const ( - SmallestNormalFloat64 = 2.2250738585072014e-308 // 2**-1022 - LargestSubnormalFloat64 = SmallestNormalFloat64 - math.SmallestNonzeroFloat64 -) - -var vffrexpBC = []float64{ - SmallestNormalFloat64, - LargestSubnormalFloat64, - math.SmallestNonzeroFloat64, - math.MaxFloat64, - -SmallestNormalFloat64, - -LargestSubnormalFloat64, - -math.SmallestNonzeroFloat64, - -math.MaxFloat64, -} - -var frexpBC = []fi{ - {0.5, -1021}, - {0.99999999999999978, -1022}, - {0.5, -1073}, - {0.99999999999999989, 1024}, - {-0.5, -1021}, - {-0.99999999999999978, -1022}, - {-0.5, -1073}, - {-0.99999999999999989, 1024}, -} - -var vfldexpBC = []fi{ - {SmallestNormalFloat64, -52}, - {LargestSubnormalFloat64, -51}, - {math.SmallestNonzeroFloat64, 1074}, - {math.MaxFloat64, -(1023 + 1074)}, - {1, -1075}, - {-1, -1075}, - {1, 1024}, - {-1, 1024}, - {1.0000000000000002, -1075}, - {1, -1075}, -} - -var ldexpBC = []float64{ - math.SmallestNonzeroFloat64, - 1e-323, // 2**-1073 - 1, - 1e-323, // 2**-1073 - 0, - math.Copysign(0, -1), - math.Inf(1), - math.Inf(-1), - math.SmallestNonzeroFloat64, - 0, -} - -var logbBC = []float64{ - -1022, - -1023, - -1074, - 1023, - -1022, - -1023, - -1074, - 1023, -} - -// Test cases were generated with Berkeley TestFloat-3e/testfloat_gen. -// http://www.jhauser.us/arithmetic/TestFloat.html. -// The default rounding mode is selected (nearest/even), and exception flags are ignored. -var fmaC = []struct{ x, y, z, want float64 }{ - // Large exponent spread - {-3.999999999999087, -1.1123914289620494e-16, -7.999877929687506, -7.999877929687505}, - {-262112.0000004768, -0.06251525855623184, 1.1102230248837136e-16, 16385.99945072085}, - {-6.462348523533467e-27, -2.3763644720331857e-211, 4.000000000931324, 4.000000000931324}, - - // Effective addition - {-2.0000000037252907, 6.7904383376e-313, -3.3951933161e-313, -1.697607001654e-312}, - {-0.12499999999999999, 512.007568359375, -1.4193627164960366e-16, -64.00094604492188}, - {-2.7550648847397148e-39, -3.4028301595800694e+38, 0.9960937495343386, 1.9335955376735676}, - {5.723369164769208e+24, 3.8149300927159385e-06, 1.84489958778182e+19, 4.028324913621874e+19}, - {-0.4843749999990904, -3.6893487872543293e+19, 9.223653786709391e+18, 2.7093936974938993e+19}, - {-3.8146972665201165e-06, 4.2949672959999385e+09, -2.2204460489938386e-16, -16384.000003844263}, - {6.98156394130982e-309, -1.1072962560000002e+09, -4.4414561548793455e-308, -7.73065965765153e-300}, - - // Effective subtraction - {5e-324, 4.5, -2e-323, 0}, - {5e-324, 7, -3.5e-323, 0}, - {5e-324, 0.5000000000000001, -5e-324, math.Copysign(0, -1)}, - {-2.1240680525e-314, -1.233647078189316e+308, -0.25781249999954525, -0.25780987964919844}, - {8.579992955364441e-308, 0.6037391876780558, -4.4501307410480706e-308, 7.29947236107098e-309}, - {-4.450143471986689e-308, -0.9960937499927239, -4.450419332475649e-308, -1.7659233458788e-310}, - {1.4932076393918112, -2.2248022430460833e-308, 4.449875571054211e-308, 1.127783865601762e-308}, - - // Overflow - {-2.288020632214759e+38, -8.98846570988901e+307, 1.7696041796300924e+308, math.Inf(0)}, - {1.4888652783208255e+308, -9.007199254742012e+15, -6.807282911929205e+38, math.Inf(-1)}, - {9.142703268902826e+192, -1.3504889569802838e+296, -1.9082200803806996e-89, math.Inf(-1)}, - - // Finite x and y, but non-finite z. - {31.99218749627471, -1.7976930544991702e+308, math.Inf(0), math.Inf(0)}, - {-1.7976931281784667e+308, -2.0009765625002265, math.Inf(-1), math.Inf(-1)}, - - // Special - {0, 0, 0, 0}, - {math.Copysign(0, -1), 0, 0, 0}, - {0, 0, math.Copysign(0, -1), 0}, - {math.Copysign(0, -1), 0, math.Copysign(0, -1), math.Copysign(0, -1)}, - {-1.1754226043408471e-38, math.NaN(), math.Inf(0), math.NaN()}, - {0, 0, 2.22507385643494e-308, 2.22507385643494e-308}, - {-8.65697792e+09, math.NaN(), -7.516192799999999e+09, math.NaN()}, - {-0.00012207403779029757, 3.221225471996093e+09, math.NaN(), math.NaN()}, - {math.Inf(-1), 0.1252441407414153, -1.387184532981584e-76, math.Inf(-1)}, - {math.Inf(0), 1.525878907671432e-05, -9.214364835452549e+18, math.Inf(0)}, - - // Random - {0.1777916152213626, -32.000015266239636, -2.2204459148334633e-16, -5.689334401293007}, - {-2.0816681711722314e-16, -0.4997558592585846, -0.9465627129124969, -0.9465627129124968}, - {-1.9999997615814211, 1.8518819259933516e+19, 16.874999999999996, -3.703763410463646e+19}, - {-0.12499994039717421, 32767.99999976135, -2.0752587082923246e+19, -2.075258708292325e+19}, - {7.705600568510257e-34, -1.801432979000528e+16, -0.17224197722973714, -0.17224197722973716}, - {3.8988133103758913e-308, -0.9848632812499999, 3.893879244098556e-308, 5.40811742605814e-310}, - {-0.012651981190687427, 6.911985574912436e+38, 6.669240527007144e+18, -8.745031148409496e+36}, - {4.612811918325842e+18, 1.4901161193847641e-08, 2.6077032311277997e-08, 6.873625395187494e+10}, - {-9.094947033611148e-13, 4.450691014249257e-308, 2.086006742350485e-308, 2.086006742346437e-308}, - {-7.751454006381804e-05, 5.588653777189071e-308, -2.2207280111272877e-308, -2.2211612130544025e-308}, - - // Issue #61130 - {-1, 1, 1, 0}, - {1, 1, -1, 0}, -} - -var sqrt32 = []float32{ - 0, - float32(math.Copysign(0, -1)), - float32(math.NaN()), - float32(math.Inf(1)), - float32(math.Inf(-1)), - 1, - 2, - -2, - 4.9790119248836735e+00, - 7.7388724745781045e+00, - -2.7688005719200159e-01, - -5.0106036182710749e+00, -} - -func tolerance(a, b, e float64) bool { - // Multiplying by e here can underflow denormal values to zero. - // Check a==b so that at least if a and b are small and identical - // we say they match. - if a == b { - return true - } - d := a - b - if d < 0 { - d = -d - } - - // note: b is correct (expected) value, a is actual value. - // make error tolerance a fraction of b, not a. - if b != 0 { - e = e * b - if e < 0 { - e = -e - } - } - return d < e -} -func closeFloat64(a, b float64) bool { return tolerance(a, b, 1e-14) } -func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) } -func soclose(a, b, e float64) bool { return tolerance(a, b, e) } -func alike(a, b float64) bool { - switch { - case math.IsNaN(a) && math.IsNaN(b): - return true - case a == b: - return math.Signbit(a) == math.Signbit(b) - } - return false -} - -func TestNaN(t *testing.T) { - f64 := math.NaN() - if f64 == f64 { - t.Fatalf("math.NaN() returns %g, expected NaN", f64) - } - f32 := float32(f64) - if f32 == f32 { - t.Fatalf("float32(math.NaN()) is %g, expected NaN", f32) - } -} - -func TestAcos(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := vf[i] / 10 - if f := math.Acos(a); !closeFloat64(acos[i], f) { - t.Errorf("math.Acos(%g) = %g, want %g", a, f, acos[i]) - } - } - for i := 0; i < len(vfacosSC); i++ { - if f := math.Acos(vfacosSC[i]); !alike(acosSC[i], f) { - t.Errorf("math.Acos(%g) = %g, want %g", vfacosSC[i], f, acosSC[i]) - } - } -} - -func TestAcosh(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := 1 + math.Abs(vf[i]) - if f := math.Acosh(a); !veryclose(acosh[i], f) { - t.Errorf("math.Acosh(%g) = %g, want %g", a, f, acosh[i]) - } - } - for i := 0; i < len(vfacoshSC); i++ { - if f := math.Acosh(vfacoshSC[i]); !alike(acoshSC[i], f) { - t.Errorf("math.Acosh(%g) = %g, want %g", vfacoshSC[i], f, acoshSC[i]) - } - } -} - -func TestAsin(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := vf[i] / 10 - if f := math.Asin(a); !veryclose(asin[i], f) { - t.Errorf("math.Asin(%g) = %g, want %g", a, f, asin[i]) - } - } - for i := 0; i < len(vfasinSC); i++ { - if f := math.Asin(vfasinSC[i]); !alike(asinSC[i], f) { - t.Errorf("math.Asin(%g) = %g, want %g", vfasinSC[i], f, asinSC[i]) - } - } -} - -func TestAsinh(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Asinh(vf[i]); !veryclose(asinh[i], f) { - t.Errorf("math.Asinh(%g) = %g, want %g", vf[i], f, asinh[i]) - } - } - for i := 0; i < len(vfasinhSC); i++ { - if f := math.Asinh(vfasinhSC[i]); !alike(asinhSC[i], f) { - t.Errorf("math.Asinh(%g) = %g, want %g", vfasinhSC[i], f, asinhSC[i]) - } - } -} - -func TestAtan(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Atan(vf[i]); !veryclose(atan[i], f) { - t.Errorf("math.Atan(%g) = %g, want %g", vf[i], f, atan[i]) - } - } - for i := 0; i < len(vfatanSC); i++ { - if f := math.Atan(vfatanSC[i]); !alike(atanSC[i], f) { - t.Errorf("math.Atan(%g) = %g, want %g", vfatanSC[i], f, atanSC[i]) - } - } -} - -func TestAtanh(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := vf[i] / 10 - if f := math.Atanh(a); !veryclose(atanh[i], f) { - t.Errorf("math.Atanh(%g) = %g, want %g", a, f, atanh[i]) - } - } - for i := 0; i < len(vfatanhSC); i++ { - if f := math.Atanh(vfatanhSC[i]); !alike(atanhSC[i], f) { - t.Errorf("math.Atanh(%g) = %g, want %g", vfatanhSC[i], f, atanhSC[i]) - } - } -} - -func TestAtan2(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Atan2(10, vf[i]); !veryclose(atan2[i], f) { - t.Errorf("math.Atan2(10, %g) = %g, want %g", vf[i], f, atan2[i]) - } - } - for i := 0; i < len(vfatan2SC); i++ { - if f := math.Atan2(vfatan2SC[i][0], vfatan2SC[i][1]); !alike(atan2SC[i], f) { - t.Errorf("math.Atan2(%g, %g) = %g, want %g", vfatan2SC[i][0], vfatan2SC[i][1], f, atan2SC[i]) - } - } -} - -func TestCbrt(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Cbrt(vf[i]); !veryclose(cbrt[i], f) { - t.Errorf("math.Cbrt(%g) = %g, want %g", vf[i], f, cbrt[i]) - } - } - for i := 0; i < len(vfcbrtSC); i++ { - if f := math.Cbrt(vfcbrtSC[i]); !alike(cbrtSC[i], f) { - t.Errorf("math.Cbrt(%g) = %g, want %g", vfcbrtSC[i], f, cbrtSC[i]) - } - } -} - -func TestCeil(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Ceil(vf[i]); !alike(ceil[i], f) { - t.Errorf("math.Ceil(%g) = %g, want %g", vf[i], f, ceil[i]) - } - } - for i := 0; i < len(vfceilSC); i++ { - if f := math.Ceil(vfceilSC[i]); !alike(ceilSC[i], f) { - t.Errorf("math.Ceil(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i]) - } - } -} - -func TestCopysign(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Copysign(vf[i], -1); copysign[i] != f { - t.Errorf("math.Copysign(%g, -1) = %g, want %g", vf[i], f, copysign[i]) - } - } - for i := 0; i < len(vf); i++ { - if f := math.Copysign(vf[i], 1); -copysign[i] != f { - t.Errorf("math.Copysign(%g, 1) = %g, want %g", vf[i], f, -copysign[i]) - } - } - for i := 0; i < len(vfcopysignSC); i++ { - if f := math.Copysign(vfcopysignSC[i], -1); !alike(copysignSC[i], f) { - t.Errorf("math.Copysign(%g, -1) = %g, want %g", vfcopysignSC[i], f, copysignSC[i]) - } - } -} - -func TestCos(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Cos(vf[i]); !veryclose(cos[i], f) { - t.Errorf("math.Cos(%g) = %g, want %g", vf[i], f, cos[i]) - } - } - for i := 0; i < len(vfcosSC); i++ { - if f := math.Cos(vfcosSC[i]); !alike(cosSC[i], f) { - t.Errorf("math.Cos(%g) = %g, want %g", vfcosSC[i], f, cosSC[i]) - } - } -} - -func TestCosh(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Cosh(vf[i]); !closeFloat64(cosh[i], f) { - t.Errorf("math.Cosh(%g) = %g, want %g", vf[i], f, cosh[i]) - } - } - for i := 0; i < len(vfcoshSC); i++ { - if f := math.Cosh(vfcoshSC[i]); !alike(coshSC[i], f) { - t.Errorf("math.Cosh(%g) = %g, want %g", vfcoshSC[i], f, coshSC[i]) - } - } -} - -func TestErf(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := vf[i] / 10 - if f := math.Erf(a); !veryclose(erf[i], f) { - t.Errorf("math.Erf(%g) = %g, want %g", a, f, erf[i]) - } - } - for i := 0; i < len(vferfSC); i++ { - if f := math.Erf(vferfSC[i]); !alike(erfSC[i], f) { - t.Errorf("math.Erf(%g) = %g, want %g", vferfSC[i], f, erfSC[i]) - } - } -} - -func TestErfc(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := vf[i] / 10 - if f := math.Erfc(a); !veryclose(erfc[i], f) { - t.Errorf("math.Erfc(%g) = %g, want %g", a, f, erfc[i]) - } - } - for i := 0; i < len(vferfcSC); i++ { - if f := math.Erfc(vferfcSC[i]); !alike(erfcSC[i], f) { - t.Errorf("math.Erfc(%g) = %g, want %g", vferfcSC[i], f, erfcSC[i]) - } - } -} - -func TestErfinv(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := vf[i] / 10 - if f := math.Erfinv(a); !veryclose(erfinv[i], f) { - t.Errorf("math.Erfinv(%g) = %g, want %g", a, f, erfinv[i]) - } - } - for i := 0; i < len(vferfinvSC); i++ { - if f := math.Erfinv(vferfinvSC[i]); !alike(erfinvSC[i], f) { - t.Errorf("math.Erfinv(%g) = %g, want %g", vferfinvSC[i], f, erfinvSC[i]) - } - } - for x := -0.9; x <= 0.90; x += 1e-2 { - if f := math.Erf(math.Erfinv(x)); !closeFloat64(x, f) { - t.Errorf("math.Erf(math.Erfinv(%g)) = %g, want %g", x, f, x) - } - } - for x := -0.9; x <= 0.90; x += 1e-2 { - if f := math.Erfinv(math.Erf(x)); !closeFloat64(x, f) { - t.Errorf("math.Erfinv(math.Erf(%g)) = %g, want %g", x, f, x) - } - } -} - -func TestErfcinv(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := 1.0 - (vf[i] / 10) - if f := math.Erfcinv(a); !veryclose(erfinv[i], f) { - t.Errorf("math.Erfcinv(%g) = %g, want %g", a, f, erfinv[i]) - } - } - for i := 0; i < len(vferfcinvSC); i++ { - if f := math.Erfcinv(vferfcinvSC[i]); !alike(erfcinvSC[i], f) { - t.Errorf("math.Erfcinv(%g) = %g, want %g", vferfcinvSC[i], f, erfcinvSC[i]) - } - } - for x := 0.1; x <= 1.9; x += 1e-2 { - if f := math.Erfc(math.Erfcinv(x)); !closeFloat64(x, f) { - t.Errorf("math.Erfc(math.Erfcinv(%g)) = %g, want %g", x, f, x) - } - } - for x := 0.1; x <= 1.9; x += 1e-2 { - if f := math.Erfcinv(math.Erfc(x)); !closeFloat64(x, f) { - t.Errorf("math.Erfcinv(math.Erfc(%g)) = %g, want %g", x, f, x) - } - } -} - -func TestExp(t *testing.T) { - testExp(t, math.Exp, "Exp") - testExp(t, math.ExpGo, "ExpGo") -} - -func testExp(t *testing.T, Exp func(float64) float64, name string) { - for i := 0; i < len(vf); i++ { - if f := math.Exp(vf[i]); !veryclose(exp[i], f) { - t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp[i]) - } - } - for i := 0; i < len(vfexpSC); i++ { - if f := math.Exp(vfexpSC[i]); !alike(expSC[i], f) { - t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i]) - } - } -} - -func TestExpm1(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := vf[i] / 100 - if f := math.Expm1(a); !veryclose(expm1[i], f) { - t.Errorf("math.Expm1(%g) = %g, want %g", a, f, expm1[i]) - } - } - for i := 0; i < len(vf); i++ { - a := vf[i] * 10 - if f := math.Expm1(a); !closeFloat64(expm1Large[i], f) { - t.Errorf("math.Expm1(%g) = %g, want %g", a, f, expm1Large[i]) - } - } - for i := 0; i < len(vfexpm1SC); i++ { - if f := math.Expm1(vfexpm1SC[i]); !alike(expm1SC[i], f) { - t.Errorf("math.Expm1(%g) = %g, want %g", vfexpm1SC[i], f, expm1SC[i]) - } - } -} - -func TestExp2(t *testing.T) { - testExp2(t, math.Exp2, "Exp2") - testExp2(t, math.Exp2Go, "Exp2Go") -} - -func testExp2(t *testing.T, Exp2 func(float64) float64, name string) { - for i := 0; i < len(vf); i++ { - if f := math.Exp2(vf[i]); !closeFloat64(exp2[i], f) { - t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp2[i]) - } - } - for i := 0; i < len(vfexp2SC); i++ { - if f := math.Exp2(vfexp2SC[i]); !alike(exp2SC[i], f) { - t.Errorf("%s(%g) = %g, want %g", name, vfexp2SC[i], f, exp2SC[i]) - } - } - for n := -1074; n < 1024; n++ { - f := math.Exp2(float64(n)) - vf := math.Ldexp(1, n) - if f != vf { - t.Errorf("%s(%d) = %g, want %g", name, n, f, vf) - } - } -} - -func TestAbs(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Abs(vf[i]); fabs[i] != f { - t.Errorf("math.Abs(%g) = %g, want %g", vf[i], f, fabs[i]) - } - } - for i := 0; i < len(vffabsSC); i++ { - if f := math.Abs(vffabsSC[i]); !alike(fabsSC[i], f) { - t.Errorf("math.Abs(%g) = %g, want %g", vffabsSC[i], f, fabsSC[i]) - } - } -} - -func TestDim(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Dim(vf[i], 0); fdim[i] != f { - t.Errorf("math.Dim(%g, %g) = %g, want %g", vf[i], 0.0, f, fdim[i]) - } - } - for i := 0; i < len(vffdimSC); i++ { - if f := math.Dim(vffdimSC[i][0], vffdimSC[i][1]); !alike(fdimSC[i], f) { - t.Errorf("math.Dim(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fdimSC[i]) - } - } - for i := 0; i < len(vffdim2SC); i++ { - if f := math.Dim(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fdimSC[i], f) { - t.Errorf("math.Dim(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fdimSC[i]) - } - } -} - -func TestFloor(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Floor(vf[i]); !alike(floor[i], f) { - t.Errorf("math.Floor(%g) = %g, want %g", vf[i], f, floor[i]) - } - } - for i := 0; i < len(vfceilSC); i++ { - if f := math.Floor(vfceilSC[i]); !alike(ceilSC[i], f) { - t.Errorf("math.Floor(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i]) - } - } -} - -func TestMax(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Max(vf[i], ceil[i]); ceil[i] != f { - t.Errorf("math.Max(%g, %g) = %g, want %g", vf[i], ceil[i], f, ceil[i]) - } - } - for i := 0; i < len(vffdimSC); i++ { - if f := math.Max(vffdimSC[i][0], vffdimSC[i][1]); !alike(fmaxSC[i], f) { - t.Errorf("math.Max(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fmaxSC[i]) - } - } - for i := 0; i < len(vffdim2SC); i++ { - if f := math.Max(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fmaxSC[i], f) { - t.Errorf("math.Max(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fmaxSC[i]) - } - } -} - -func TestMin(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Min(vf[i], floor[i]); floor[i] != f { - t.Errorf("math.Min(%g, %g) = %g, want %g", vf[i], floor[i], f, floor[i]) - } - } - for i := 0; i < len(vffdimSC); i++ { - if f := math.Min(vffdimSC[i][0], vffdimSC[i][1]); !alike(fminSC[i], f) { - t.Errorf("math.Min(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fminSC[i]) - } - } - for i := 0; i < len(vffdim2SC); i++ { - if f := math.Min(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fminSC[i], f) { - t.Errorf("math.Min(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fminSC[i]) - } - } -} - -func TestMod(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Mod(10, vf[i]); fmod[i] != f { - t.Errorf("math.Mod(10, %g) = %g, want %g", vf[i], f, fmod[i]) - } - } - for i := 0; i < len(vffmodSC); i++ { - if f := math.Mod(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) { - t.Errorf("math.Mod(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i]) - } - } - // verify precision of result for extreme inputs - if f := math.Mod(5.9790119248836734e+200, 1.1258465975523544); 0.6447968302508578 != f { - t.Errorf("math.Remainder(5.9790119248836734e+200, 1.1258465975523544) = %g, want 0.6447968302508578", f) - } -} - -func TestFrexp(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f, j := math.Frexp(vf[i]); !veryclose(frexp[i].f, f) || frexp[i].i != j { - t.Errorf("math.Frexp(%g) = %g, %d, want %g, %d", vf[i], f, j, frexp[i].f, frexp[i].i) - } - } - for i := 0; i < len(vffrexpSC); i++ { - if f, j := math.Frexp(vffrexpSC[i]); !alike(frexpSC[i].f, f) || frexpSC[i].i != j { - t.Errorf("math.Frexp(%g) = %g, %d, want %g, %d", vffrexpSC[i], f, j, frexpSC[i].f, frexpSC[i].i) - } - } - for i := 0; i < len(vffrexpBC); i++ { - if f, j := math.Frexp(vffrexpBC[i]); !alike(frexpBC[i].f, f) || frexpBC[i].i != j { - t.Errorf("math.Frexp(%g) = %g, %d, want %g, %d", vffrexpBC[i], f, j, frexpBC[i].f, frexpBC[i].i) - } - } -} - -func TestGamma(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Gamma(vf[i]); !closeFloat64(gamma[i], f) { - t.Errorf("math.Gamma(%g) = %g, want %g", vf[i], f, gamma[i]) - } - } - for _, g := range vfgamma { - f := math.Gamma(g[0]) - var ok bool - if math.IsNaN(g[1]) || math.IsInf(g[1], 0) || g[1] == 0 || f == 0 { - ok = alike(g[1], f) - } else if g[0] > -50 && g[0] <= 171 { - ok = veryclose(g[1], f) - } else { - ok = closeFloat64(g[1], f) - } - if !ok { - t.Errorf("math.Gamma(%g) = %g, want %g", g[0], f, g[1]) - } - } -} - -func TestHypot(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(1e200 * tanh[i] * math.Sqrt(2)) - if f := math.Hypot(1e200*tanh[i], 1e200*tanh[i]); !veryclose(a, f) { - t.Errorf("math.Hypot(%g, %g) = %g, want %g", 1e200*tanh[i], 1e200*tanh[i], f, a) - } - } - for i := 0; i < len(vfhypotSC); i++ { - if f := math.Hypot(vfhypotSC[i][0], vfhypotSC[i][1]); !alike(hypotSC[i], f) { - t.Errorf("math.Hypot(%g, %g) = %g, want %g", vfhypotSC[i][0], vfhypotSC[i][1], f, hypotSC[i]) - } - } -} - -func TestHypotGo(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(1e200 * tanh[i] * math.Sqrt(2)) - if f := math.HypotGo(1e200*tanh[i], 1e200*tanh[i]); !veryclose(a, f) { - t.Errorf("math.HypotGo(%g, %g) = %g, want %g", 1e200*tanh[i], 1e200*tanh[i], f, a) - } - } - for i := 0; i < len(vfhypotSC); i++ { - if f := math.HypotGo(vfhypotSC[i][0], vfhypotSC[i][1]); !alike(hypotSC[i], f) { - t.Errorf("math.HypotGo(%g, %g) = %g, want %g", vfhypotSC[i][0], vfhypotSC[i][1], f, hypotSC[i]) - } - } -} - -func TestIlogb(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := frexp[i].i - 1 // adjust because fr in the interval [½, 1) - if e := math.Ilogb(vf[i]); a != e { - t.Errorf("math.Ilogb(%g) = %d, want %d", vf[i], e, a) - } - } - for i := 0; i < len(vflogbSC); i++ { - if e := math.Ilogb(vflogbSC[i]); ilogbSC[i] != e { - t.Errorf("math.Ilogb(%g) = %d, want %d", vflogbSC[i], e, ilogbSC[i]) - } - } - for i := 0; i < len(vffrexpBC); i++ { - if e := math.Ilogb(vffrexpBC[i]); int(logbBC[i]) != e { - t.Errorf("math.Ilogb(%g) = %d, want %d", vffrexpBC[i], e, int(logbBC[i])) - } - } -} - -func TestJ0(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.J0(vf[i]); !soclose(j0[i], f, 4e-14) { - t.Errorf("math.J0(%g) = %g, want %g", vf[i], f, j0[i]) - } - } - for i := 0; i < len(vfj0SC); i++ { - if f := math.J0(vfj0SC[i]); !alike(j0SC[i], f) { - t.Errorf("math.J0(%g) = %g, want %g", vfj0SC[i], f, j0SC[i]) - } - } -} - -func TestJ1(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.J1(vf[i]); !closeFloat64(j1[i], f) { - t.Errorf("math.J1(%g) = %g, want %g", vf[i], f, j1[i]) - } - } - for i := 0; i < len(vfj0SC); i++ { - if f := math.J1(vfj0SC[i]); !alike(j1SC[i], f) { - t.Errorf("math.J1(%g) = %g, want %g", vfj0SC[i], f, j1SC[i]) - } - } -} - -func TestJn(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Jn(2, vf[i]); !closeFloat64(j2[i], f) { - t.Errorf("math.Jn(2, %g) = %g, want %g", vf[i], f, j2[i]) - } - if f := math.Jn(-3, vf[i]); !closeFloat64(jM3[i], f) { - t.Errorf("math.Jn(-3, %g) = %g, want %g", vf[i], f, jM3[i]) - } - } - for i := 0; i < len(vfj0SC); i++ { - if f := math.Jn(2, vfj0SC[i]); !alike(j2SC[i], f) { - t.Errorf("math.Jn(2, %g) = %g, want %g", vfj0SC[i], f, j2SC[i]) - } - if f := math.Jn(-3, vfj0SC[i]); !alike(jM3SC[i], f) { - t.Errorf("math.Jn(-3, %g) = %g, want %g", vfj0SC[i], f, jM3SC[i]) - } - } -} - -func TestLdexp(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Ldexp(frexp[i].f, frexp[i].i); !veryclose(vf[i], f) { - t.Errorf("math.Ldexp(%g, %d) = %g, want %g", frexp[i].f, frexp[i].i, f, vf[i]) - } - } - for i := 0; i < len(vffrexpSC); i++ { - if f := math.Ldexp(frexpSC[i].f, frexpSC[i].i); !alike(vffrexpSC[i], f) { - t.Errorf("math.Ldexp(%g, %d) = %g, want %g", frexpSC[i].f, frexpSC[i].i, f, vffrexpSC[i]) - } - } - for i := 0; i < len(vfldexpSC); i++ { - if f := math.Ldexp(vfldexpSC[i].f, vfldexpSC[i].i); !alike(ldexpSC[i], f) { - t.Errorf("math.Ldexp(%g, %d) = %g, want %g", vfldexpSC[i].f, vfldexpSC[i].i, f, ldexpSC[i]) - } - } - for i := 0; i < len(vffrexpBC); i++ { - if f := math.Ldexp(frexpBC[i].f, frexpBC[i].i); !alike(vffrexpBC[i], f) { - t.Errorf("math.Ldexp(%g, %d) = %g, want %g", frexpBC[i].f, frexpBC[i].i, f, vffrexpBC[i]) - } - } - for i := 0; i < len(vfldexpBC); i++ { - if f := math.Ldexp(vfldexpBC[i].f, vfldexpBC[i].i); !alike(ldexpBC[i], f) { - t.Errorf("math.Ldexp(%g, %d) = %g, want %g", vfldexpBC[i].f, vfldexpBC[i].i, f, ldexpBC[i]) - } - } -} - -func TestLgamma(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f, s := math.Lgamma(vf[i]); !closeFloat64(lgamma[i].f, f) || lgamma[i].i != s { - t.Errorf("math.Lgamma(%g) = %g, %d, want %g, %d", vf[i], f, s, lgamma[i].f, lgamma[i].i) - } - } - for i := 0; i < len(vflgammaSC); i++ { - if f, s := math.Lgamma(vflgammaSC[i]); !alike(lgammaSC[i].f, f) || lgammaSC[i].i != s { - t.Errorf("math.Lgamma(%g) = %g, %d, want %g, %d", vflgammaSC[i], f, s, lgammaSC[i].f, lgammaSC[i].i) - } - } -} - -func TestLog(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(vf[i]) - if f := math.Log(a); log[i] != f { - t.Errorf("math.Log(%g) = %g, want %g", a, f, log[i]) - } - } - if f := math.Log(10); f != math.Ln10 { - t.Errorf("math.Log(%g) = %g, want %g", 10.0, f, math.Ln10) - } - for i := 0; i < len(vflogSC); i++ { - if f := math.Log(vflogSC[i]); !alike(logSC[i], f) { - t.Errorf("math.Log(%g) = %g, want %g", vflogSC[i], f, logSC[i]) - } - } -} - -func TestLogb(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Logb(vf[i]); logb[i] != f { - t.Errorf("math.Logb(%g) = %g, want %g", vf[i], f, logb[i]) - } - } - for i := 0; i < len(vflogbSC); i++ { - if f := math.Logb(vflogbSC[i]); !alike(logbSC[i], f) { - t.Errorf("math.Logb(%g) = %g, want %g", vflogbSC[i], f, logbSC[i]) - } - } - for i := 0; i < len(vffrexpBC); i++ { - if f := math.Logb(vffrexpBC[i]); !alike(logbBC[i], f) { - t.Errorf("math.Logb(%g) = %g, want %g", vffrexpBC[i], f, logbBC[i]) - } - } -} - -func TestLog10(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(vf[i]) - if f := math.Log10(a); !veryclose(log10[i], f) { - t.Errorf("math.Log10(%g) = %g, want %g", a, f, log10[i]) - } - } - if f := math.Log10(math.E); f != math.Log10E { - t.Errorf("math.Log10(%g) = %g, want %g", math.E, f, math.Log10E) - } - for i := 0; i < len(vflogSC); i++ { - if f := math.Log10(vflogSC[i]); !alike(logSC[i], f) { - t.Errorf("math.Log10(%g) = %g, want %g", vflogSC[i], f, logSC[i]) - } - } -} - -func TestLog1p(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := vf[i] / 100 - if f := math.Log1p(a); !veryclose(log1p[i], f) { - t.Errorf("math.Log1p(%g) = %g, want %g", a, f, log1p[i]) - } - } - a := 9.0 - if f := math.Log1p(a); f != math.Ln10 { - t.Errorf("math.Log1p(%g) = %g, want %g", a, f, math.Ln10) - } - for i := 0; i < len(vflogSC); i++ { - if f := math.Log1p(vflog1pSC[i]); !alike(log1pSC[i], f) { - t.Errorf("math.Log1p(%g) = %g, want %g", vflog1pSC[i], f, log1pSC[i]) - } - } -} - -func TestLog2(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(vf[i]) - if f := math.Log2(a); !veryclose(log2[i], f) { - t.Errorf("math.Log2(%g) = %g, want %g", a, f, log2[i]) - } - } - if f := math.Log2(math.E); f != math.Log2E { - t.Errorf("math.Log2(%g) = %g, want %g", math.E, f, math.Log2E) - } - for i := 0; i < len(vflogSC); i++ { - if f := math.Log2(vflogSC[i]); !alike(logSC[i], f) { - t.Errorf("math.Log2(%g) = %g, want %g", vflogSC[i], f, logSC[i]) - } - } - for i := -1074; i <= 1023; i++ { - f := math.Ldexp(1, i) - l := math.Log2(f) - if l != float64(i) { - t.Errorf("math.Log2(2**%d) = %g, want %d", i, l, i) - } - } -} - -func TestModf(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f, g := math.Modf(vf[i]); !veryclose(modf[i][0], f) || !veryclose(modf[i][1], g) { - t.Errorf("math.Modf(%g) = %g, %g, want %g, %g", vf[i], f, g, modf[i][0], modf[i][1]) - } - } - for i := 0; i < len(vfmodfSC); i++ { - if f, g := math.Modf(vfmodfSC[i]); !alike(modfSC[i][0], f) || !alike(modfSC[i][1], g) { - t.Errorf("math.Modf(%g) = %g, %g, want %g, %g", vfmodfSC[i], f, g, modfSC[i][0], modfSC[i][1]) - } - } -} - -func TestNextafter32(t *testing.T) { - for i := 0; i < len(vf); i++ { - vfi := float32(vf[i]) - if f := math.Nextafter32(vfi, 10); nextafter32[i] != f { - t.Errorf("math.Nextafter32(%g, %g) = %g want %g", vfi, 10.0, f, nextafter32[i]) - } - } - for i := 0; i < len(vfnextafter32SC); i++ { - if f := math.Nextafter32(vfnextafter32SC[i][0], vfnextafter32SC[i][1]); !alike(float64(nextafter32SC[i]), float64(f)) { - t.Errorf("math.Nextafter32(%g, %g) = %g want %g", vfnextafter32SC[i][0], vfnextafter32SC[i][1], f, nextafter32SC[i]) - } - } -} - -func TestNextafter64(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Nextafter(vf[i], 10); nextafter64[i] != f { - t.Errorf("math.Nextafter64(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter64[i]) - } - } - for i := 0; i < len(vfnextafter64SC); i++ { - if f := math.Nextafter(vfnextafter64SC[i][0], vfnextafter64SC[i][1]); !alike(nextafter64SC[i], f) { - t.Errorf("math.Nextafter64(%g, %g) = %g want %g", vfnextafter64SC[i][0], vfnextafter64SC[i][1], f, nextafter64SC[i]) - } - } -} - -func TestPow(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Pow(10, vf[i]); !closeFloat64(pow[i], f) { - t.Errorf("math.Pow(10, %g) = %g, want %g", vf[i], f, pow[i]) - } - } - for i := 0; i < len(vfpowSC); i++ { - if f := math.Pow(vfpowSC[i][0], vfpowSC[i][1]); !alike(powSC[i], f) { - t.Errorf("math.Pow(%g, %g) = %g, want %g", vfpowSC[i][0], vfpowSC[i][1], f, powSC[i]) - } - } -} - -func TestPow10(t *testing.T) { - for i := 0; i < len(vfpow10SC); i++ { - if f := math.Pow10(vfpow10SC[i]); !alike(pow10SC[i], f) { - t.Errorf("math.Pow10(%d) = %g, want %g", vfpow10SC[i], f, pow10SC[i]) - } - } -} - -func TestRemainder(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Remainder(10, vf[i]); remainder[i] != f { - t.Errorf("math.Remainder(10, %g) = %g, want %g", vf[i], f, remainder[i]) - } - } - for i := 0; i < len(vffmodSC); i++ { - if f := math.Remainder(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) { - t.Errorf("math.Remainder(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i]) - } - } - // verify precision of result for extreme inputs - if f := math.Remainder(5.9790119248836734e+200, 1.1258465975523544); -0.4810497673014966 != f { - t.Errorf("math.Remainder(5.9790119248836734e+200, 1.1258465975523544) = %g, want -0.4810497673014966", f) - } - // verify that sign is correct when r == 0. - test := func(x, y float64) { - if r := math.Remainder(x, y); r == 0 && math.Signbit(r) != math.Signbit(x) { - t.Errorf("math.Remainder(x=%f, y=%f) = %f, sign of (zero) result should agree with sign of x", x, y, r) - } - } - for x := 0.0; x <= 3.0; x += 1 { - for y := 1.0; y <= 3.0; y += 1 { - test(x, y) - test(x, -y) - test(-x, y) - test(-x, -y) - } - } -} - -func TestRound(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Round(vf[i]); !alike(round[i], f) { - t.Errorf("math.Round(%g) = %g, want %g", vf[i], f, round[i]) - } - } - for i := 0; i < len(vfroundSC); i++ { - if f := math.Round(vfroundSC[i][0]); !alike(vfroundSC[i][1], f) { - t.Errorf("math.Round(%g) = %g, want %g", vfroundSC[i][0], f, vfroundSC[i][1]) - } - } -} - -func TestRoundToEven(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.RoundToEven(vf[i]); !alike(round[i], f) { - t.Errorf("math.RoundToEven(%g) = %g, want %g", vf[i], f, round[i]) - } - } - for i := 0; i < len(vfroundEvenSC); i++ { - if f := math.RoundToEven(vfroundEvenSC[i][0]); !alike(vfroundEvenSC[i][1], f) { - t.Errorf("math.RoundToEven(%g) = %g, want %g", vfroundEvenSC[i][0], f, vfroundEvenSC[i][1]) - } - } -} - -func TestSignbit(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Signbit(vf[i]); signbit[i] != f { - t.Errorf("math.Signbit(%g) = %t, want %t", vf[i], f, signbit[i]) - } - } - for i := 0; i < len(vfsignbitSC); i++ { - if f := math.Signbit(vfsignbitSC[i]); signbitSC[i] != f { - t.Errorf("math.Signbit(%g) = %t, want %t", vfsignbitSC[i], f, signbitSC[i]) - } - } -} - -func TestSin(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Sin(vf[i]); !veryclose(sin[i], f) { - t.Errorf("math.Sin(%g) = %g, want %g", vf[i], f, sin[i]) - } - } - for i := 0; i < len(vfsinSC); i++ { - if f := math.Sin(vfsinSC[i]); !alike(sinSC[i], f) { - t.Errorf("math.Sin(%g) = %g, want %g", vfsinSC[i], f, sinSC[i]) - } - } -} - -func TestSincos(t *testing.T) { - for i := 0; i < len(vf); i++ { - if s, c := math.Sincos(vf[i]); !veryclose(sin[i], s) || !veryclose(cos[i], c) { - t.Errorf("math.Sincos(%g) = %g, %g want %g, %g", vf[i], s, c, sin[i], cos[i]) - } - } -} - -func TestSinh(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Sinh(vf[i]); !closeFloat64(sinh[i], f) { - t.Errorf("math.Sinh(%g) = %g, want %g", vf[i], f, sinh[i]) - } - } - for i := 0; i < len(vfsinhSC); i++ { - if f := math.Sinh(vfsinhSC[i]); !alike(sinhSC[i], f) { - t.Errorf("math.Sinh(%g) = %g, want %g", vfsinhSC[i], f, sinhSC[i]) - } - } -} - -func TestSqrt(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(vf[i]) - if f := math.SqrtGo(a); sqrt[i] != f { - t.Errorf("math.SqrtGo(%g) = %g, want %g", a, f, sqrt[i]) - } - a = math.Abs(vf[i]) - if f := math.Sqrt(a); sqrt[i] != f { - t.Errorf("math.Sqrt(%g) = %g, want %g", a, f, sqrt[i]) - } - } - for i := 0; i < len(vfsqrtSC); i++ { - if f := math.SqrtGo(vfsqrtSC[i]); !alike(sqrtSC[i], f) { - t.Errorf("math.SqrtGo(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i]) - } - if f := math.Sqrt(vfsqrtSC[i]); !alike(sqrtSC[i], f) { - t.Errorf("math.Sqrt(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i]) - } - } -} - -func TestTan(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Tan(vf[i]); !veryclose(tan[i], f) { - t.Errorf("math.Tan(%g) = %g, want %g", vf[i], f, tan[i]) - } - } - // same special cases as Sin - for i := 0; i < len(vfsinSC); i++ { - if f := math.Tan(vfsinSC[i]); !alike(sinSC[i], f) { - t.Errorf("math.Tan(%g) = %g, want %g", vfsinSC[i], f, sinSC[i]) - } - } -} - -func TestTanh(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Tanh(vf[i]); !veryclose(tanh[i], f) { - t.Errorf("math.Tanh(%g) = %g, want %g", vf[i], f, tanh[i]) - } - } - for i := 0; i < len(vftanhSC); i++ { - if f := math.Tanh(vftanhSC[i]); !alike(tanhSC[i], f) { - t.Errorf("math.Tanh(%g) = %g, want %g", vftanhSC[i], f, tanhSC[i]) - } - } -} - -func TestTrunc(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Trunc(vf[i]); !alike(trunc[i], f) { - t.Errorf("math.Trunc(%g) = %g, want %g", vf[i], f, trunc[i]) - } - } - for i := 0; i < len(vfceilSC); i++ { - if f := math.Trunc(vfceilSC[i]); !alike(ceilSC[i], f) { - t.Errorf("math.Trunc(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i]) - } - } -} - -func TestY0(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(vf[i]) - if f := math.Y0(a); !closeFloat64(y0[i], f) { - t.Errorf("math.Y0(%g) = %g, want %g", a, f, y0[i]) - } - } - for i := 0; i < len(vfy0SC); i++ { - if f := math.Y0(vfy0SC[i]); !alike(y0SC[i], f) { - t.Errorf("math.Y0(%g) = %g, want %g", vfy0SC[i], f, y0SC[i]) - } - } -} - -func TestY1(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(vf[i]) - if f := math.Y1(a); !soclose(y1[i], f, 2e-14) { - t.Errorf("math.Y1(%g) = %g, want %g", a, f, y1[i]) - } - } - for i := 0; i < len(vfy0SC); i++ { - if f := math.Y1(vfy0SC[i]); !alike(y1SC[i], f) { - t.Errorf("math.Y1(%g) = %g, want %g", vfy0SC[i], f, y1SC[i]) - } - } -} - -func TestYn(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Abs(vf[i]) - if f := math.Yn(2, a); !closeFloat64(y2[i], f) { - t.Errorf("math.Yn(2, %g) = %g, want %g", a, f, y2[i]) - } - if f := math.Yn(-3, a); !closeFloat64(yM3[i], f) { - t.Errorf("math.Yn(-3, %g) = %g, want %g", a, f, yM3[i]) - } - } - for i := 0; i < len(vfy0SC); i++ { - if f := math.Yn(2, vfy0SC[i]); !alike(y2SC[i], f) { - t.Errorf("math.Yn(2, %g) = %g, want %g", vfy0SC[i], f, y2SC[i]) - } - if f := math.Yn(-3, vfy0SC[i]); !alike(yM3SC[i], f) { - t.Errorf("math.Yn(-3, %g) = %g, want %g", vfy0SC[i], f, yM3SC[i]) - } - } - if f := math.Yn(0, 0); !alike(math.Inf(-1), f) { - t.Errorf("math.Yn(0, 0) = %g, want %g", f, math.Inf(-1)) - } -} - -var PortableFMA = math.FMA // hide call from compiler intrinsic; falls back to portable code - -func TestFMA(t *testing.T) { - for _, c := range fmaC { - got := math.FMA(c.x, c.y, c.z) - if !alike(got, c.want) { - t.Errorf("math.FMA(%g,%g,%g) == %g; want %g", c.x, c.y, c.z, got, c.want) - } - got = PortableFMA(c.x, c.y, c.z) - if !alike(got, c.want) { - t.Errorf("PortableFMA(%g,%g,%g) == %g; want %g", c.x, c.y, c.z, got, c.want) - } - } -} - -//go:noinline -func fmsub(x, y, z float64) float64 { - return math.FMA(x, y, -z) -} - -//go:noinline -func fnmsub(x, y, z float64) float64 { - return math.FMA(-x, y, z) -} - -//go:noinline -func fnmadd(x, y, z float64) float64 { - return math.FMA(-x, y, -z) -} - -func TestFMANegativeArgs(t *testing.T) { - // Some architectures have instructions for fused multiply-subtract and - // also negated variants of fused multiply-add and subtract. This test - // aims to check that the optimizations that generate those instructions - // are applied correctly, if they exist. - for _, c := range fmaC { - want := PortableFMA(c.x, c.y, -c.z) - got := fmsub(c.x, c.y, c.z) - if !alike(got, want) { - t.Errorf("math.FMA(%g, %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want) - } - want = PortableFMA(-c.x, c.y, c.z) - got = fnmsub(c.x, c.y, c.z) - if !alike(got, want) { - t.Errorf("math.FMA(-(%g), %g, %g) == %g, want %g", c.x, c.y, c.z, got, want) - } - want = PortableFMA(-c.x, c.y, -c.z) - got = fnmadd(c.x, c.y, c.z) - if !alike(got, want) { - t.Errorf("math.FMA(-(%g), %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want) - } - } -} - -// Check that math functions of high angle values -// return accurate results. [Since (vf[i] + large) - large != vf[i], -// testing for math.Trig(vf[i] + large) == math.Trig(vf[i]), where large is -// a multiple of 2*math.Pi, is misleading.] -func TestLargeCos(t *testing.T) { - large := float64(100000 * math.Pi) - for i := 0; i < len(vf); i++ { - f1 := cosLarge[i] - f2 := math.Cos(vf[i] + large) - if !closeFloat64(f1, f2) { - t.Errorf("math.Cos(%g) = %g, want %g", vf[i]+large, f2, f1) - } - } -} - -func TestLargeSin(t *testing.T) { - large := float64(100000 * math.Pi) - for i := 0; i < len(vf); i++ { - f1 := sinLarge[i] - f2 := math.Sin(vf[i] + large) - if !closeFloat64(f1, f2) { - t.Errorf("math.Sin(%g) = %g, want %g", vf[i]+large, f2, f1) - } - } -} - -func TestLargeSincos(t *testing.T) { - large := float64(100000 * math.Pi) - for i := 0; i < len(vf); i++ { - f1, g1 := sinLarge[i], cosLarge[i] - f2, g2 := math.Sincos(vf[i] + large) - if !closeFloat64(f1, f2) || !closeFloat64(g1, g2) { - t.Errorf("math.Sincos(%g) = %g, %g, want %g, %g", vf[i]+large, f2, g2, f1, g1) - } - } -} - -func TestLargeTan(t *testing.T) { - large := float64(100000 * math.Pi) - for i := 0; i < len(vf); i++ { - f1 := tanLarge[i] - f2 := math.Tan(vf[i] + large) - if !closeFloat64(f1, f2) { - t.Errorf("math.Tan(%g) = %g, want %g", vf[i]+large, f2, f1) - } - } -} - -// Check that trigReduce matches the standard reduction results for input values -// below reduceThreshold. -func TestTrigReduce(t *testing.T) { - inputs := make([]float64, len(vf)) - // all of the standard inputs - copy(inputs, vf) - // all of the large inputs - large := float64(100000 * math.Pi) - for _, v := range vf { - inputs = append(inputs, v+large) - } - // Also test some special inputs, math.Pi and right below the reduceThreshold - // XXX: https://github.com/gnolang/gno/issues/1149 - inputs = append(inputs, float64(math.Pi), math.Nextafter(math.ReduceThreshold, 0)) - for _, x := range inputs { - // reduce the value to compare - j, z := math.TrigReduce(x) - xred := float64(j)*(math.Pi/4) + z - - if f, fred := math.Sin(x), math.Sin(xred); !closeFloat64(f, fred) { - t.Errorf("math.Sin(trigmath.Reduce(%g)) != math.Sin(%g), got %g, want %g", x, x, fred, f) - } - if f, fred := math.Cos(x), math.Cos(xred); !closeFloat64(f, fred) { - t.Errorf("math.Cos(trigmath.Reduce(%g)) != math.Cos(%g), got %g, want %g", x, x, fred, f) - } - if f, fred := math.Tan(x), math.Tan(xred); !closeFloat64(f, fred) { - t.Errorf(" math.Tan(trigmath.Reduce(%g)) != math.Tan(%g), got %g, want %g", x, x, fred, f) - } - f, g := math.Sincos(x) - fred, gred := math.Sincos(xred) - if !closeFloat64(f, fred) || !closeFloat64(g, gred) { - t.Errorf(" math.Sincos(trigmath.Reduce(%g)) != math.Sincos(%g), got %g, %g, want %g, %g", x, x, fred, gred, f, g) - } - } -} - -// Check that math constants are accepted by compiler -// and have right value (assumes strconv.ParseFloat works). -// https://golang.org/issue/201 - -type floatTest struct { - val interface{} - name string - str string -} - -var floatTests = []floatTest{ - {float64(math.MaxFloat64), "MaxFloat64", "1.7976931348623157e+308"}, - {float64(math.SmallestNonzeroFloat64), "SmallestNonzeroFloat64", "5e-324"}, - {float32(math.MaxFloat32), "MaxFloat32", "3.4028235e+38"}, - {float32(math.SmallestNonzeroFloat32), "SmallestNonzeroFloat32", "1e-45"}, -} - -func TestFloatMinMax(t *testing.T) { - for _, tt := range floatTests { - s := fmt.Sprint(tt.val) - if s != tt.str { - t.Errorf("math.Sprint(%v) = %s, want %s", tt.name, s, tt.str) - } - } -} - -func TestFloatMinima(t *testing.T) { - if q := float32(math.SmallestNonzeroFloat32 / 2); q != 0 { - t.Errorf("float32(math.SmallestNonzeroFloat32 / 2) = %g, want 0", q) - } - if q := float64(math.SmallestNonzeroFloat64 / 2); q != 0 { - t.Errorf("float64(math.SmallestNonzeroFloat64 / 2) = %g, want 0", q) - } -} - -var indirectSqrt = math.Sqrt - -// TestFloat32Sqrt checks the correctness of the float32 square root optimization result. -func TestFloat32Sqrt(t *testing.T) { - for _, v := range sqrt32 { - want := float32(indirectSqrt(float64(v))) - got := float32(math.Sqrt(float64(v))) - if math.IsNaN(float64(want)) { - if !math.IsNaN(float64(got)) { - t.Errorf("got=%#v want=NaN, v=%#v", got, v) - } - continue - } - if got != want { - t.Errorf("got=%#v want=%#v, v=%#v", got, want, v) - } - } -} - -// Benchmarks - -// Global exported variables are used to store the -// return values of functions measured in the benchmarks. -// Storing the results in these variables prevents the compiler -// from completely optimizing the benchmarked functions away. -var ( - GlobalI int - GlobalB bool - GlobalF float64 -) - -func BenchmarkAcos(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Acos(.5) - } - GlobalF = x -} - -func BenchmarkAcosh(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Acosh(1.5) - } - GlobalF = x -} - -func BenchmarkAsin(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Asin(.5) - } - GlobalF = x -} - -func BenchmarkAsinh(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Asinh(.5) - } - GlobalF = x -} - -func BenchmarkAtan(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Atan(.5) - } - GlobalF = x -} - -func BenchmarkAtanh(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Atanh(.5) - } - GlobalF = x -} - -func BenchmarkAtan2(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Atan2(.5, 1) - } - GlobalF = x -} - -func BenchmarkCbrt(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Cbrt(10) - } - GlobalF = x -} - -func BenchmarkCeil(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Ceil(.5) - } - GlobalF = x -} - -var copysignNeg = -1.0 - -func BenchmarkCopysign(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Copysign(.5, copysignNeg) - } - GlobalF = x -} - -func BenchmarkCos(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Cos(.5) - } - GlobalF = x -} - -func BenchmarkCosh(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Cosh(2.5) - } - GlobalF = x -} - -func BenchmarkErf(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Erf(.5) - } - GlobalF = x -} - -func BenchmarkErfc(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Erfc(.5) - } - GlobalF = x -} - -func BenchmarkErfinv(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Erfinv(.5) - } - GlobalF = x -} - -func BenchmarkErfcinv(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Erfcinv(.5) - } - GlobalF = x -} - -func BenchmarkExp(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Exp(.5) - } - GlobalF = x -} - -func BenchmarkExpGo(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.ExpGo(.5) - } - GlobalF = x -} - -func BenchmarkExpm1(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Expm1(.5) - } - GlobalF = x -} - -func BenchmarkExp2(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Exp2(.5) - } - GlobalF = x -} - -func BenchmarkExp2Go(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Exp2Go(.5) - } - GlobalF = x -} - -var absPos = .5 - -func BenchmarkAbs(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Abs(absPos) - } - GlobalF = x -} - -func BenchmarkDim(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Dim(GlobalF, x) - } - GlobalF = x -} - -func BenchmarkFloor(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Floor(.5) - } - GlobalF = x -} - -func BenchmarkMax(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Max(10, 3) - } - GlobalF = x -} - -func BenchmarkMin(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Min(10, 3) - } - GlobalF = x -} - -func BenchmarkMod(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Mod(10, 3) - } - GlobalF = x -} - -func BenchmarkFrexp(b *testing.B) { - x := 0.0 - y := 0 - for i := 0; i < b.N; i++ { - x, y = math.Frexp(8) - } - GlobalF = x - GlobalI = y -} - -func BenchmarkGamma(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Gamma(2.5) - } - GlobalF = x -} - -func BenchmarkHypot(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Hypot(3, 4) - } - GlobalF = x -} - -func BenchmarkHypotGo(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.HypotGo(3, 4) - } - GlobalF = x -} - -func BenchmarkIlogb(b *testing.B) { - x := 0 - for i := 0; i < b.N; i++ { - x = math.Ilogb(.5) - } - GlobalI = x -} - -func BenchmarkJ0(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.J0(2.5) - } - GlobalF = x -} - -func BenchmarkJ1(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.J1(2.5) - } - GlobalF = x -} - -func BenchmarkJn(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Jn(2, 2.5) - } - GlobalF = x -} - -func BenchmarkLdexp(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Ldexp(.5, 2) - } - GlobalF = x -} - -func BenchmarkLgamma(b *testing.B) { - x := 0.0 - y := 0 - for i := 0; i < b.N; i++ { - x, y = math.Lgamma(2.5) - } - GlobalF = x - GlobalI = y -} - -func BenchmarkLog(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Log(.5) - } - GlobalF = x -} - -func BenchmarkLogb(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Logb(.5) - } - GlobalF = x -} - -func BenchmarkLog1p(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Log1p(.5) - } - GlobalF = x -} - -func BenchmarkLog10(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Log10(.5) - } - GlobalF = x -} - -func BenchmarkLog2(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Log2(.5) - } - GlobalF += x -} - -func BenchmarkModf(b *testing.B) { - x := 0.0 - y := 0.0 - for i := 0; i < b.N; i++ { - x, y = math.Modf(1.5) - } - GlobalF += x - GlobalF += y -} - -func BenchmarkNextafter32(b *testing.B) { - x := float32(0.0) - for i := 0; i < b.N; i++ { - x = math.Nextafter32(.5, 1) - } - GlobalF = float64(x) -} - -func BenchmarkNextafter64(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Nextafter(.5, 1) - } - GlobalF = x -} - -func BenchmarkPowInt(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Pow(2, 2) - } - GlobalF = x -} - -func BenchmarkPowFrac(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Pow(2.5, 1.5) - } - GlobalF = x -} - -var pow10pos = int(300) - -func BenchmarkPow10Pos(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Pow10(pow10pos) - } - GlobalF = x -} - -var pow10neg = int(-300) - -func BenchmarkPow10Neg(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Pow10(pow10neg) - } - GlobalF = x -} - -var roundNeg = float64(-2.5) - -func BenchmarkRound(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Round(roundNeg) - } - GlobalF = x -} - -func BenchmarkRoundToEven(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.RoundToEven(roundNeg) - } - GlobalF = x -} - -func BenchmarkRemainder(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Remainder(10, 3) - } - GlobalF = x -} - -var signbitPos = 2.5 - -func BenchmarkSignbit(b *testing.B) { - x := false - for i := 0; i < b.N; i++ { - x = math.Signbit(signbitPos) - } - GlobalB = x -} - -func BenchmarkSin(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Sin(.5) - } - GlobalF = x -} - -func BenchmarkSincos(b *testing.B) { - x := 0.0 - y := 0.0 - for i := 0; i < b.N; i++ { - x, y = math.Sincos(.5) - } - GlobalF += x - GlobalF += y -} - -func BenchmarkSinh(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Sinh(2.5) - } - GlobalF = x -} - -func BenchmarkSqrtIndirect(b *testing.B) { - x, y := 0.0, 10.0 - f := math.Sqrt - for i := 0; i < b.N; i++ { - x += f(y) - } - GlobalF = x -} - -func BenchmarkSqrtLatency(b *testing.B) { - x := 10.0 - for i := 0; i < b.N; i++ { - x = math.Sqrt(x) - } - GlobalF = x -} - -func BenchmarkSqrtIndirectLatency(b *testing.B) { - x := 10.0 - f := math.Sqrt - for i := 0; i < b.N; i++ { - x = f(x) - } - GlobalF = x -} - -func BenchmarkSqrtGoLatency(b *testing.B) { - x := 10.0 - for i := 0; i < b.N; i++ { - x = math.SqrtGo(x) - } - GlobalF = x -} - -func isPrime(i int) bool { - // Yes, this is a dumb way to write this code, - // but calling Sqrt repeatedly in this way demonstrates - // the benefit of using a direct SQRT instruction on systems - // that have one, whereas the obvious loop seems not to - // demonstrate such a benefit. - for j := 2; float64(j) <= math.Sqrt(float64(i)); j++ { - if i%j == 0 { - return false - } - } - return true -} - -func BenchmarkSqrtPrime(b *testing.B) { - x := false - for i := 0; i < b.N; i++ { - x = isPrime(100003) - } - GlobalB = x -} - -func BenchmarkTan(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Tan(.5) - } - GlobalF = x -} - -func BenchmarkTanh(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Tanh(2.5) - } - GlobalF = x -} - -func BenchmarkTrunc(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Trunc(.5) - } - GlobalF = x -} - -func BenchmarkY0(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Y0(2.5) - } - GlobalF = x -} - -func BenchmarkY1(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Y1(2.5) - } - GlobalF = x -} - -func BenchmarkYn(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Yn(2, 2.5) - } - GlobalF = x -} - -func BenchmarkFloat64bits(b *testing.B) { - y := uint64(0) - for i := 0; i < b.N; i++ { - y = math.Float64bits(roundNeg) - } - GlobalI = int(y) -} - -var roundUint64 = uint64(5) - -func BenchmarkFloat64frombits(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.Float64frombits(roundUint64) - } - GlobalF = x -} - -var roundFloat32 = float32(-2.5) - -func BenchmarkFloat32bits(b *testing.B) { - y := uint32(0) - for i := 0; i < b.N; i++ { - y = math.Float32bits(roundFloat32) - } - GlobalI = int(y) -} - -var roundUint32 = uint32(5) - -func BenchmarkFloat32frombits(b *testing.B) { - x := float32(0.0) - for i := 0; i < b.N; i++ { - x = math.Float32frombits(roundUint32) - } - GlobalF = float64(x) -} - -func BenchmarkFMA(b *testing.B) { - x := 0.0 - for i := 0; i < b.N; i++ { - x = math.FMA(math.E, math.Pi, x) - } - GlobalF = x -} diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index f6bd789f1bf..8ab60145bd5 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -13,7 +13,6 @@ import ( "strconv" "strings" - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/stdlibs" teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" @@ -54,7 +53,7 @@ func TestContext(pkgPath string, send std.Coins) *teststd.TestExecContext { pkgAddr := gno.DerivePkgAddr(pkgPath) // the addr of the pkgPath called. caller := gno.DerivePkgAddr("user1.gno") - pkgCoins := std.MustParseCoins(ugnot.ValueString(200000000)).Add(send) // >= send. + pkgCoins := std.MustParseCoins("200000000ugnot").Add(send) // >= send. banker := newTestBanker(pkgAddr.Bech32(), pkgCoins) ctx := stdlibs.ExecContext{ ChainID: "dev", @@ -110,7 +109,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { opt(&f) } - directives, pkgPath, resWanted, errWanted, rops, stacktraceWanted, maxAlloc, send := wantedFromComment(path) + directives, pkgPath, resWanted, errWanted, rops, maxAlloc, send := wantedFromComment(path) if pkgPath == "" { pkgPath = "main" } @@ -125,7 +124,6 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { store := TestStore(rootDir, "./files", stdin, stdout, stderr, mode) store.SetLogStoreOps(true) m := testMachineCustom(store, pkgPath, stdout, maxAlloc, send) - checkMachineIsEmpty := true // TODO support stdlib groups, but make testing safe; // e.g. not be able to make network connections. @@ -261,8 +259,6 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { errstr = v.Sprint(m) case *gno.PreprocessError: errstr = v.Unwrap().Error() - case gno.UnhandledPanicError: - errstr = v.Error() default: errstr = strings.TrimSpace(fmt.Sprintf("%v", pnc)) } @@ -283,7 +279,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { // NOTE: ignores any gno.GetDebugErrors(). gno.ClearDebugErrors() - checkMachineIsEmpty = false // nothing more to do. + return nil // nothing more to do. } else { // record errors when errWanted is empty and pnc not nil if pnc != nil { @@ -311,7 +307,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { panic(fmt.Sprintf("fail on %s: got unexpected debug error(s): %v", path, gno.GetDebugErrors())) } // pnc is nil, errWanted empty, no gno debug errors - checkMachineIsEmpty = false + return nil } case "Output": // panic if got unexpected error @@ -377,51 +373,24 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { } } } - case "Stacktrace": - if stacktraceWanted != "" { - var stacktrace string - - switch pnc.(type) { - case gno.UnhandledPanicError: - stacktrace = m.ExceptionsStacktrace() - default: - stacktrace = m.Stacktrace().String() - } - - if !strings.Contains(stacktrace, stacktraceWanted) { - diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ - A: difflib.SplitLines(stacktraceWanted), - B: difflib.SplitLines(stacktrace), - FromFile: "Expected", - FromDate: "", - ToFile: "Actual", - ToDate: "", - Context: 1, - }) - panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff)) - } - } - checkMachineIsEmpty = false default: - checkMachineIsEmpty = false + return nil } } } - if checkMachineIsEmpty { - // Check that machine is empty. - err = m.CheckEmpty() - if err != nil { - if f.logger != nil { - f.logger("last state: \n", m.String()) - } - panic(fmt.Sprintf("fail on %s: machine not empty after main: %v", path, err)) + // Check that machine is empty. + err = m.CheckEmpty() + if err != nil { + if f.logger != nil { + f.logger("last state: \n", m.String()) } + panic(fmt.Sprintf("fail on %s: machine not empty after main: %v", path, err)) } return nil } -func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops, stacktrace string, maxAlloc int64, send std.Coins) { +func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops string, maxAlloc int64, send std.Coins) { fset := token.NewFileSet() f, err2 := parser.ParseFile(fset, p, nil, parser.ParseComments) if err2 != nil { @@ -463,10 +432,6 @@ func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops, rops = strings.TrimPrefix(text, "Realm:\n") rops = strings.TrimSpace(rops) directives = append(directives, "Realm") - } else if strings.HasPrefix(text, "Stacktrace:\n") { - stacktrace = strings.TrimPrefix(text, "Stacktrace:\n") - stacktrace = strings.TrimSpace(stacktrace) - directives = append(directives, "Stacktrace") } else { // ignore unexpected. } diff --git a/gnovm/tests/files/a31.gno b/gnovm/tests/files/a31.gno index 052ab673cf2..d687b098e7c 100644 --- a/gnovm/tests/files/a31.gno +++ b/gnovm/tests/files/a31.gno @@ -2,10 +2,10 @@ package main func main() { for range []int{0, 1, 2} { - print("hello,") + print("hello ") } println("") } // Output: -// hello,hello,hello, +// hello hello hello diff --git a/gnovm/tests/files/assign_unnamed_type/unnamedtype5_filetest.gno b/gnovm/tests/files/assign_unnamed_type/unnamedtype5_filetest.gno index 0c15ce1ae02..583e2f12bd8 100644 --- a/gnovm/tests/files/assign_unnamed_type/unnamedtype5_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/unnamedtype5_filetest.gno @@ -34,8 +34,8 @@ func main() { // Output: // 1 (inc main.op) -// 0 func(n int)( int){...} +// 0 // -1 dec -// 0 (func(n int)( int){...} main.op) +// 0 ( main.op) // -1 dec // 1 inc diff --git a/gnovm/tests/files/assign_unnamed_type/unnamedtype5a_filetest.gno b/gnovm/tests/files/assign_unnamed_type/unnamedtype5a_filetest.gno index 165dd8e18a4..e14e64e4dfd 100644 --- a/gnovm/tests/files/assign_unnamed_type/unnamedtype5a_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/unnamedtype5a_filetest.gno @@ -27,7 +27,6 @@ func main() { } // Output: -// func(n int)( int){...} // 1 -// (func(n int)( int){...} main.op) +// ( main.op) // -1 diff --git a/gnovm/tests/files/cap1.gno b/gnovm/tests/files/cap1.gno deleted file mode 100644 index e382357ca11..00000000000 --- a/gnovm/tests/files/cap1.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - exp := [...]string{"HELLO"} - x := cap(&exp) - println(x) -} - -// Output: -// 1 diff --git a/gnovm/tests/files/cap10.gno b/gnovm/tests/files/cap10.gno deleted file mode 100644 index a76c723f77a..00000000000 --- a/gnovm/tests/files/cap10.gno +++ /dev/null @@ -1,8 +0,0 @@ -package main - -func main() { - println("cap", cap(struct{ A int }{})) -} - -// Error: -// unexpected type for cap(): struct{A int} diff --git a/gnovm/tests/files/cap2.gno b/gnovm/tests/files/cap2.gno deleted file mode 100644 index a834c17b474..00000000000 --- a/gnovm/tests/files/cap2.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - exp := [...]int{1, 2, 3, 4, 5} - println(cap(exp)) -} - -// Output: -// 5 diff --git a/gnovm/tests/files/cap3.gno b/gnovm/tests/files/cap3.gno deleted file mode 100644 index c5b323338d8..00000000000 --- a/gnovm/tests/files/cap3.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - slice := make([]int, 3, 5) - println(cap(slice)) -} - -// Output: -// 5 diff --git a/gnovm/tests/files/cap4.gno b/gnovm/tests/files/cap4.gno deleted file mode 100644 index 758001358fa..00000000000 --- a/gnovm/tests/files/cap4.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - var slice []int - println(cap(slice)) -} - -// Output: -// 0 diff --git a/gnovm/tests/files/cap5.gno b/gnovm/tests/files/cap5.gno deleted file mode 100644 index ce2b6be2c42..00000000000 --- a/gnovm/tests/files/cap5.gno +++ /dev/null @@ -1,12 +0,0 @@ -package main - -func main() { - printCap(nil) -} - -func printCap(arr *[2]int) { - println(cap(arr)) -} - -// Output: -// 2 diff --git a/gnovm/tests/files/cap6.gno b/gnovm/tests/files/cap6.gno deleted file mode 100644 index 182279b7ec6..00000000000 --- a/gnovm/tests/files/cap6.gno +++ /dev/null @@ -1,31 +0,0 @@ -package main - -func main() { - var arr [5]int - var nilArr *[5]int - var nilSlice []int - var nilArr2 *[8]struct{ A, B int } - var nilMatrix *[2][3]int - - println("cap(arr): ", cap(arr)) - println("cap(&arr): ", cap(&arr)) - println("cap(nilArr): ", cap(nilArr)) - println("cap(nilSlice): ", cap(nilSlice)) - println("cap(nilArr2): ", cap(nilArr2)) - println("cap(nilMatrix):", cap(nilMatrix)) - - printCap(nil) -} - -func printCap(arr *[3]string) { - println("printCap: ", cap(arr)) -} - -// Output: -// cap(arr): 5 -// cap(&arr): 5 -// cap(nilArr): 5 -// cap(nilSlice): 0 -// cap(nilArr2): 8 -// cap(nilMatrix): 2 -// printCap: 3 diff --git a/gnovm/tests/files/cap7.gno b/gnovm/tests/files/cap7.gno deleted file mode 100644 index 73e2f11c147..00000000000 --- a/gnovm/tests/files/cap7.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - var s string - println("cap", cap(s)) -} - -// Error: -// unexpected type for cap(): string diff --git a/gnovm/tests/files/cap8.gno b/gnovm/tests/files/cap8.gno deleted file mode 100644 index 7fe9b48e28b..00000000000 --- a/gnovm/tests/files/cap8.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - var i *int - println("cap", cap(i)) -} - -// Error: -// unexpected type for cap(): *int diff --git a/gnovm/tests/files/cap9.gno b/gnovm/tests/files/cap9.gno deleted file mode 100644 index b7aad6037b4..00000000000 --- a/gnovm/tests/files/cap9.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - i := new(int) - println("cap", cap(i)) -} - -// Error: -// unexpected type for cap(): *int diff --git a/gnovm/tests/files/circular_constant.gno b/gnovm/tests/files/circular_constant.gno deleted file mode 100644 index ff25da7428d..00000000000 --- a/gnovm/tests/files/circular_constant.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -const A = B -const B = A + 1 - -func main() { -} - -// Error: -// main/files/circular_constant.gno:3:7: constant definition loop with A diff --git a/gnovm/tests/files/convert4.gno b/gnovm/tests/files/convert4.gno index e03e1d07ce3..d7ab4905f62 100644 --- a/gnovm/tests/files/convert4.gno +++ b/gnovm/tests/files/convert4.gno @@ -4,5 +4,4 @@ func main() { println(int(nil)) } -// Error: -// main/files/convert4.gno:4:10: cannot convert (undefined) to int +// Error: cannot convert (undefined) to int diff --git a/gnovm/tests/files/convert5.gno b/gnovm/tests/files/convert5.gno index e2e16c5eb83..74063709110 100644 --- a/gnovm/tests/files/convert5.gno +++ b/gnovm/tests/files/convert5.gno @@ -6,5 +6,4 @@ func main() { println(ints) } -// Error: -// main/files/convert5.gno:3:1: cannot convert (undefined) to int +// Error: cannot convert (undefined) to int diff --git a/gnovm/tests/files/defer6.gno b/gnovm/tests/files/defer6.gno index fa0d61285c3..65a8d933996 100644 --- a/gnovm/tests/files/defer6.gno +++ b/gnovm/tests/files/defer6.gno @@ -1,21 +1,21 @@ package main func f1() { - defer print("f1-begin,") + defer print("f1-begin ") f2() - defer print("f1-end,") + defer print("f1-end ") } func f2() { - defer print("f2-begin,") + defer print("f2-begin ") f3() - defer print("f2-end,") + defer print("f2-end ") } func f3() { - defer print("f3-begin,") - print("hello,") - defer print("f3-end,") + defer print("f3-begin ") + print("hello ") + defer print("f3-end ") } func main() { @@ -24,4 +24,4 @@ func main() { } // Output: -// hello,f3-end,f3-begin,f2-end,f2-begin,f1-end,f1-begin, +// hello f3-end f3-begin f2-end f2-begin f1-end f1-begin diff --git a/gnovm/tests/files/len1.gno b/gnovm/tests/files/len1.gno deleted file mode 100644 index f627fba190f..00000000000 --- a/gnovm/tests/files/len1.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - exp := [...]string{"HELLO"} - x := len(&exp) - println(x) -} - -// Output: -// 1 diff --git a/gnovm/tests/files/len2.gno b/gnovm/tests/files/len2.gno deleted file mode 100644 index 377ff01851f..00000000000 --- a/gnovm/tests/files/len2.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - exp := [...]string{"HELLO", "WORLD"} - println(len(exp)) -} - -// Output: -// 2 diff --git a/gnovm/tests/files/len3.gno b/gnovm/tests/files/len3.gno deleted file mode 100644 index 89fe863b20b..00000000000 --- a/gnovm/tests/files/len3.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - exp := [...]int{1, 2, 3, 4, 5} - ptr := &exp - println(len(ptr)) -} - -// Output: -// 5 diff --git a/gnovm/tests/files/len4.gno b/gnovm/tests/files/len4.gno deleted file mode 100644 index 8b24c755041..00000000000 --- a/gnovm/tests/files/len4.gno +++ /dev/null @@ -1,12 +0,0 @@ -package main - -func main() { - printLen(nil) -} - -func printLen(arr *[2]int) { - println(len(arr)) -} - -// Output: -// 2 diff --git a/gnovm/tests/files/len5.gno b/gnovm/tests/files/len5.gno deleted file mode 100644 index 7daf3c2cc07..00000000000 --- a/gnovm/tests/files/len5.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - var arr *[3]string - println(cap(arr)) -} - -// Output: -// 3 diff --git a/gnovm/tests/files/len6.gno b/gnovm/tests/files/len6.gno deleted file mode 100644 index 9656f65e08d..00000000000 --- a/gnovm/tests/files/len6.gno +++ /dev/null @@ -1,14 +0,0 @@ -package main - -func main() { - printLenCap(nil) -} - -func printLenCap(arr *[4]float64) { - println(len(arr)) - println(cap(arr)) -} - -// Output: -// 4 -// 4 diff --git a/gnovm/tests/files/len7.gno b/gnovm/tests/files/len7.gno deleted file mode 100644 index 5deccdbf331..00000000000 --- a/gnovm/tests/files/len7.gno +++ /dev/null @@ -1,8 +0,0 @@ -package main - -func main() { - println(len(new(int))) -} - -// Error: -// unexpected type for len(): *int diff --git a/gnovm/tests/files/len8.gno b/gnovm/tests/files/len8.gno deleted file mode 100644 index 6ca5a6ae8fa..00000000000 --- a/gnovm/tests/files/len8.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - println(len(struct { - A, B int - }{})) -} - -// Error: -// unexpected type for len(): struct{A int;B int} diff --git a/gnovm/tests/files/map15.gno b/gnovm/tests/files/map15.gno index 1c1775fa30b..99e28fdeeda 100644 --- a/gnovm/tests/files/map15.gno +++ b/gnovm/tests/files/map15.gno @@ -6,8 +6,8 @@ func main() { users := make(map[string]string) v := users["a"] - fmt.Println("v:", v, ";") + fmt.Println("v:", v) } // Output: -// v: ; +// v: diff --git a/gnovm/tests/files/method27.gno b/gnovm/tests/files/method27.gno index ccb3c53d250..cb046d27449 100644 --- a/gnovm/tests/files/method27.gno +++ b/gnovm/tests/files/method27.gno @@ -13,8 +13,8 @@ type AuthenticatedRequest struct { func main() { a := &AuthenticatedRequest{} - fmt.Println("ua:", a.UserAgent(), ";") + fmt.Println("ua:", a.UserAgent()) } // Output: -// ua: ; +// ua: diff --git a/gnovm/tests/files/panic0.gno b/gnovm/tests/files/panic0.gno index 06460ca9d07..66a38b42c46 100644 --- a/gnovm/tests/files/panic0.gno +++ b/gnovm/tests/files/panic0.gno @@ -4,10 +4,5 @@ func main() { panic("wtf") } -// Stacktrace: -// panic: wtf -// main() -// main/files/panic0.gno:4 - // Error: // wtf diff --git a/gnovm/tests/files/panic0a.gno b/gnovm/tests/files/panic0a.gno deleted file mode 100644 index 575bb7cce91..00000000000 --- a/gnovm/tests/files/panic0a.gno +++ /dev/null @@ -1,45 +0,0 @@ -// Test panic with function call with all kind of expressions -package main - -type S struct { - s string -} - -func f(it1 int, it2, it3 int, pit *int, b bool, strs []string, s S, m map[string]string, t func(s string) string) { - panic("wtf") -} - -func main() { - vit := 1 - lit := []int{1} - var ( - pit *int = &vit - v interface{} - ) - b := true - v = 1 - - f( - v.(int), - lit[0], - *pit, - &vit, - !b, - []string{"a", "b"}, - S{s: "c"}, - map[string]string{"d": "gg", "test": "test"}, - func(s string) string { - return s - }, - ) -} - -// Stacktrace: -// panic: wtf -// f(v.((const-type int)),lit[0],*pit,&vit,!b,[](const-type string),S,map[(const-type string)] (const-type string),func(s (const-type string)) (const-type string){ ... }) -// main/files/panic0a.gno:9 -// main() -// main/files/panic0a.gno:22 - -// Error: -// wtf diff --git a/gnovm/tests/files/panic0b.gno b/gnovm/tests/files/panic0b.gno index 55a7b21015a..bf3b343f785 100644 --- a/gnovm/tests/files/panic0b.gno +++ b/gnovm/tests/files/panic0b.gno @@ -14,19 +14,6 @@ func f() { panic("first") } -// Stacktrace: -// panic: first -// f() -// main/files/panic0b.gno:14 -// main() -// main/files/panic0b.gno:4 -// ... 1 panic(s) elided ... -// panic: third -// f() -// main/files/panic0b.gno:9 -// main() -// main/files/panic0b.gno:4 - // Error: // first // second diff --git a/gnovm/tests/files/panic0c.gno b/gnovm/tests/files/panic0c.gno deleted file mode 100644 index c331ee3bd17..00000000000 --- a/gnovm/tests/files/panic0c.gno +++ /dev/null @@ -1,87 +0,0 @@ -package main - -type S struct { - s string -} - -func f( - s string, - b bool, - by byte, - it int, - it8 int8, - it16 int16, - it32 int32, - it64 int64, - uit uint, - uit8 uint8, - uit16 uint16, - uit32 uint32, - uit64 uint64, - ft32 float32, - ft64 float64, - strs []string, - st S, - m map[string]string, - t func(s string) string, -) { - panic("wtf") -} - -func main() { - strs := []string{"a", "b"} - st := S{"c"} - m := map[string]string{"d": "gg", "test": "test"} - t := func(s string) string { - return s - } - - const s string = "a" - - const b bool = true - - const by byte = 0 - - const it int = 1 - const it8 int8 = 1 - const it16 int16 = 1 - const it32 int32 = 1 - const it64 int64 = 1 - const uit uint = 1 - const uit8 uint8 = 1 - const uit16 uint16 = 1 - const uit32 uint32 = 1 - const uit64 uint64 = 1 - const ft32 float32 = 1 - const ft64 float64 = 1 - f( - s, - b, - by, - it, - it8, - it16, - it32, - it64, - uit, - uit8, - uit16, - uit32, - uit64, - ft32, - ft64, - strs, - st, - m, - t) -} - -// Stacktrace: -// panic: wtf -// f(a,true,0,1,1,1,1,1,1,1,1,1,1,1,1,strs,st,m,t) -// main/files/panic0c.gno:28 -// main() -// main/files/panic0c.gno:57 - -// Error: -// wtf diff --git a/gnovm/tests/files/panic1.gno b/gnovm/tests/files/panic1.gno index 235ba4a0b34..483d43e53d1 100644 --- a/gnovm/tests/files/panic1.gno +++ b/gnovm/tests/files/panic1.gno @@ -22,10 +22,5 @@ func main() { panic("here") } -// Stacktrace: -// panic: here -// main() -// main/files/panic1.gno:22 - // Error: // here diff --git a/gnovm/tests/files/panic2a.gno b/gnovm/tests/files/panic2a.gno deleted file mode 100644 index 7310d6cce71..00000000000 --- a/gnovm/tests/files/panic2a.gno +++ /dev/null @@ -1,275 +0,0 @@ -package main - -func p(i int) { - if i == 200 { - panic("here") - } - p(i + 1) -} - -func main() { - p(0) -} - -// Stacktrace: -// panic: here -// p(i + 1) -// main/files/panic2a.gno:5 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// ...74 frame(s) elided... -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(i + 1) -// main/files/panic2a.gno:7 -// p(0) -// main/files/panic2a.gno:7 -// main() -// main/files/panic2a.gno:11 - -// Error: -// here diff --git a/gnovm/tests/files/panic2b.gno b/gnovm/tests/files/panic2b.gno deleted file mode 100644 index 7c356409aad..00000000000 --- a/gnovm/tests/files/panic2b.gno +++ /dev/null @@ -1,44 +0,0 @@ -package main - -func p(i int) { - defer func() { - panic("here") - }() - if i == 4 { - panic("here") - } - p(i + 1) -} - -func main() { - p(0) -} - -// Stacktrace: -// panic: here -// p(i + 1) -// main/files/panic2b.gno:8 -// p(i + 1) -// main/files/panic2b.gno:10 -// p(i + 1) -// main/files/panic2b.gno:10 -// p(i + 1) -// main/files/panic2b.gno:10 -// p(0) -// main/files/panic2b.gno:10 -// main() -// main/files/panic2b.gno:14 -// ... 4 panic(s) elided ... -// panic: here -// p(0) -// main/files/panic2b.gno:5 -// main() -// main/files/panic2b.gno:14 - -// Error: -// here -// here -// here -// here -// here -// here diff --git a/gnovm/tests/files/recover10.gno b/gnovm/tests/files/recover10.gno index de083a322a4..16dff4d4fed 100644 --- a/gnovm/tests/files/recover10.gno +++ b/gnovm/tests/files/recover10.gno @@ -6,10 +6,5 @@ func main() { panic("ahhhhh") } -// Stacktrace: -// panic: ahhhhh -// main() -// main/files/recover10.gno:6 - // Error: // ahhhhh diff --git a/gnovm/tests/files/recover1b.gno b/gnovm/tests/files/recover1b.gno index 978b4988329..9e3b9ba72b6 100644 --- a/gnovm/tests/files/recover1b.gno +++ b/gnovm/tests/files/recover1b.gno @@ -10,10 +10,5 @@ func main() { panic("test panic") } -// Stacktrace: -// panic: other panic -// main() -// main/files/recover1b.gno:8 - // Error: // other panic diff --git a/gnovm/tests/files/recover8.gno b/gnovm/tests/files/recover8.gno index d144a4f986f..53b31f05468 100644 --- a/gnovm/tests/files/recover8.gno +++ b/gnovm/tests/files/recover8.gno @@ -20,12 +20,5 @@ func main() { doSomething() } -// Stacktrace: -// panic: do something panic -// doSomething() -// main/files/recover8.gno:7 -// main() -// main/files/recover8.gno:20 - // Error: // do something panic diff --git a/gnovm/tests/files/recursive1.gno b/gnovm/tests/files/recursive1.gno deleted file mode 100644 index 8279e247d84..00000000000 --- a/gnovm/tests/files/recursive1.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -type S struct { - T S -} - -func main() { - var a, b S - println(a == b) -} - -// Error: -// main/files/recursive1.gno:1:1: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive1a.gno b/gnovm/tests/files/recursive1a.gno deleted file mode 100644 index 87681e1fcdd..00000000000 --- a/gnovm/tests/files/recursive1a.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -type S1 *S - -type S struct { - T S1 -} - -func main() { - var a, b S - println(a == b) -} - -// Output: -// true \ No newline at end of file diff --git a/gnovm/tests/files/recursive1b.gno b/gnovm/tests/files/recursive1b.gno deleted file mode 100644 index 2893baf8fca..00000000000 --- a/gnovm/tests/files/recursive1b.gno +++ /dev/null @@ -1,16 +0,0 @@ -package main - -type S struct { - T *S - B Integer -} - -type Integer int - -func main() { - var a, b S - println(a == b) -} - -// Output: -// true diff --git a/gnovm/tests/files/recursive1c.gno b/gnovm/tests/files/recursive1c.gno deleted file mode 100644 index 7797f375027..00000000000 --- a/gnovm/tests/files/recursive1c.gno +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import "fmt" - -type S struct { - A [2][2]S -} - -func main() { - var a, b S - - fmt.Println(a) - fmt.Println(b) -} - -// Error: -// main/files/recursive1c.gno:1:1: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive1d.gno b/gnovm/tests/files/recursive1d.gno deleted file mode 100644 index 22bf172b5ac..00000000000 --- a/gnovm/tests/files/recursive1d.gno +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import "fmt" - -type S struct { - A [2]S -} - -func main() { - var a, b S - - fmt.Println(a) - fmt.Println(b) -} - -// Error: -// main/files/recursive1d.gno:1:1: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive1e.gno b/gnovm/tests/files/recursive1e.gno deleted file mode 100644 index 6d1636ba9f3..00000000000 --- a/gnovm/tests/files/recursive1e.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -type S struct { - A [2][]S -} - -func main() { - var a, b S - println(a) -} - -// Output: -// (struct{(array[(nil []main.S),(nil []main.S)] [2][]main.S)} main.S) diff --git a/gnovm/tests/files/recursive1f.gno b/gnovm/tests/files/recursive1f.gno deleted file mode 100644 index 81fe2a5699c..00000000000 --- a/gnovm/tests/files/recursive1f.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -func main() { - type S struct { - T S - } - - var a, b S - println(a == b) -} - -// Error: -// main/files/recursive1f.gno:3:1: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive2.gno b/gnovm/tests/files/recursive2.gno deleted file mode 100644 index 4ed86f03d58..00000000000 --- a/gnovm/tests/files/recursive2.gno +++ /dev/null @@ -1,21 +0,0 @@ -package main - -type A struct { - X B -} - -type B struct { - X C -} - -type C struct { - X A -} - -func main() { - var p, q A - println(p == q) -} - -// Error: -// main/files/recursive2.gno:1:1: invalid recursive type: A -> B -> C -> A diff --git a/gnovm/tests/files/recursive2a.gno b/gnovm/tests/files/recursive2a.gno deleted file mode 100644 index 9c7dd3e179f..00000000000 --- a/gnovm/tests/files/recursive2a.gno +++ /dev/null @@ -1,21 +0,0 @@ -package main - -type A struct { - X B -} - -type B struct { - X int -} - -type C struct { - X A -} - -func main() { - var p, q A - println(p == q) -} - -// Output: -// true diff --git a/gnovm/tests/files/recursive2b.gno b/gnovm/tests/files/recursive2b.gno deleted file mode 100644 index 92d633cdda1..00000000000 --- a/gnovm/tests/files/recursive2b.gno +++ /dev/null @@ -1,21 +0,0 @@ -package main - -type A struct { - X B -} - -type B struct { - X C -} - -type C struct { - X *A -} - -func main() { - var p, q A - println(p == q) -} - -// Output: -// true diff --git a/gnovm/tests/files/recursive2c.gno b/gnovm/tests/files/recursive2c.gno deleted file mode 100644 index 3b5c27ed8ea..00000000000 --- a/gnovm/tests/files/recursive2c.gno +++ /dev/null @@ -1,21 +0,0 @@ -package main - -func main() { - type A struct { - X B - } - - type B struct { - X C - } - - type C struct { - X A - } - - var p, q A - println(p == q) -} - -// Error: -// main/files/recursive2c.gno:3:1: name B not defined in fileset with files [files/recursive2c.gno] diff --git a/gnovm/tests/files/recursive2d.gno b/gnovm/tests/files/recursive2d.gno deleted file mode 100644 index b2439ba6259..00000000000 --- a/gnovm/tests/files/recursive2d.gno +++ /dev/null @@ -1,21 +0,0 @@ -package main - -type A struct { - X *B -} - -type B struct { - X int -} - -type C struct { - X A -} - -func main() { - var p, q A - println(p == q) -} - -// Output: -// true diff --git a/gnovm/tests/files/recursive3.gno b/gnovm/tests/files/recursive3.gno deleted file mode 100644 index 552c086c91b..00000000000 --- a/gnovm/tests/files/recursive3.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -type S struct { - T *S -} - -func main() { - var a, b S - println(a == b) -} - -// Output: -// true diff --git a/gnovm/tests/files/recursive4.gno b/gnovm/tests/files/recursive4.gno deleted file mode 100644 index 29392cb35ab..00000000000 --- a/gnovm/tests/files/recursive4.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import "time" - -type Duration struct { - t time.Duration -} - -func main() { - var a, b Duration - println(a == b) -} - -// Output: -// true diff --git a/gnovm/tests/files/recursive4a.gno b/gnovm/tests/files/recursive4a.gno deleted file mode 100644 index 8b4d13b4785..00000000000 --- a/gnovm/tests/files/recursive4a.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -type time time.Duration - -func main() { -} - -// Error: -// main/files/recursive4a.gno:1:1: invalid recursive type: time -> time diff --git a/gnovm/tests/files/recursive5.gno b/gnovm/tests/files/recursive5.gno deleted file mode 100644 index 1c2fbd89fb8..00000000000 --- a/gnovm/tests/files/recursive5.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -type S struct { - S -} - -func main() { - var a, b S - println(a == b) -} - -// Error: -// main/files/recursive5.gno:1:1: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive6.gno b/gnovm/tests/files/recursive6.gno deleted file mode 100644 index 73858b2ea1b..00000000000 --- a/gnovm/tests/files/recursive6.gno +++ /dev/null @@ -1,23 +0,0 @@ -package main - -type SelfReferencing interface { - Self() SelfReferencing -} - -type Implementation struct { - // Some implementation details... -} - -func (impl Implementation) Self() SelfReferencing { - return &impl -} - -func main() { - var obj Implementation - var intf SelfReferencing = obj - _ = intf.Self() - println("ok") -} - -// Output: -// ok diff --git a/gnovm/tests/files/recursive6a.gno b/gnovm/tests/files/recursive6a.gno deleted file mode 100644 index 8123fc626a5..00000000000 --- a/gnovm/tests/files/recursive6a.gno +++ /dev/null @@ -1,12 +0,0 @@ -package main - -type SelfReferencing interface { - SelfReferencing -} - -func main() { - println("ok") -} - -// Error: -// main/files/recursive6a.gno:1:1: invalid recursive type: SelfReferencing -> SelfReferencing diff --git a/gnovm/tests/files/recursive7.gno b/gnovm/tests/files/recursive7.gno deleted file mode 100644 index 9bd8a56995d..00000000000 --- a/gnovm/tests/files/recursive7.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -type S []S - -func main() { - println("ok") -} - -// Output: -// ok diff --git a/gnovm/tests/files/recursive7a.gno b/gnovm/tests/files/recursive7a.gno deleted file mode 100644 index b3c57516f13..00000000000 --- a/gnovm/tests/files/recursive7a.gno +++ /dev/null @@ -1,8 +0,0 @@ -package main - -type S [2]S - -func main() {} - -// Error: -// main/files/recursive7a.gno:1:1: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive8.gno b/gnovm/tests/files/recursive8.gno deleted file mode 100644 index 1f9325ae35c..00000000000 --- a/gnovm/tests/files/recursive8.gno +++ /dev/null @@ -1,8 +0,0 @@ -package main - -type Int Int - -func main() {} - -// Error: -// main/files/recursive8.gno:1:1: invalid recursive type: Int -> Int diff --git a/gnovm/tests/files/recursive9.gno b/gnovm/tests/files/recursive9.gno deleted file mode 100644 index 8181be55d33..00000000000 --- a/gnovm/tests/files/recursive9.gno +++ /dev/null @@ -1,8 +0,0 @@ -package main - -type Int = Int - -func main() {} - -// Error: -// main/files/recursive9.gno:1:1: invalid recursive type: Int -> Int diff --git a/gnovm/tests/files/recursive9a.gno b/gnovm/tests/files/recursive9a.gno deleted file mode 100644 index b96efa090e4..00000000000 --- a/gnovm/tests/files/recursive9a.gno +++ /dev/null @@ -1,8 +0,0 @@ -package main - -type Int = *Int - -func main() {} - -// Error: -// main/files/recursive9a.gno:1:1: invalid recursive type: Int -> Int \ No newline at end of file diff --git a/gnovm/tests/files/recursive9b.gno b/gnovm/tests/files/recursive9b.gno deleted file mode 100644 index e033349d597..00000000000 --- a/gnovm/tests/files/recursive9b.gno +++ /dev/null @@ -1,8 +0,0 @@ -package main - -type Int = func() Int - -func main() {} - -// Error: -// main/files/recursive9b.gno:1:1: invalid recursive type: Int -> Int \ No newline at end of file diff --git a/gnovm/tests/files/recursive9c.gno b/gnovm/tests/files/recursive9c.gno deleted file mode 100644 index ad865978920..00000000000 --- a/gnovm/tests/files/recursive9c.gno +++ /dev/null @@ -1,8 +0,0 @@ -package main - -type Int = []Int - -func main() {} - -// Error: -// main/files/recursive9c.gno:1:1: invalid recursive type: Int -> Int diff --git a/gnovm/tests/files/recursive9d.gno b/gnovm/tests/files/recursive9d.gno deleted file mode 100644 index ae7310ede0f..00000000000 --- a/gnovm/tests/files/recursive9d.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -type S = struct { - *S -} - -func main() {} - -// Error: -// main/files/recursive9d.gno:1:1: invalid recursive type: S -> S diff --git a/gnovm/tests/files/std5_stdlibs.gno b/gnovm/tests/files/std5_stdlibs.gno index 4afa09da8d3..d8de58518f1 100644 --- a/gnovm/tests/files/std5_stdlibs.gno +++ b/gnovm/tests/files/std5_stdlibs.gno @@ -11,14 +11,5 @@ func main() { println(caller2) } -// Stacktrace: -// panic: frame not found -// callerAt(n) -// gonative:std.callerAt -// std.GetCallerAt(2) -// std/native.gno:44 -// main() -// main/files/std5_stdlibs.gno:10 - // Error: // frame not found diff --git a/gnovm/tests/files/std8_stdlibs.gno b/gnovm/tests/files/std8_stdlibs.gno index ab5e15bd618..6964cec1d3d 100644 --- a/gnovm/tests/files/std8_stdlibs.gno +++ b/gnovm/tests/files/std8_stdlibs.gno @@ -21,18 +21,5 @@ func main() { testutils.WrapCall(inner) } -// Stacktrace: -// panic: frame not found -// callerAt(n) -// gonative:std.callerAt -// std.GetCallerAt(4) -// std/native.gno:44 -// fn() -// main/files/std8_stdlibs.gno:16 -// testutils.WrapCall(inner) -// gno.land/p/demo/testutils/misc.gno:5 -// main() -// main/files/std8_stdlibs.gno:21 - // Error: // frame not found diff --git a/gnovm/tests/files/time17_native.gno b/gnovm/tests/files/time17_native.gno deleted file mode 100644 index 6733c1381cb..00000000000 --- a/gnovm/tests/files/time17_native.gno +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - now := time.Now() - now.In(nil) -} - -// Error: -// time: missing Location in call to Time.In - -// Stacktrace: -// now.In(gonative{*time.Location}) -// gofunction:func(*time.Location) time.Time -// main() -// main/files/time17_native.gno:10 diff --git a/gnovm/tests/files/typeassert1.gno b/gnovm/tests/files/typeassert1.gno index f6609a3d18c..041034e4bd0 100644 --- a/gnovm/tests/files/typeassert1.gno +++ b/gnovm/tests/files/typeassert1.gno @@ -9,10 +9,5 @@ func main() { _ = a.(A) } -// Stacktrace: -// panic: interface conversion: interface is nil, not main.A -// main() -// main/files/typeassert1.gno:9 - // Error: // interface conversion: interface is nil, not main.A diff --git a/gnovm/tests/files/typeassert2a.gno b/gnovm/tests/files/typeassert2a.gno index bfbd24d38bd..0441bf83437 100644 --- a/gnovm/tests/files/typeassert2a.gno +++ b/gnovm/tests/files/typeassert2a.gno @@ -11,10 +11,5 @@ func main() { }() } -// Stacktrace: -// panic: interface conversion: interface is nil, not main.A -// main() -// main/files/typeassert2a.gno:10 - // Error: // interface conversion: interface is nil, not main.A diff --git a/gnovm/tests/files/typeassert9.gno b/gnovm/tests/files/typeassert9.gno index 6ea072661c1..d9d5bad55af 100644 --- a/gnovm/tests/files/typeassert9.gno +++ b/gnovm/tests/files/typeassert9.gno @@ -16,10 +16,5 @@ func main() { _ = reader.(Writer) } -// Stacktrace: -// panic: interface conversion: interface is nil, not main.Writer -// main() -// main/files/typeassert9.gno:16 - // Error: // interface conversion: interface is nil, not main.Writer diff --git a/gnovm/tests/files/types/cmp_databyte.gno b/gnovm/tests/files/types/cmp_databyte.gno deleted file mode 100644 index 0583ed9a259..00000000000 --- a/gnovm/tests/files/types/cmp_databyte.gno +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import "bytes" - -func main() { - cmp := bytes.Compare([]byte("hello"), []byte("hey")) - println(cmp) - -} - -// Output: -// -1 diff --git a/gnovm/tests/files/types/cmp_iface_0_stdlibs.gno b/gnovm/tests/files/types/cmp_iface_0_stdlibs.gno deleted file mode 100644 index fb4ac682243..00000000000 --- a/gnovm/tests/files/types/cmp_iface_0_stdlibs.gno +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "errors" - "strconv" -) - -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -var errCmp = errors.New("XXXX") - -// special case: -// one is interface -func main() { - if Error(0) == errCmp { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Output: -// something else diff --git a/gnovm/tests/files/types/cmp_iface_1.gno b/gnovm/tests/files/types/cmp_iface_1.gno deleted file mode 100644 index 551b4acf0f1..00000000000 --- a/gnovm/tests/files/types/cmp_iface_1.gno +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "errors" - "strconv" -) - -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -// typed -var errCmp error = errors.New("XXXX") - -// special case: -// one is interface -func main() { - const e Error = Error(0) // typed const - if e == errCmp { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Output: -// something else diff --git a/gnovm/tests/files/types/cmp_iface_2.gno b/gnovm/tests/files/types/cmp_iface_2.gno deleted file mode 100644 index f3bf14b2b7b..00000000000 --- a/gnovm/tests/files/types/cmp_iface_2.gno +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "fmt" - "strconv" -) - -type E interface { - Error() string -} -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -// special case: -// one is interface -func main() { - var e0 E - e0 = Error(0) - fmt.Printf("%T\n", e0) - if e0 == Error(0) { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Output: -// int64 -// what the firetruck? diff --git a/gnovm/tests/files/types/cmp_iface_3_stdlibs.gno b/gnovm/tests/files/types/cmp_iface_3_stdlibs.gno deleted file mode 100644 index 9c4cb0e5ea0..00000000000 --- a/gnovm/tests/files/types/cmp_iface_3_stdlibs.gno +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "errors" - "strconv" -) - -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -var errCmp = errors.New("XXXX") - -// special case: -// one is interface -func main() { - if Error(1) == errCmp { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Output: -// something else diff --git a/gnovm/tests/files/types/cmp_iface_4.gno b/gnovm/tests/files/types/cmp_iface_4.gno deleted file mode 100644 index a4ae0463291..00000000000 --- a/gnovm/tests/files/types/cmp_iface_4.gno +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "strconv" -) - -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -// both not const, and both interface -func main() { - var l interface{} - if l == Error(0) { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Output: -// something else diff --git a/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno b/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno deleted file mode 100644 index e706c74808e..00000000000 --- a/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "errors" - "strconv" -) - -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -var errCmp = errors.New("XXXX") - -// special case: -// one is interface -func main() { - if errCmp == int64(1) { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Error: -// main/files/types/cmp_iface_5_stdlibs.gno:19:5: int64 does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/cmp_iface_6.gno b/gnovm/tests/files/types/cmp_iface_6.gno deleted file mode 100644 index 6abc84992ea..00000000000 --- a/gnovm/tests/files/types/cmp_iface_6.gno +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "strconv" -) - -type E interface { - Error() string -} - -type Error1 int64 - -func (e Error1) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -type Error2 int64 - -func (e Error2) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -// both not const, and both interface -func main() { - var e1 E = Error1(0) - var e2 E = Error2(0) - println(e1 == e2) -} - -// Output: -// false diff --git a/gnovm/tests/files/types/cmp_iface_7.gno b/gnovm/tests/files/types/cmp_iface_7.gno deleted file mode 100644 index a0ba3e8a0d3..00000000000 --- a/gnovm/tests/files/types/cmp_iface_7.gno +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import "fmt" - -func check(v1, v2 interface{}) bool { - return v1 == v2 -} - -func main() { - type t1 int - type t2 int - v1 := t1(1) - v2 := t2(1) - v3 := t2(3) - - fmt.Println("v1, v2", v1, v2, check(v1, v2)) - fmt.Println("v1, v3", v1, v3, check(v1, v3)) - fmt.Println("v2, v3", v2, v3, check(v2, v3)) -} - -// Output: -// v1, v2 1 1 false -// v1, v3 1 3 false -// v2, v3 1 3 false diff --git a/gnovm/tests/files/types/cmp_primitive_0.gno b/gnovm/tests/files/types/cmp_primitive_0.gno deleted file mode 100644 index 2c968b5158f..00000000000 --- a/gnovm/tests/files/types/cmp_primitive_0.gno +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "strconv" -) - -type Error int8 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -// left is untyped const, right is typed const -// left is assignable to right -func main() { - if 1 == Error(1) { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Output: -// what the firetruck? diff --git a/gnovm/tests/files/types/cmp_primitive_1.gno b/gnovm/tests/files/types/cmp_primitive_1.gno deleted file mode 100644 index 2f2e1c94ef1..00000000000 --- a/gnovm/tests/files/types/cmp_primitive_1.gno +++ /dev/null @@ -1,22 +0,0 @@ -package main - -type Error string - -func (e Error) Error() string { - return "error: " + string(e) -} - -// left is untyped const, right is typed const -// left is not assignable to right -// a) it's (untyped) bigint -// b) base type of right is string -func main() { - if 1 == Error(1) { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Error: -// main/files/types/cmp_primitive_1.gno:14:5: cannot use untyped Bigint as StringKind diff --git a/gnovm/tests/files/types/cmp_primitive_2.gno b/gnovm/tests/files/types/cmp_primitive_2.gno deleted file mode 100644 index 34c8a24cba2..00000000000 --- a/gnovm/tests/files/types/cmp_primitive_2.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -var a int8 - -func main() { - a = 1 - if 1 == a { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Output: -// what the firetruck? diff --git a/gnovm/tests/files/types/cmp_primitive_3.gno b/gnovm/tests/files/types/cmp_primitive_3.gno deleted file mode 100644 index c1692c8019c..00000000000 --- a/gnovm/tests/files/types/cmp_primitive_3.gno +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - "strconv" -) - -type Error int8 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -// left is typed const, right is untyped const -func main() { - if Error(1) == 1 { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Output: -// what the firetruck? diff --git a/gnovm/tests/files/types/cmp_slice_0.gno b/gnovm/tests/files/types/cmp_slice_0.gno deleted file mode 100644 index 1db537a4d8c..00000000000 --- a/gnovm/tests/files/types/cmp_slice_0.gno +++ /dev/null @@ -1,20 +0,0 @@ -package main - -type S struct { - expected string -} - -// special case when RHS is result of slice operation, its type is determined in runtime -func main() { - s := S{ - expected: `hello`[:], // this is not converted - } - - a := "hello" - - println(a == s.expected) - -} - -// Output: -// true diff --git a/gnovm/tests/files/types/cmp_slice_1.gno b/gnovm/tests/files/types/cmp_slice_1.gno deleted file mode 100644 index 76f2db8d7d8..00000000000 --- a/gnovm/tests/files/types/cmp_slice_1.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - expected := `hello`[:] - a := "hello" - println(a == expected) -} - -// Output: -// true diff --git a/gnovm/tests/files/types/cmp_slice_2.gno b/gnovm/tests/files/types/cmp_slice_2.gno deleted file mode 100644 index 018d53fa81a..00000000000 --- a/gnovm/tests/files/types/cmp_slice_2.gno +++ /dev/null @@ -1,14 +0,0 @@ -package main - -type S struct { - expected string -} - -func main() { - println("hello" == S{ - expected: `hello`[:], - }.expected) -} - -// Output: -// true diff --git a/gnovm/tests/files/types/cmp_slice_3.gno b/gnovm/tests/files/types/cmp_slice_3.gno deleted file mode 100644 index 2795d618e91..00000000000 --- a/gnovm/tests/files/types/cmp_slice_3.gno +++ /dev/null @@ -1,16 +0,0 @@ -package main - -type S struct { - expected string -} - -func main() { - var s = S{ - expected: `hello`[:], - } - a := "hello" - println(a == s.expected) -} - -// Output: -// true diff --git a/gnovm/tests/files/types/cmp_slice_4.gno b/gnovm/tests/files/types/cmp_slice_4.gno deleted file mode 100644 index 2bdd3191eff..00000000000 --- a/gnovm/tests/files/types/cmp_slice_4.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - expected := `hello`[:] - a := 1 - println(a == expected) // both typed -} - -// Error: -// main/files/types/cmp_slice_4.gno:6:10: cannot use int as string diff --git a/gnovm/tests/files/types/cmp_typeswitch.gno b/gnovm/tests/files/types/cmp_typeswitch.gno deleted file mode 100644 index 721dfc9579a..00000000000 --- a/gnovm/tests/files/types/cmp_typeswitch.gno +++ /dev/null @@ -1,18 +0,0 @@ -package main - -func main() { - var l interface{} - l = int64(0) - - switch val := l.(type) { - case int64, int: - if val == 0 { - println("l is zero") - } else { - println("NOT zero") - } - } -} - -// Output: -// NOT zero diff --git a/gnovm/tests/files/types/cmp_typeswitch_a.gno b/gnovm/tests/files/types/cmp_typeswitch_a.gno deleted file mode 100644 index f70fcb3d3d6..00000000000 --- a/gnovm/tests/files/types/cmp_typeswitch_a.gno +++ /dev/null @@ -1,18 +0,0 @@ -package main - -func main() { - var l interface{} - l = int(0) - - switch val := l.(type) { - case int64, int: - if val == 0 { - println("l is zero") - } else { - println("NOT zero") - } - } -} - -// Output: -// l is zero diff --git a/gnovm/tests/files/types/eql_0f2d.gno b/gnovm/tests/files/types/eql_0f2d.gno index f3bf14b2b7b..5ad121f515b 100644 --- a/gnovm/tests/files/types/eql_0f2d.gno +++ b/gnovm/tests/files/types/eql_0f2d.gno @@ -19,7 +19,7 @@ func (e Error) Error() string { func main() { var e0 E e0 = Error(0) - fmt.Printf("%T\n", e0) + fmt.Printf("%T \n", e0) if e0 == Error(0) { println("what the firetruck?") } else { diff --git a/gnovm/tests/files/types/eql_0f2e.gno b/gnovm/tests/files/types/eql_0f2e.gno index c9c24dcd4eb..ea03028f5e1 100644 --- a/gnovm/tests/files/types/eql_0f2e.gno +++ b/gnovm/tests/files/types/eql_0f2e.gno @@ -19,7 +19,7 @@ func (e Error) Error() string { func main() { var e0 E e0 = Error(0) - fmt.Printf("%T\n", e0) + fmt.Printf("%T \n", e0) if Error(0) == e0 { println("what the firetruck?") } else { diff --git a/gnovm/tests/files/types/eql_0f49.gno b/gnovm/tests/files/types/eql_0f49.gno deleted file mode 100644 index b5a4bf4ed05..00000000000 --- a/gnovm/tests/files/types/eql_0f49.gno +++ /dev/null @@ -1,21 +0,0 @@ -package main - -func main() { - a := "1234" - b := "1234" - - cond := a == b - println(cond) - println(cond == (a == b)) - println((a == b) == cond) - println((a == b) == (a == b)) - println(cond && (a == b)) - println(cond || (a > b)) - -} - -// true -// true -// true -// true -// true diff --git a/gnovm/tests/files/types/iface_eql.gno b/gnovm/tests/files/types/iface_eql.gno deleted file mode 100644 index 97daa27c184..00000000000 --- a/gnovm/tests/files/types/iface_eql.gno +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - var l interface{} = 1 - println(int8(1) == l) -} - -// Output: -// false diff --git a/gnovm/tests/files/types/runtime_a2.gno b/gnovm/tests/files/types/runtime_a2.gno index 0c1b8453591..d53c9c4d970 100644 --- a/gnovm/tests/files/types/runtime_a2.gno +++ b/gnovm/tests/files/types/runtime_a2.gno @@ -8,7 +8,7 @@ func gen() interface{} { func main() { r := gen() - fmt.Printf("%T\n", r) + fmt.Printf("%T \n", r) } // Output: diff --git a/gnovm/tests/files/types/shift_a12.gno b/gnovm/tests/files/types/shift_a12.gno index 272373b19a6..5735854d684 100644 --- a/gnovm/tests/files/types/shift_a12.gno +++ b/gnovm/tests/files/types/shift_a12.gno @@ -6,7 +6,7 @@ func main() { a := uint(1) r := uint64(1) << a println(r) - fmt.Printf("%T\n", r) + fmt.Printf("%T \n", r) } // Output: diff --git a/gnovm/tests/files/types/shift_a13.gno b/gnovm/tests/files/types/shift_a13.gno index 4ff5c6b7753..7d70cc3589a 100644 --- a/gnovm/tests/files/types/shift_a13.gno +++ b/gnovm/tests/files/types/shift_a13.gno @@ -4,7 +4,7 @@ import "fmt" func main() { var r uint64 = 1 << int8(1) - fmt.Printf("%T\n", r) + fmt.Printf("%T \n", r) println(r) } diff --git a/gnovm/tests/files/var19.gno b/gnovm/tests/files/var19.gno index 99d7452f603..cbdce802e0a 100644 --- a/gnovm/tests/files/var19.gno +++ b/gnovm/tests/files/var19.gno @@ -2,7 +2,6 @@ package main func main() { var a, b, c = 1, a+1 - println(a) println(b) println(c) diff --git a/gnovm/tests/files/var20.gno b/gnovm/tests/files/var20.gno index 6e15fcca6c5..e2455cbaed8 100644 --- a/gnovm/tests/files/var20.gno +++ b/gnovm/tests/files/var20.gno @@ -9,4 +9,4 @@ func main() { } // Error: -// main/files/var20.gno:8:6: assignment mismatch: 3 variable(s) but r() returns 1 value(s) +// main/files/var20.gno:8:6: assignment mismatch: 3 variable(s) but r returns 1 value(s) diff --git a/gnovm/tests/files/var29.gno b/gnovm/tests/files/var29.gno deleted file mode 100644 index a37ccddd240..00000000000 --- a/gnovm/tests/files/var29.gno +++ /dev/null @@ -1,14 +0,0 @@ -package main - -func main() { - println(a) - println(b) - println(c) -} - -var a, b, c = 1, a + 1, b + 1 - -// Output: -// 1 -// 2 -// 3 \ No newline at end of file diff --git a/gnovm/tests/files/var30.gno b/gnovm/tests/files/var30.gno deleted file mode 100644 index c8c9efabdef..00000000000 --- a/gnovm/tests/files/var30.gno +++ /dev/null @@ -1,17 +0,0 @@ -package main - -func main() { - println(a) - println(b) - println(c) - println(d) -} - -var a, b, c = 1, a + d, 3 -var d = a - -// Output: -// 1 -// 2 -// 3 -// 1 \ No newline at end of file diff --git a/gnovm/tests/files/vardecl.gno b/gnovm/tests/files/vardecl.gno deleted file mode 100644 index 34390f26a6a..00000000000 --- a/gnovm/tests/files/vardecl.gno +++ /dev/null @@ -1,23 +0,0 @@ -package main - -func main() { - var i interface{} = 1 - var a, ok = i.(int) - println(a, ok) - - var b, c = doSomething() - println(b, c) - - m := map[string]int{"a": 1, "b": 2} - var d, okk = m["d"] - println(d, okk) -} - -func doSomething() (int, string) { - return 4, "hi" -} - -// Output: -// 1 true -// 4 hi -// 0 false diff --git a/gnovm/tests/files/zrealm_panic.gno b/gnovm/tests/files/zrealm_panic.gno deleted file mode 100644 index 3864e2a7f7f..00000000000 --- a/gnovm/tests/files/zrealm_panic.gno +++ /dev/null @@ -1,20 +0,0 @@ -// PKGPATH: gno.land/r/test -package test - -type MyStruct struct{} - -func (ms MyStruct) Panic() { - panic("panic") -} - -func main() { - ms := MyStruct{} - ms.Panic() -} - -// Stacktrace: -// panic: panic -// ms.Panic() -// gno.land/r/test/main.gno:7 -// main() -// gno.land/r/test/main.gno:12 diff --git a/go.mod b/go.mod index d890ab020a4..d0845d73641 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.22 toolchain go1.22.4 require ( - dario.cat/mergo v1.0.1 + dario.cat/mergo v1.0.0 github.com/btcsuite/btcd/btcec/v2 v2.3.4 - github.com/btcsuite/btcd/btcutil v1.1.6 + github.com/btcsuite/btcd/btcutil v1.1.5 github.com/cockroachdb/apd/v3 v3.2.1 github.com/cosmos/ledger-cosmos-go v0.13.3 github.com/davecgh/go-spew v1.1.1 @@ -26,27 +26,27 @@ require ( github.com/peterbourgon/ff/v3 v3.4.0 github.com/pmezard/go-difflib v1.0.0 github.com/rogpeppe/go-internal v1.12.0 - github.com/rs/cors v1.11.1 - github.com/rs/xid v1.6.0 + github.com/rs/cors v1.11.0 + github.com/rs/xid v1.5.0 github.com/stretchr/testify v1.9.0 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - go.etcd.io/bbolt v1.3.11 - go.opentelemetry.io/otel v1.29.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 - go.opentelemetry.io/otel/metric v1.29.0 - go.opentelemetry.io/otel/sdk v1.29.0 - go.opentelemetry.io/otel/sdk/metric v1.29.0 + go.etcd.io/bbolt v1.3.10 + go.opentelemetry.io/otel v1.28.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 + go.opentelemetry.io/otel/metric v1.28.0 + go.opentelemetry.io/otel/sdk v1.28.0 + go.opentelemetry.io/otel/sdk/metric v1.28.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 go.uber.org/zap/exp v0.2.0 - golang.org/x/crypto v0.26.0 + golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 - golang.org/x/mod v0.20.0 - golang.org/x/net v0.28.0 - golang.org/x/sync v0.8.0 - golang.org/x/term v0.23.0 - golang.org/x/tools v0.24.0 + golang.org/x/mod v0.19.0 + golang.org/x/net v0.27.0 + golang.org/x/sync v0.7.0 + golang.org/x/term v0.22.0 + golang.org/x/tools v0.23.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 ) @@ -60,18 +60,18 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/nxadm/tail v1.4.11 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/rivo/uniseg v0.4.3 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/grpc v1.65.0 // indirect ) diff --git a/go.sum b/go.sum index 9495dd5b451..5cb6be26da2 100644 --- a/go.sum +++ b/go.sum @@ -1,20 +1,18 @@ -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7Nzl7WHaOTlTr5hIrR4n1NM4v9n4Kw= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= -github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= -github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= -github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= -github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= @@ -95,8 +93,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotuna/gotuna v0.6.0 h1:N1lQKXEi/lwRp8u3sccTYLhzOffA4QasExz/1M5Riws= github.com/gotuna/gotuna v0.6.0/go.mod h1:F/ecRt29ChB6Ycy1AFIBpBiMNK0j7Heq+gFbLWquhjc= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -141,17 +139,12 @@ github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= -github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= -github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -161,22 +154,22 @@ github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= -go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= -go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 h1:k6fQVDQexDE+3jG2SfCQjnHS7OamcP73YMoxEVq5B6k= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0/go.mod h1:t4BrYLHU450Zo9fnydWlIuswB1bm7rM8havDpWOJeDo= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 h1:xvhQxJ/C9+RTnAj5DpTg7LSM1vbbMTiXt7e9hsfqHNw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0/go.mod h1:Fcvs2Bz1jkDM+Wf5/ozBGmi3tQ/c9zPKLnsipnfhGAo= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/sdk/metric v1.29.0 h1:K2CfmJohnRgvZ9UAj2/FhIf/okdWcNdBwe1m8xFXiSY= -go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLmmtjRke7LPDQ3lvpFz+kNEH43faFhzW7v8BFIEydg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0/go.mod h1:TC1pyCt6G9Sjb4bQpShH+P5R53pO6ZuGnHuuln9xMeE= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08= +go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -191,14 +184,14 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -208,14 +201,14 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -232,36 +225,36 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/misc/deployments/staging.gno.land/docker-compose.yml b/misc/deployments/staging.gno.land/docker-compose.yml index 7d264a34dbd..3479067372d 100644 --- a/misc/deployments/staging.gno.land/docker-compose.yml +++ b/misc/deployments/staging.gno.land/docker-compose.yml @@ -1,126 +1,130 @@ -name: "staging-gno-land" -services: - traefik: - image: "traefik:v2.11" - restart: unless-stopped - command: - - "--api.insecure=true" - - "--providers.docker=true" - - "--providers.docker.exposedbydefault=false" - - "--entrypoints.web.address=:80" - - "--entrypoints.rpc.address=:26657" - - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - - "--entrypoints.web.http.redirections.entrypoint.permanent=true" - - "--entryPoints.web.forwardedHeaders.insecure" - - "--entrypoints.traefik.address=:8080" - - "--entrypoints.websecure.address=:443" - - - "--certificatesresolvers.le.acme.tlschallenge=true" - - "--certificatesresolvers.le.acme.email=dev@gno.land" - - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json" - ports: - - "80:80" - - "443:443" - - "26657:26657" - volumes: - - "/var/run/docker.sock:/var/run/docker.sock:ro" - - ./letsencrypt:/letsencrypt +version: "2" +services: gnoland: - image: ghcr.io/gnolang/gno/gnoland:master - restart: unless-stopped - entrypoint: /entrypoint.sh - working_dir: /gnoroot + container_name: gnoland + build: ../../.. environment: - CHAIN_ID: staging - MONIKER: gno-staging + - VIRTUAL_HOST=rpc.staging.gno.land + - VIRTUAL_PORT=26657 + - LETSENCRYPT_HOST=rpc.staging.gno.land + - LOG_LEVEL=4 + working_dir: /opt/gno/src/gno.land + command: + - gnoland + - start + - --skip-failing-genesis-txs + - --chainid=staging + - --genesis-remote=staging.gno.land:26657 volumes: - - ./gnoland.entrypoint.sh:/entrypoint.sh - #ports: - # - 26656:26656 - labels: - com.centurylinklabs.watchtower.enable: "true" - traefik.enable: "true" - traefik.http.routers.gnoland.entrypoints: "web,websecure" - traefik.http.routers.gnoland.rule: "Host(`rpc.staging.gno.land`)" - traefik.http.routers.gnoland.service: gnoland-rpc - traefik.http.routers.gnoland.tls: "true" - traefik.http.routers.gnoland.tls.certresolver: "le" - traefik.http.routers.gnoland-rpc.entrypoints: "rpc" - traefik.http.routers.gnoland-rpc.rule: "PathPrefix(`/`)" - traefik.http.routers.gnoland-rpc.service: gnoland-rpc - traefik.http.services.gnoland-rpc.loadbalancer.server.port: 26657 + - "./data/gnoland:/opt/gno/src/gno.land/gnoland-data" + ports: + - 26656:26656 + - 26657:26657 + restart: on-failure + logging: + driver: "json-file" + options: + max-file: "10" + max-size: "100m" gnoweb: - image: ghcr.io/gnolang/gno/gnoweb:master - restart: unless-stopped - env_file: ".env" - entrypoint: + container_name: gnoweb + build: ../../.. + command: - gnoweb - - --bind=0.0.0.0:8888 - - --remote=http://traefik:26657 - - --faucet-url=https://faucet-api.staging.gno.land - - --captcha-site=$CAPTCHA_SITE_KEY - - --with-analytics + - --bind=0.0.0.0:80 + - --remote=gnoland:26657 + - --captcha-site=$RECAPTCHA_SITE_KEY + - --faucet-url=https://faucet-staging.gno.land/ - --help-chainid=staging - - --help-remote=https://rpc.staging.gno.land:443 - labels: - com.centurylinklabs.watchtower.enable: "true" - traefik.enable: "true" - traefik.http.routers.gnoweb.entrypoints: "web,websecure" - traefik.http.routers.gnoweb.rule: "Host(`staging.gno.land`)" - traefik.http.routers.gnoweb.tls: "true" - traefik.http.routers.gnoweb.tls.certresolver: "le" + - --help-remote=staging.gno.land:26657 + - --with-analytics + volumes: + - "./overlay:/overlay:ro" + links: + - gnoland + environment: + - VIRTUAL_HOST=staging.gno.land + - LETSENCRYPT_HOST=staging.gno.land + # from .env + - RECAPTCHA_SITE_KEY + restart: on-failure + logging: + driver: "json-file" + options: + max-file: "10" + max-size: "100m" gnofaucet: - image: ghcr.io/gnolang/gno/gnofaucet-slim - restart: unless-stopped - command: - - "serve" - - "--listen-address=0.0.0.0:5050" - - "--chain-id=staging" - - "--is-behind-proxy=true" - - "--mnemonic=${FAUCET_MNEMONIC}" - - "--num-accounts=1" - - "--remote=http://traefik:26657" - - "--captcha-secret=${CAPTCHA_SECRET_KEY}" - env_file: ".env" - # environment: - # from .env - # - RECAPTCHA_SECRET_KEY - labels: - com.centurylinklabs.watchtower.enable: "true" - traefik.enable: "true" - traefik.http.routers.gnofaucet-api.entrypoints: "websecure" - traefik.http.routers.gnofaucet-api.rule: "Host(`faucet-api.staging.gno.land`) || Host(`faucet-api.staging.gnoteam.com`)" - traefik.http.routers.gnofaucet-api.tls: "true" - traefik.http.routers.gnofaucet-api.tls.certresolver: "le" - traefik.http.middlewares.gnofaucet-ratelimit.ratelimit.average: "6" - traefik.http.middlewares.gnofaucet-ratelimit.ratelimit.period: "1m" + container_name: gnofaucet + build: ../../.. + command: sh -xc " + date && + mkdir -p /.gno && + expect -c \"set timeout -1; spawn gnokey add --home /.gno/ --recover faucet; expect \\\"Enter a passphrase\\\"; send \\\"$GNOKEY_PASS\\r\\\"; expect \\\"Repeat the passphrase\\\"; send \\\"$GNOKEY_PASS\\r\\\"; expect \\\"Enter your bip39 mnemonic\\\"; send \\\"$FAUCET_WORDS\\r\\\"; expect eof\" && + while true; do + expect -c \"set timeout -1; spawn gnofaucet serve --send 50000000ugnot --captcha-secret \\\"$RECAPTCHA_SECRET_KEY\\\" --remote gnoland:26657 --chain-id staging --home /.gno/ faucet; expect \\\"Enter password\\\"; send \\\"$GNOKEY_PASS\\r\\\"; expect eof\"; + sleep 5; + done + " + links: + - gnoland + environment: + - VIRTUAL_HOST=faucet-staging.gno.land + - VIRTUAL_PORT=5050 + - LETSENCRYPT_HOST=faucet-staging.gno.land + # from .env + - RECAPTCHA_SECRET_KEY + - FAUCET_WORDS + - GNOKEY_PASS + ports: + - 5050 + restart: on-failure + logging: + driver: "json-file" + options: + max-file: "10" + max-size: "100m" - watchtower: - image: containrrr/watchtower - restart: unless-stopped - command: --interval 30 --http-api-metrics --label-enable + nginx-proxy: + image: nginxproxy/nginx-proxy + container_name: nginx-proxy + ports: + - "80:80" + - "443:443" volumes: - - /var/run/docker.sock:/var/run/docker.sock - environment: - WATCHTOWER_HTTP_API_TOKEN: "mytoken" + - conf:/etc/nginx/conf.d + - vhost:/etc/nginx/vhost.d + - html:/usr/share/nginx/html + - certs:/etc/nginx/certs:ro + - /var/run/docker.sock:/tmp/docker.sock:ro + logging: + driver: "json-file" + options: + max-file: "10" + max-size: "100m" - restarter: - image: docker:cli - restart: unless-stopped - entrypoint: [ "/bin/sh", "-c" ] - working_dir: "/app" + acme-companion: + image: nginxproxy/acme-companion + container_name: nginx-proxy-acme + environment: + - DEFAULT_EMAIL=noreply@gno.land + volumes_from: + - nginx-proxy volumes: - - ".:/app" - - "/var/run/docker.sock:/var/run/docker.sock" - command: - - | - while true; do - if [ "$$(date +'%H:%M')" = '22:00' ]; then - docker compose restart gnoland - fi - sleep 60 - done + - certs:/etc/nginx/certs:rw + - acme:/etc/acme.sh + - /var/run/docker.sock:/var/run/docker.sock:ro + logging: + driver: "json-file" + options: + max-file: "10" + max-size: "100m" + +volumes: + conf: + vhost: + html: + certs: + acme: diff --git a/misc/deployments/staging.gno.land/gnoland.entrypoint.sh b/misc/deployments/staging.gno.land/gnoland.entrypoint.sh deleted file mode 100755 index 90957e92da8..00000000000 --- a/misc/deployments/staging.gno.land/gnoland.entrypoint.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env sh - -set -ex - -MONIKER=${MONIKER:-"gnode"} -P2P_LADDR=${P2P_LADDR:-"tcp://0.0.0.0:26656"} -RPC_LADDR=${RPC_LADDR:-"tcp://0.0.0.0:26657"} - -CHAIN_ID=${CHAIN_ID:-"staging"} - -rm -rfv ./gnoland-data genesis.json - -gnoland config init -gnoland secrets init - -gnoland config set moniker "${MONIKER}" -gnoland config set rpc.laddr "${RPC_LADDR}" -gnoland config set p2p.laddr "${P2P_LADDR}" - -exec gnoland start \ - --skip-failing-genesis-txs \ - --chainid="${CHAIN_ID}" \ - --lazy diff --git a/misc/docker-integration/integration_test.go b/misc/docker-integration/integration_test.go index 973cb386e9b..1142709cc16 100644 --- a/misc/docker-integration/integration_test.go +++ b/misc/docker-integration/integration_test.go @@ -13,7 +13,6 @@ import ( "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" @@ -56,10 +55,7 @@ func runSuite(t *testing.T, tempdir string) { 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)) + minCoins := std.MustParseCoins("9990000000000ugnot") // This value is chosen arbitrarily and may not be optimal. Feel free to update it to a more suitable amount require.True(t, acc.Coins.IsAllGTE(minCoins), "test1 account coins expected at least %s, got %s", minCoins, acc.Coins) diff --git a/tm2/pkg/bft/fail/fail.go b/tm2/pkg/bft/fail/fail.go index c56f43d7d89..607084f484f 100644 --- a/tm2/pkg/bft/fail/fail.go +++ b/tm2/pkg/bft/fail/fail.go @@ -4,33 +4,31 @@ import ( "fmt" "os" "strconv" - "sync" ) -func setFromEnv() { +func envSet() int { callIndexToFailS := os.Getenv("FAIL_TEST_INDEX") if callIndexToFailS == "" { - callIndexToFail = -1 + return -1 } else { var err error - callIndexToFail, err = strconv.Atoi(callIndexToFailS) + callIndexToFail, err := strconv.Atoi(callIndexToFailS) if err != nil { - callIndexToFail = -1 + return -1 } + return callIndexToFail } } -var ( - callIndex int // indexes Fail calls - callIndexToFail int // index of call which should fail - callIndexToFailOnce sync.Once // sync.Once to set the value of the above -) +// Fail when FAIL_TEST_INDEX == callIndex +var callIndex int // indexes Fail calls -// Fail exits the program when after being called the same number of times as -// that passed as the FAIL_TEST_INDEX environment variable. func Fail() { - callIndexToFailOnce.Do(setFromEnv) + callIndexToFail := envSet() + if callIndexToFail < 0 { + return + } if callIndex == callIndexToFail { Exit() diff --git a/tm2/pkg/crypto/bech32_test.go b/tm2/pkg/crypto/bech32_test.go index d0d7ee92898..f5bc3e9ed7c 100644 --- a/tm2/pkg/crypto/bech32_test.go +++ b/tm2/pkg/crypto/bech32_test.go @@ -1,7 +1,6 @@ package crypto_test import ( - "encoding/json" "math/rand" "testing" @@ -60,7 +59,6 @@ func TestRandBech32AddrConsistency(t *testing.T) { addr := crypto.AddressFromBytes(pub.Address().Bytes()) testMarshal(t, addr, amino.Marshal, amino.Unmarshal) testMarshal(t, addr, amino.MarshalJSON, amino.UnmarshalJSON) - testMarshal(t, addr, json.Marshal, json.Unmarshal) str := addr.String() res, err := crypto.AddressFromBech32(str) diff --git a/tm2/pkg/crypto/crypto.go b/tm2/pkg/crypto/crypto.go index 7757b75354e..e7089ca579b 100644 --- a/tm2/pkg/crypto/crypto.go +++ b/tm2/pkg/crypto/crypto.go @@ -2,7 +2,6 @@ package crypto import ( "bytes" - "encoding/json" "fmt" "github.com/gnolang/gno/tm2/pkg/bech32" @@ -54,25 +53,11 @@ func AddressFromBytes(bz []byte) (ret Address) { return } -func (addr Address) MarshalJSON() ([]byte, error) { - b := AddressToBech32(addr) - return []byte(`"` + b + `"`), nil -} - -func (addr *Address) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - return addr.UnmarshalAmino(s) -} - func (addr Address) MarshalAmino() (string, error) { return AddressToBech32(addr), nil } func (addr *Address) UnmarshalAmino(b32str string) (err error) { - // NOTE: also used to unmarshal normal JSON, through UnmarshalJSON. if b32str == "" { return nil // leave addr as zero. } diff --git a/tm2/pkg/sdk/abci.go b/tm2/pkg/sdk/abci.go index 0b86518f0b9..a9cd14e9ed3 100644 --- a/tm2/pkg/sdk/abci.go +++ b/tm2/pkg/sdk/abci.go @@ -16,12 +16,3 @@ type BeginBlocker func(ctx Context, req abci.RequestBeginBlock) abci.ResponseBeg // Note: applications which set create_empty_blocks=false will not have regular block timing and should use // e.g. BFT timestamps rather than block height for any periodic EndBlock logic type EndBlocker func(ctx Context, req abci.RequestEndBlock) abci.ResponseEndBlock - -// BeginTxHook is a BaseApp-specific hook, called to modify the context with any -// additional application-specific information, before running the messages in a -// transaction. -type BeginTxHook func(ctx Context) Context - -// EndTxHook is a BaseApp-specific hook, called after all the messages in a -// transaction have terminated. -type EndTxHook func(ctx Context, result Result) diff --git a/tm2/pkg/sdk/baseapp.go b/tm2/pkg/sdk/baseapp.go index 867a38d680a..0fa26b817e1 100644 --- a/tm2/pkg/sdk/baseapp.go +++ b/tm2/pkg/sdk/baseapp.go @@ -42,9 +42,6 @@ type BaseApp struct { beginBlocker BeginBlocker // logic to run before any txs endBlocker EndBlocker // logic to run after all txs, and to determine valset changes - beginTxHook BeginTxHook // BaseApp-specific hook run before running transaction messages. - endTxHook EndTxHook // BaseApp-specific hook run after running transaction messages. - // -------------------- // Volatile state // checkState is set on initialization and reset on Commit. @@ -823,11 +820,6 @@ func (app *BaseApp) runTx(mode RunTxMode, txBytes []byte, tx Tx) (result Result) // Create a new context based off of the existing context with a cache wrapped // multi-store in case message processing fails. runMsgCtx, msCache := app.cacheTxContext(ctx) - - if app.beginTxHook != nil { - runMsgCtx = app.beginTxHook(runMsgCtx) - } - result = app.runMsgs(runMsgCtx, msgs, mode) result.GasWanted = gasWanted @@ -836,10 +828,6 @@ func (app *BaseApp) runTx(mode RunTxMode, txBytes []byte, tx Tx) (result Result) return result } - if app.endTxHook != nil { - app.endTxHook(runMsgCtx, result) - } - // only update state if all messages pass if result.IsOK() { msCache.MultiWrite() diff --git a/tm2/pkg/sdk/baseapp_test.go b/tm2/pkg/sdk/baseapp_test.go index c8884533b30..1680b99a5c6 100644 --- a/tm2/pkg/sdk/baseapp_test.go +++ b/tm2/pkg/sdk/baseapp_test.go @@ -19,9 +19,9 @@ import ( "github.com/gnolang/gno/tm2/pkg/db/memdb" "github.com/gnolang/gno/tm2/pkg/sdk/testutils" "github.com/gnolang/gno/tm2/pkg/std" - "github.com/gnolang/gno/tm2/pkg/store" "github.com/gnolang/gno/tm2/pkg/store/dbadapter" "github.com/gnolang/gno/tm2/pkg/store/iavl" + store "github.com/gnolang/gno/tm2/pkg/store/types" ) var ( @@ -199,47 +199,6 @@ func TestLoadVersionInvalid(t *testing.T) { require.Error(t, err) } -func TestOptionSetters(t *testing.T) { - t.Parallel() - - tt := []struct { - // Calling BaseApp.[method]([value]) should change BaseApp.[fieldName] to [value]. - method string - fieldName string - value any - }{ - {"SetName", "name", "hello"}, - {"SetAppVersion", "appVersion", "12345"}, - {"SetDB", "db", memdb.NewMemDB()}, - {"SetCMS", "cms", store.NewCommitMultiStore(memdb.NewMemDB())}, - {"SetInitChainer", "initChainer", func(Context, abci.RequestInitChain) abci.ResponseInitChain { panic("not implemented") }}, - {"SetBeginBlocker", "beginBlocker", func(Context, abci.RequestBeginBlock) abci.ResponseBeginBlock { panic("not implemented") }}, - {"SetEndBlocker", "endBlocker", func(Context, abci.RequestEndBlock) abci.ResponseEndBlock { panic("not implemented") }}, - {"SetAnteHandler", "anteHandler", func(Context, Tx, bool) (Context, Result, bool) { panic("not implemented") }}, - {"SetBeginTxHook", "beginTxHook", func(Context) Context { panic("not implemented") }}, - {"SetEndTxHook", "endTxHook", func(Context, Result) { panic("not implemented") }}, - } - - for _, tc := range tt { - t.Run(tc.method, func(t *testing.T) { - t.Parallel() - - var ba BaseApp - rv := reflect.ValueOf(&ba) - - rv.MethodByName(tc.method).Call([]reflect.Value{reflect.ValueOf(tc.value)}) - changed := rv.Elem().FieldByName(tc.fieldName) - - if reflect.TypeOf(tc.value).Kind() == reflect.Func { - assert.Equal(t, reflect.ValueOf(tc.value).Pointer(), changed.Pointer(), "%s(%#v): function value should have changed", tc.method, tc.value) - } else { - assert.True(t, reflect.ValueOf(tc.value).Equal(changed), "%s(%#v): wanted %v got %v", tc.method, tc.value, tc.value, changed) - } - assert.False(t, changed.IsZero(), "%s(%#v): field's new value should not be zero value", tc.method, tc.value) - }) - } -} - func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID store.CommitID) { t.Helper() @@ -313,12 +272,6 @@ func TestBaseAppOptionSeal(t *testing.T) { require.Panics(t, func() { app.SetAnteHandler(nil) }) - require.Panics(t, func() { - app.SetBeginTxHook(nil) - }) - require.Panics(t, func() { - app.SetEndTxHook(nil) - }) } func TestSetMinGasPrices(t *testing.T) { @@ -974,6 +927,7 @@ func TestMaxBlockGasLimits(t *testing.T) { } for i, tc := range testCases { + fmt.Printf("debug i: %v\n", i) tx := tc.tx // reset the block gas diff --git a/tm2/pkg/sdk/context.go b/tm2/pkg/sdk/context.go index 63c5a50f8eb..0e1021e0174 100644 --- a/tm2/pkg/sdk/context.go +++ b/tm2/pkg/sdk/context.go @@ -147,21 +147,31 @@ func (c Context) WithEventLogger(em *EventLogger) Context { return c } -// WithValue is shorthand for: +// WithValue is deprecated, provided for backwards compatibility +// Please use // -// c.WithContext(context.WithValue(c.Context(), key, value)) +// ctx = ctx.WithContext(context.WithValue(ctx.Context(), key, false)) // -// It adds a value to the [context.Context]. +// instead of +// +// ctx = ctx.WithValue(key, false) +// +// NOTE: why? func (c Context) WithValue(key, value interface{}) Context { c.ctx = context.WithValue(c.ctx, key, value) return c } -// Value is shorthand for: +// Value is deprecated, provided for backwards compatibility +// Please use +// +// ctx.Context().Value(key) +// +// instead of // -// c.Context().Value(key) +// ctx.Value(key) // -// It retrieves a value from the [context.Context]. +// NOTE: why? func (c Context) Value(key interface{}) interface{} { return c.ctx.Value(key) } diff --git a/tm2/pkg/sdk/options.go b/tm2/pkg/sdk/options.go index b9840a7510b..f174b5501a2 100644 --- a/tm2/pkg/sdk/options.go +++ b/tm2/pkg/sdk/options.go @@ -85,17 +85,3 @@ func (app *BaseApp) SetAnteHandler(ah AnteHandler) { } app.anteHandler = ah } - -func (app *BaseApp) SetBeginTxHook(beginTx BeginTxHook) { - if app.sealed { - panic("SetBeginTxHook() on sealed BaseApp") - } - app.beginTxHook = beginTx -} - -func (app *BaseApp) SetEndTxHook(endTx EndTxHook) { - if app.sealed { - panic("SetEndTxHook() on sealed BaseApp") - } - app.endTxHook = endTx -}